A new pipe function that can be used to pipe the contents of the screen and scrollback buffer to any desired program running in a new window, tab or overlay window.

This commit is contained in:
Kovid Goyal 2018-09-09 18:29:29 +05:30
parent e5a7ba4f22
commit b9b38a4ec1
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 88 additions and 26 deletions

View File

@ -6,13 +6,17 @@ Changelog
0.12.2 [future]
------------------------------
- Add a new ``last_used_layout`` function that can be mapped to a shortcut to
- A new ``last_used_layout`` function that can be mapped to a shortcut to
switch to the previously used window layout (:iss:`870`)
- Add new ``neighboring_window`` and ``move_window`` functions to switch to
- New ``neighboring_window`` and ``move_window`` functions to switch to
neighboring windows in the current layout, and move them around, similar to
window movement in vim (:iss:`916`)
- A new ``pipe`` function that can be used to pipe the contents of the screen
and scrollback buffer to any desired program running in a new window, tab or
overlay window. (:iss:`933`)
- Add a new :option:`kitty --start-as` command line flag to start kitty
fullscreen/maximized/minimized. This replaces the ``--start-in-fullscreen``
flag introduced in the previous release (:iss:`935`)

View File

@ -48,6 +48,23 @@ def listen_on(spec):
return s.fileno()
def data_for_at(w, arg):
if arg == '@selection':
return w.text_for_selection()
if arg == '@ansi':
return w.as_text(as_ansi=True, add_history=True)
if arg == '@text':
return w.as_text(add_history=True)
if arg == '@screen':
return w.as_text()
if arg == '@ansi_screen':
return w.as_text(as_ansi=True)
if arg == '@alternate':
return w.as_text(alternate_screen=True)
if arg == '@ansi_alternate':
return w.as_text(as_ansi=True, alternate_screen=True)
class DumpCommands: # {{{
def __init__(self, args):
@ -774,29 +791,50 @@ class Boss:
if tm is not None:
tm.next_tab(-1)
def special_window_for_cmd(self, cmd, window=None, stdin=None, cwd_from=None, as_overlay=False):
w = window or self.active_window
if stdin:
stdin = data_for_at(w, stdin)
if stdin is not None:
stdin = stdin.encode('utf-8')
cmdline = []
for arg in cmd:
if arg == '@selection':
arg = data_for_at(w, arg)
if not arg:
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)
def pipe(self, source, dest, exe, *args):
cmd = [exe] + list(args)
window = self.active_window
cwd_from = window.child.pid if window else None
def create_window():
return self.special_window_for_cmd(
cmd, stdin=source, as_overlay=dest == 'overlay', cwd_from=cwd_from)
if dest == 'overlay' or dest == 'window':
tab = self.active_tab
if tab is not None:
return tab.new_special_window(create_window())
elif dest == 'tab':
tm = self.active_tab_manager
if tm is not None:
tm.new_tab(special_window=create_window(), cwd_from=cwd_from)
else:
import subprocess
subprocess.Popen(cmd)
def args_to_special_window(self, args, cwd_from=None):
args = list(args)
stdin = None
w = self.active_window
def data_for_at(arg):
if arg == '@selection':
return w.text_for_selection()
if arg == '@ansi':
return w.as_text(as_ansi=True, add_history=True)
if arg == '@text':
return w.as_text(add_history=True)
if arg == '@screen':
return w.as_text()
if arg == '@ansi_screen':
return w.as_text(as_ansi=True)
if arg == '@alternate':
return w.as_text(alternate_screen=True)
if arg == '@ansi_alternate':
return w.as_text(as_ansi=True, alternate_screen=True)
if args[0].startswith('@') and args[0] != '@':
stdin = data_for_at(args[0]) or None
stdin = data_for_at(w, args[0]) or None
if stdin is not None:
stdin = stdin.encode('utf-8')
del args[0]
@ -804,7 +842,7 @@ class Boss:
cmd = []
for arg in args:
if arg == '@selection':
arg = data_for_at(arg)
arg = data_for_at(w, arg)
if not arg:
continue
cmd.append(arg)

View File

@ -163,6 +163,16 @@ def move_window(func, rest):
return func, [rest]
@func_with_args('pipe')
def pipe(func, rest):
import shlex
rest = shlex.split(rest)
if len(rest) < 3:
log_error('Too few arguments to pipe function')
rest = ['none', 'none', 'true']
return func, rest
def parse_key_action(action):
parts = action.split(' ', 1)
func = parts[0]

View File

@ -825,13 +825,23 @@ k('scroll_page_down', 'kitty_mod+page_down', 'scroll_page_down', _('Scroll page
k('scroll_home', 'kitty_mod+home', 'scroll_home', _('Scroll to top'))
k('scroll_end', 'kitty_mod+end', 'scroll_end', _('Scroll to bottom'))
k('show_scrollback', 'kitty_mod+h', 'show_scrollback', _('Browse scrollback buffer in less'), long_text=_('''
You can send the contents of the current screen + history buffer as stdin to an arbitrary program using
the placeholders @text (which is the 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.
For example, the following command opens the scrollback buffer in less in a new window::
map kitty_mod+y new_window @ansi less +G -R
You can pipe the contents of the current screen + history buffer as
:file:`STDIN` to an arbitrary program using the ``pipe`` function. For example,
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.
Note that the secondary screen is 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.
To open in a new window or tab use ``window`` or ``tab`` respectively. You can
also use ``none`` in which case the data will be piped into the program without
creating any windows.
'''))