Allow adding line wrap markers when piping screen contents
Also make some data such as scroll position, cursor position and screen geometry available via an env var when piping. See #719
This commit is contained in:
parent
ae8ca5272b
commit
a7a7216b30
@ -13,7 +13,7 @@ Changelog
|
||||
- Modify the kittens sub-system to allow creating custom kittens without any
|
||||
user interface. This is useful for creating more complex actions that can
|
||||
be bound to key presses in :file:`kitty.conf`. See
|
||||
`https://sw.kovidgoyal.net/kitty/kittens/custom.html`_. (:iss:`870`)
|
||||
doc:`kittens/custom`. (:iss:`870`)
|
||||
|
||||
- Add a new ``nth_window`` action that can be used to go to the nth window and
|
||||
also previously active windows, using negative numbers. Similarly,
|
||||
@ -443,7 +443,7 @@ Changelog
|
||||
|
||||
- Add a config option (:opt:`editor`) to set the EDITOR kitty uses (:iss:`580`)
|
||||
|
||||
- Add a config option (:opt:`x11_hide_window_decorations`) to hide window
|
||||
- Add a config option (``x11_hide_window_decorations``) to hide window
|
||||
decorations under X11/Wayland (:iss:`607`)
|
||||
|
||||
- Add an option to @set-window-title to make the title change non-permanent
|
||||
|
||||
88
docs/pipe.rst
Normal file
88
docs/pipe.rst
Normal file
@ -0,0 +1,88 @@
|
||||
Working with the screen and history buffer contents
|
||||
======================================================
|
||||
|
||||
|
||||
You can pipe the contents of the current screen and history buffer as
|
||||
:file:`STDIN` to an arbitrary program using the ``pipe`` function. The program
|
||||
can be displayed in a kitty window or overlay.
|
||||
|
||||
For example, the following in :file:`kitty.conf` will open the scrollback
|
||||
buffer in less in an overlay window, when you press :kbd:`F1`::
|
||||
|
||||
map f1 pipe @ansi overlay less +G -R
|
||||
|
||||
The syntax of the ``pipe`` function is::
|
||||
|
||||
pipe <input placeholder> <destination window type> <command line to run>
|
||||
|
||||
|
||||
The piping environment
|
||||
--------------------------
|
||||
|
||||
The program to which the data is piped has a special environment variable
|
||||
declared, ``KITTY_PIPE_DATA`` whose contents are::
|
||||
|
||||
KITTY_PIPE_DATA={scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns}
|
||||
|
||||
where ``scrolled_by`` is the number of lines kitty is currently scrolled by,
|
||||
``cursor_(x|y)`` is the position of the cursor on the screen with ``(1,1)``
|
||||
being the top left corner and ``{lines},{columns}`` being the number of rows
|
||||
and columns of the screen.
|
||||
|
||||
You can choose where to run the pipe program:
|
||||
|
||||
``overlay``
|
||||
An overlay window over the current kitty window
|
||||
|
||||
``window``
|
||||
A new kitty window
|
||||
|
||||
``os_window``
|
||||
A new top-level window
|
||||
|
||||
``tab``
|
||||
A new window in a new tab
|
||||
|
||||
``none``
|
||||
Run it in the background
|
||||
|
||||
|
||||
Input placeholders
|
||||
--------------------
|
||||
|
||||
There are various different kinds of placeholders
|
||||
|
||||
``@text``
|
||||
Plain text, current screen + scrollback buffer
|
||||
|
||||
``@ansi``
|
||||
Text with formatting, current screen + scrollback buffer
|
||||
|
||||
``@screen``
|
||||
Plain text, only current screen
|
||||
|
||||
``@ansi_screen``
|
||||
Text with formatting, only current screen
|
||||
|
||||
``@alternate``
|
||||
Plain text, secondary screen. The secondary screen is the screen not currently displayed. For
|
||||
example if you run a fullscreen terminal application, the secondary screen will
|
||||
be the screen you return to when quitting the application.
|
||||
|
||||
``@ansi_alternate``
|
||||
Text with formatting, secondary screen.
|
||||
|
||||
``@alternate_scrollback``
|
||||
Plain text, secondary screen + scrollback, if any.
|
||||
|
||||
``@ansi_alternate_scrollback``
|
||||
Text with formatting, secondary screen + scrollback, if any.
|
||||
|
||||
``none``
|
||||
No input
|
||||
|
||||
|
||||
You can also add the suffix ``_wrap`` to the placeholder, in which case kitty
|
||||
will insert the carriage return at every line wrap location (where long lines
|
||||
are wrapped at screen edges). This is useful if you want to pipe to program
|
||||
that wants to duplicate the screen layout of the screen.
|
||||
@ -48,25 +48,29 @@ def listen_on(spec):
|
||||
return s.fileno()
|
||||
|
||||
|
||||
def data_for_at(w, arg):
|
||||
def data_for_at(w, arg, add_wrap_markers=False):
|
||||
def as_text(**kw):
|
||||
kw['add_wrap_markers'] = add_wrap_markers
|
||||
return w.as_text(**kw)
|
||||
|
||||
if arg == '@selection':
|
||||
return w.text_for_selection()
|
||||
if arg == '@ansi':
|
||||
return w.as_text(as_ansi=True, add_history=True)
|
||||
return as_text(as_ansi=True, add_history=True)
|
||||
if arg == '@text':
|
||||
return w.as_text(add_history=True)
|
||||
return as_text(add_history=True)
|
||||
if arg == '@screen':
|
||||
return w.as_text()
|
||||
return as_text()
|
||||
if arg == '@ansi_screen':
|
||||
return w.as_text(as_ansi=True)
|
||||
return as_text(as_ansi=True)
|
||||
if arg == '@alternate':
|
||||
return w.as_text(alternate_screen=True)
|
||||
return as_text(alternate_screen=True)
|
||||
if arg == '@alternate_scrollback':
|
||||
return w.as_text(alternate_screen=True, add_history=True)
|
||||
return as_text(alternate_screen=True, add_history=True)
|
||||
if arg == '@ansi_alternate':
|
||||
return w.as_text(as_ansi=True, alternate_screen=True)
|
||||
return as_text(as_ansi=True, alternate_screen=True)
|
||||
if arg == '@ansi_alternate_scrollback':
|
||||
return w.as_text(as_ansi=True, alternate_screen=True, add_history=True)
|
||||
return as_text(as_ansi=True, alternate_screen=True, add_history=True)
|
||||
|
||||
|
||||
class DumpCommands: # {{{
|
||||
@ -816,9 +820,19 @@ class Boss:
|
||||
|
||||
def special_window_for_cmd(self, cmd, window=None, stdin=None, cwd_from=None, as_overlay=False):
|
||||
w = window or self.active_window
|
||||
env = None
|
||||
if stdin:
|
||||
stdin = data_for_at(w, stdin)
|
||||
add_wrap_markers = stdin.endswith('_wrap')
|
||||
if add_wrap_markers:
|
||||
stdin = stdin[:-len('_wrap')]
|
||||
stdin = data_for_at(w, stdin, add_wrap_markers=add_wrap_markers)
|
||||
if stdin is not None:
|
||||
pipe_data = w.pipe_data(stdin, has_wrap_markers=add_wrap_markers) if w else {}
|
||||
if pipe_data:
|
||||
env = {
|
||||
'KITTY_PIPE_DATA':
|
||||
'{scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns}'.format(**pipe_data)
|
||||
}
|
||||
stdin = stdin.encode('utf-8')
|
||||
cmdline = []
|
||||
for arg in cmd:
|
||||
@ -828,7 +842,7 @@ class Boss:
|
||||
continue
|
||||
cmdline.append(arg)
|
||||
overlay_for = w.id if as_overlay and w.overlay_for is None else None
|
||||
return SpecialWindow(cmd, stdin, cwd_from=cwd_from, overlay_for=overlay_for)
|
||||
return SpecialWindow(cmd, stdin, cwd_from=cwd_from, overlay_for=overlay_for, env=env)
|
||||
|
||||
def pipe(self, source, dest, exe, *args):
|
||||
cmd = [exe] + list(args)
|
||||
|
||||
@ -783,7 +783,7 @@ an arbitrary color, such as :code:`#12af59` or :code:`red`. WARNING: This option
|
||||
using a hack, as there is no proper Cocoa API for it. It sets the background
|
||||
color of the entire window and makes the titlebar transparent. As such it is
|
||||
incompatible with :opt:`background_opacity`. If you want to use both, you are
|
||||
probably better off just hiding the titlebar with :opt:`macos_hide_titlebar`.
|
||||
probably better off just hiding the titlebar with :opt:`hide_window_decorations`.
|
||||
'''))
|
||||
|
||||
o('macos_option_as_alt', True, long_text=_('''
|
||||
@ -877,19 +877,9 @@ the following opens the scrollback buffer in less in an overlay window::
|
||||
|
||||
map f1 pipe @ansi overlay less +G -R
|
||||
|
||||
Placeholders available are: ``@text`` (which is plain text) and ``@ansi`` (which
|
||||
includes text styling escape codes). For only the current screen, use ``@screen``
|
||||
or ``@ansi_screen``. For the secondary screen, use ``@alternate`` and ``@ansi_alternate``.
|
||||
The secondary screen is the screen not currently displayed. For
|
||||
example if you run a fullscreen terminal application, the secondary screen will
|
||||
be the screen you return to when quitting the application. If you want access to the
|
||||
secondary screen scrollback, use ``@alternate_scrollback``. You can also use
|
||||
``none`` for no :file:`STDIN` input.
|
||||
|
||||
To open in a new window, tab or new OS window, use ``window``, ``tab``, or
|
||||
``os_window`` respectively. You can also use ``none`` in which case the data
|
||||
will be piped into the program without creating any windows, useful if the
|
||||
program is a GUI program that creates its own windows. '''))
|
||||
For more details on piping screen and buffer contents to external programs,
|
||||
see :doc:`pipe`.
|
||||
'''))
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
@ -483,15 +483,26 @@ class Window:
|
||||
if pid is not None:
|
||||
return cwd_of_process(pid) or None
|
||||
|
||||
def pipe_data(self, text, has_wrap_markers=False):
|
||||
text = text or ''
|
||||
if has_wrap_markers:
|
||||
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||
lines = text.count('\n')
|
||||
input_line_number = (lines - (self.screen.lines - 1) - self.screen.scrolled_by)
|
||||
return {
|
||||
'input_line_number': input_line_number, 'scrolled_by': self.screen.scrolled_by,
|
||||
'cursor_x': self.screen.cursor.x + 1, 'cursor_y': self.screen.cursor.y + 1,
|
||||
'lines': self.screen.lines, 'columns': self.screen.columns,
|
||||
'text': text
|
||||
}
|
||||
|
||||
# actions {{{
|
||||
|
||||
def show_scrollback(self):
|
||||
data = self.as_text(as_ansi=True, add_history=True, add_wrap_markers=True)
|
||||
data = data.replace('\r\n', '\n').replace('\r', '\n')
|
||||
lines = data.count('\n')
|
||||
input_line_number = (lines - (self.screen.lines - 1) - self.screen.scrolled_by)
|
||||
cmd = [x.replace('INPUT_LINE_NUMBER', str(input_line_number)) for x in self.opts.scrollback_pager]
|
||||
get_boss().display_scrollback(self, data, cmd)
|
||||
text = self.as_text(as_ansi=True, add_history=True, add_wrap_markers=True)
|
||||
data = self.pipe_data(text, has_wrap_markers=True)
|
||||
cmd = [x.replace('INPUT_LINE_NUMBER', str(data['input_line_number'])) for x in self.opts.scrollback_pager]
|
||||
get_boss().display_scrollback(self, data['text'], cmd)
|
||||
|
||||
def paste(self, text):
|
||||
if text and not self.destroyed:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user