kitty @ get-text add an option to also get the current cursor position and state as ANSI escape codes

Fixes #3625
This commit is contained in:
Kovid Goyal 2021-05-15 09:27:28 +05:30
parent 3bf9130b0a
commit fcd206891f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 55 additions and 15 deletions

View File

@ -53,6 +53,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- Fix deleting windows that are not the last window via remote control leaving
no window focused (:iss:`3619`)
- ``kitty @ get-text`` add an option to also get the current cursor position
and state as ANSI escape codes (:iss:`3625`)
0.20.3 [2021-05-06]
----------------------

View File

@ -278,6 +278,7 @@ PyInit_fast_data_types(void) {
PyModule_AddIntMacro(m, CURSOR_BLOCK);
PyModule_AddIntMacro(m, CURSOR_BEAM);
PyModule_AddIntMacro(m, CURSOR_UNDERLINE);
PyModule_AddIntMacro(m, NO_CURSOR_SHAPE);
PyModule_AddIntMacro(m, DECAWM);
PyModule_AddIntMacro(m, DECCOLM);
PyModule_AddIntMacro(m, DECOM);

View File

@ -235,6 +235,7 @@ GLFW_RELEASE: int
GLFW_REPEAT: int
CURSOR_BEAM: int
CURSOR_BLOCK: int
NO_CURSOR_SHAPE: int
CURSOR_UNDERLINE: int
DECAWM: int
BGIMAGE_PROGRAM: int
@ -923,6 +924,8 @@ class Cursor:
fg: int
bold: bool
italic: bool
blink: bool
shape: int
class Screen:
@ -934,6 +937,7 @@ class Screen:
historybuf: HistoryBuf
linebuf: LineBuf
in_bracketed_paste_mode: bool
cursor_visible: bool
scrolled_by: int
cursor: Cursor
disable_ligatures: int

View File

@ -20,6 +20,7 @@ class GetText(RemoteCommand):
match: The tab to focus
extent: One of :code:`screen`, :code:`all`, or :code:`selection`
ansi: Boolean, if True send ANSI formatting codes
cursor: Boolean, if True send cursor position/style as ANSI codes
self: Boolean, if True use window command was run in
'''
@ -39,6 +40,11 @@ include the formatting escape codes for colors/bold/italic/etc. Note that when
getting the current selection, the result is always plain text.
--add-cursor
type=bool-set
Add ANSI escape codes specifying the cursor position and style to the end of the text.
--self
type=bool-set
If specified get text from the window this command is run in, rather than the active window.
@ -46,14 +52,18 @@ If specified get text from the window this command is run in, rather than the ac
argspec = ''
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self}
return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self, 'cursor': opts.add_cursor}
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
window = self.windows_for_match_payload(boss, window, payload_get)[0]
if payload_get('extent') == 'selection':
ans = window.text_for_selection()
else:
ans = window.as_text(as_ansi=bool(payload_get('ansi')), add_history=payload_get('extent') == 'all')
ans = window.as_text(
as_ansi=bool(payload_get('ansi')),
add_history=payload_get('extent') == 'all',
add_cursor=bool(payload_get('cursor')),
)
return ans

View File

@ -22,15 +22,16 @@ from .config import build_ansi_color_table
from .constants import appname, is_macos, wakeup
from .fast_data_types import (
BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM,
CELL_PROGRAM, CELL_SPECIAL_PROGRAM, DCS, DECORATION, DIM, GLFW_MOD_CONTROL,
CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CURSOR_BEAM, CURSOR_BLOCK,
CURSOR_UNDERLINE, DCS, DECORATION, DIM, GLFW_MOD_CONTROL,
GRAPHICS_ALPHA_MASK_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_PROGRAM,
MARK, MARK_MASK, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE,
STRIKETHROUGH, TINT_PROGRAM, KeyEvent, Screen, add_timer, add_window,
cell_size_for_window, click_mouse_url, compile_program, encode_key_for_tty,
get_boss, get_clipboard_string, init_cell_program, mouse_selection,
pt_to_px, set_clipboard_string, set_titlebar_color, set_window_padding,
set_window_render_data, update_window_title, update_window_visibility,
viewport_for_window
MARK, MARK_MASK, NO_CURSOR_SHAPE, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE,
SCROLL_PAGE, STRIKETHROUGH, TINT_PROGRAM, KeyEvent, Screen, add_timer,
add_window, cell_size_for_window, click_mouse_url, compile_program,
encode_key_for_tty, get_boss, get_clipboard_string, init_cell_program,
mouse_selection, pt_to_px, set_clipboard_string, set_titlebar_color,
set_window_padding, set_window_render_data, update_window_title,
update_window_visibility, viewport_for_window
)
from .keys import keyboard_mode_name
from .notify import NotificationCommand, handle_notification_cmd
@ -152,7 +153,8 @@ def as_text(
as_ansi: bool = False,
add_history: bool = False,
add_wrap_markers: bool = False,
alternate_screen: bool = False
alternate_screen: bool = False,
add_cursor: bool = False
) -> str:
lines: List[str] = []
add_history = add_history and not (screen.is_using_alternate_linebuf() ^ alternate_screen)
@ -161,6 +163,19 @@ def as_text(
else:
f = screen.as_text_non_visual if add_history else screen.as_text
f(lines.append, as_ansi, add_wrap_markers)
ctext = ''
if add_cursor:
ctext += '\x1b[?25' + ('h' if screen.cursor_visible else 'l')
ctext += f'\x1b[{screen.cursor.y + 1};{screen.cursor.x + 1}H'
shape = screen.cursor.shape
if shape == NO_CURSOR_SHAPE:
ctext += '\x1b[?12' + ('h' if screen.cursor.blink else 'l')
else:
code = {CURSOR_BLOCK: 1, CURSOR_UNDERLINE: 3, CURSOR_BEAM: 5}[shape]
if not screen.cursor.blink:
code += 1
ctext += f'\x1b[{code} q'
if add_history:
h: List[str] = []
pht = screen.historybuf.pagerhist_as_text()
@ -175,8 +190,14 @@ def as_text(
h[-1] += '\n'
if as_ansi:
h[-1] += '\x1b[m'
return ''.join(chain(h, lines))
return ''.join(lines)
ans = ''.join(chain(h, lines))
if ctext:
ans += ctext
return ans
ans = ''.join(lines)
if ctext:
ans += ctext
return ans
class LoadShaderPrograms:
@ -848,9 +869,10 @@ class Window:
as_ansi: bool = False,
add_history: bool = False,
add_wrap_markers: bool = False,
alternate_screen: bool = False
alternate_screen: bool = False,
add_cursor: bool = False
) -> str:
return as_text(self.screen, as_ansi, add_history, add_wrap_markers, alternate_screen)
return as_text(self.screen, as_ansi, add_history, add_wrap_markers, alternate_screen, add_cursor)
@property
def cwd_of_child(self) -> Optional[str]: