diff --git a/docs/index.rst b/docs/index.rst index 36bb4e117..7bb7839f8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -415,7 +415,7 @@ comfortably within the pager. Additionally, you can pipe the contents of the scrollback buffer to an arbitrary, command running in a new window, tab or overlay, for example:: - map f1 pipe @ansi window less +G -R + map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting less +G -R Would open the scrollback buffer in a new window when you press the :kbd:`F1` key. See :sc:`show_scrollback` for details. diff --git a/docs/launch.rst b/docs/launch.rst index ec254115c..f5c9d77f9 100644 --- a/docs/launch.rst +++ b/docs/launch.rst @@ -35,6 +35,20 @@ To pass the contents of the current screen and scrollback to the started process There are many more powerful options, refer to the complete list below. +The piping environment +-------------------------- + +When using :option:`launch --stdin-source`, 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. + Syntax reference ------------------ diff --git a/docs/pipe.rst b/docs/pipe.rst index d1fa99ead..8f1289cd8 100644 --- a/docs/pipe.rst +++ b/docs/pipe.rst @@ -1,6 +1,9 @@ Working with the screen and history buffer contents ====================================================== +.. warning:: + The pipe action has been deprecated in favor of the + :doc:`launch ` action which is more powerful. 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 diff --git a/kitty/boss.py b/kitty/boss.py index b7bf65ae5..492293f8f 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -914,6 +914,25 @@ class Boss: 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, env=env) + def run_background_process(self, cmd, cwd=None, env=None, stdin=None, cwd_from=None): + import subprocess + if cwd_from: + with suppress(Exception): + cwd = cwd_of_process(cwd_from) + + if stdin: + r, w = safe_pipe(False) + try: + subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd) + except Exception: + os.close(w) + else: + thread_write(w, stdin) + finally: + os.close(r) + else: + subprocess.Popen(cmd, env=env, cwd=cwd) + def pipe(self, source, dest, exe, *args): cmd = [exe] + list(args) window = self.active_window @@ -939,24 +958,8 @@ class Boss: func = set_clipboard_string if dest == 'clipboard' else set_primary_selection func(stdin) else: - import subprocess env, stdin = self.process_stdin_source(stdin=source, window=window) - cwd = None - if cwd_from: - with suppress(Exception): - cwd = cwd_of_process(cwd_from) - if stdin: - r, w = safe_pipe(False) - try: - subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd) - except Exception: - os.close(w) - else: - thread_write(w, stdin) - finally: - os.close(r) - else: - subprocess.Popen(cmd, env=env, cwd=cwd) + self.run_background_process(cmd, cwd_from=cwd_from, stdin=stdin, env=env) def args_to_special_window(self, args, cwd_from=None): args = list(args) diff --git a/kitty/cmds.py b/kitty/cmds.py index c378b1f19..0154993b6 100644 --- a/kitty/cmds.py +++ b/kitty/cmds.py @@ -792,7 +792,7 @@ Do not print out the id of the newly created window. type=bool-set If specified the tab containing the window this command is run in is used instead of the active tab - ''' + '\n\n' + launch_options_spec(), + ''' + '\n\n' + launch_options_spec().replace(':option:`launch', ':option:`kitty @ launch'), argspec='[CMD ...]' ) def cmd_launch(global_opts, opts, args): @@ -841,7 +841,7 @@ def launch(boss, window, payload): tabs = [window.tabref()] tab = tabs[0] w = do_launch(boss, opts, pg(payload, 'args') or None, target_tab=tab) - return None if pg(payload, 'no_response') else str(w.id) + return None if pg(payload, 'no_response') else str(getattr(w, 'id', 0)) # }}} diff --git a/kitty/config_data.py b/kitty/config_data.py index 107c8fd84..a496f950b 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -1073,13 +1073,13 @@ if is_macos: k('show_scrollback', 'kitty_mod+h', 'show_scrollback', _('Browse scrollback buffer in less'), long_text=_(''' You can pipe the contents of the current screen + history buffer as -:file:`STDIN` to an arbitrary program using the ``pipe`` function. For example, +:file:`STDIN` to an arbitrary program using the ``launch`` function. For example, the following opens the scrollback buffer in less in an overlay window:: - map f1 pipe @ansi overlay less +G -R + map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting --type=overlay less +G -R For more details on piping screen and buffer contents to external programs, -see :doc:`pipe`. +see :doc:`launch`. ''')) diff --git a/kitty/launch.py b/kitty/launch.py index 6a4fe24e9..24c20d7ef 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -4,6 +4,8 @@ from kitty.cli import parse_args +from kitty.fast_data_types import set_clipboard_string +from kitty.utils import set_primary_selection def options_spec(): @@ -22,11 +24,14 @@ of the actie window in the tab is used as the tab title. --type type=choices default=window -choices=window,tab,os-window,overlay +choices=window,tab,os-window,overlay,background,clipboard,primary Where to launch the child process, in a new kitty window in the current tab, a new tab, or a new OS window or an overlay over the current window. Note that if the current window already has an overlay, then it will -open a new window. +open a new window. The value of none means the process will be +run in the background. The values clipboard and primary are meant +to work with :option:`launch --stdin-source` to copy data to the system +clipboard or primary selection. --keep-focus @@ -197,8 +202,15 @@ def launch(boss, opts, args, target_tab=None): if penv: env.update(penv) - tab = tab_for_window(boss, opts, target_tab) - new_window = tab.new_window(env=env or None, **kw) - if opts.keep_focus and active: - boss.set_active_window(active, switch_os_window_if_needed=True) - return new_window + if opts.type == 'background': + boss.run_background_process(kw['cmd'], cwd=kw.get('cwd'), cwd_from=kw.get('cwd_from'), env=env or None, stdin=kw.get('stdin')) + elif opts.type in ('clipboard', 'primary'): + if 'stdin' in kw: + func = set_clipboard_string if opts.type == 'clipboard' else set_primary_selection + func(kw['stdin']) + else: + tab = tab_for_window(boss, opts, target_tab) + new_window = tab.new_window(env=env or None, **kw) + if opts.keep_focus and active: + boss.set_active_window(active, switch_os_window_if_needed=True) + return new_window