main.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #!/usr/bin/env python
  2. # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
  3. import sys
  4. from typing import Any, Dict, List, Optional
  5. from kitty.cli import parse_args
  6. from kitty.cli_stub import RCOptions, ResizeCLIOptions
  7. from kitty.constants import version
  8. from kitty.key_encoding import CTRL, EventType, KeyEvent
  9. from kitty.rc.base import command_for_name, parse_subcommand_cli
  10. from kitty.remote_control import encode_send, parse_rc_args
  11. from kitty.utils import ScreenSize
  12. from ..tui.handler import Handler
  13. from ..tui.loop import Loop
  14. from ..tui.operations import styled
  15. global_opts = RCOptions()
  16. class Resize(Handler):
  17. print_on_fail: Optional[str] = None
  18. def __init__(self, opts: ResizeCLIOptions):
  19. self.opts = opts
  20. def initialize(self) -> None:
  21. global global_opts
  22. global_opts = parse_rc_args(['kitty', '@resize-window'])[0]
  23. self.original_size = self.screen_size
  24. self.cmd.set_cursor_visible(False)
  25. self.cmd.set_line_wrapping(False)
  26. self.draw_screen()
  27. def do_window_resize(self, is_decrease: bool = False, is_horizontal: bool = True, reset: bool = False, multiplier: int = 1) -> None:
  28. resize_window = command_for_name('resize_window')
  29. increment = self.opts.horizontal_increment if is_horizontal else self.opts.vertical_increment
  30. increment *= multiplier
  31. if is_decrease:
  32. increment *= -1
  33. axis = 'reset' if reset else ('horizontal' if is_horizontal else 'vertical')
  34. cmdline = [resize_window.name, '--self', f'--increment={increment}', '--axis=' + axis]
  35. opts, items = parse_subcommand_cli(resize_window, cmdline)
  36. payload = resize_window.message_to_kitty(global_opts, opts, items)
  37. send = {'cmd': resize_window.name, 'version': version, 'payload': payload, 'no_response': False}
  38. self.write(encode_send(send))
  39. def on_kitty_cmd_response(self, response: Dict[str, Any]) -> None:
  40. if not response.get('ok'):
  41. err = response['error']
  42. if response.get('tb'):
  43. err += '\n' + response['tb']
  44. self.print_on_fail = err
  45. self.quit_loop(1)
  46. return
  47. res = response.get('data')
  48. if res:
  49. self.cmd.bell()
  50. def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
  51. text = text.upper()
  52. if text in 'WNTSR':
  53. self.do_window_resize(is_decrease=text in 'NS', is_horizontal=text in 'WN', reset=text == 'R')
  54. elif text == 'Q':
  55. self.quit_loop(0)
  56. def on_key(self, key_event: KeyEvent) -> None:
  57. if key_event.type is EventType.RELEASE:
  58. return
  59. if key_event.matches('esc'):
  60. self.quit_loop(0)
  61. return
  62. if key_event.key in ('w', 'n', 't', 's') and key_event.mods_without_locks == CTRL:
  63. self.do_window_resize(is_decrease=key_event.key in 'ns', is_horizontal=key_event.key in 'wn', multiplier=2)
  64. def on_resize(self, new_size: ScreenSize) -> None:
  65. self.draw_screen()
  66. def draw_screen(self) -> None:
  67. self.cmd.clear_screen()
  68. print = self.print
  69. print(styled('Resize this window', bold=True, fg='gray', fg_intense=True))
  70. print()
  71. print('Press one of the following keys:')
  72. print(' {}ider'.format(styled('W', fg='green')))
  73. print(' {}arrower'.format(styled('N', fg='green')))
  74. print(' {}aller'.format(styled('T', fg='green')))
  75. print(' {}horter'.format(styled('S', fg='green')))
  76. print(' {}eset'.format(styled('R', fg='red')))
  77. print()
  78. print('Press {} to quit resize mode'.format(styled('Esc', italic=True)))
  79. print('Hold down {} to double step size'.format(styled('Ctrl', italic=True)))
  80. print()
  81. print(styled('Sizes', bold=True, fg='white', fg_intense=True))
  82. print(f'Original: {self.original_size.rows} rows {self.original_size.cols} cols')
  83. print('Current: {} rows {} cols'.format(
  84. styled(str(self.screen_size.rows), fg='magenta'), styled(str(self.screen_size.cols), fg='magenta')))
  85. OPTIONS = r'''
  86. --horizontal-increment
  87. default=2
  88. type=int
  89. The base horizontal increment.
  90. --vertical-increment
  91. default=2
  92. type=int
  93. The base vertical increment.
  94. '''.format
  95. def main(args: List[str]) -> None:
  96. msg = 'Resize the current window'
  97. try:
  98. cli_opts, items = parse_args(args[1:], OPTIONS, '', msg, 'resize_window', result_class=ResizeCLIOptions)
  99. except SystemExit as e:
  100. if e.code != 0:
  101. print(e.args[0], file=sys.stderr)
  102. input('Press Enter to quit')
  103. return
  104. loop = Loop()
  105. handler = Resize(cli_opts)
  106. loop.loop(handler)
  107. if handler.print_on_fail:
  108. print(handler.print_on_fail, file=sys.stderr)
  109. input('Press Enter to quit')
  110. raise SystemExit(loop.return_code)