From ca2232e4358e6e3525bba67c7eac6aa6cc191e0b Mon Sep 17 00:00:00 2001 From: Barr Date: Fri, 11 Jul 2025 18:34:21 +0300 Subject: [PATCH] feat: new option --hold-after-ssh to allow spawning a shell after a kitten ssh disconnection new option to the launch command, the new shell will be in the directory that launched kitten ssh --- kitty/child.py | 3 ++- kitty/launch.py | 16 +++++++++++++++- kitty/rc/launch.py | 1 + kitty/tabs.py | 6 ++++-- kitty/window.py | 12 ++++++++---- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/kitty/child.py b/kitty/child.py index 1f45990b4..40f7667a9 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -221,6 +221,7 @@ class Child: hold: bool = False, pass_fds: tuple[int, ...] = (), remote_control_fd: int = -1, + hold_after_ssh: bool = False ): self.is_clone_launch = is_clone_launch self.id = next(child_counter) @@ -230,7 +231,7 @@ class Child: self.remote_control_fd = remote_control_fd if cwd_from: try: - cwd = cwd_from.modify_argv_for_launch_with_cwd(self.argv, env) or cwd + cwd = cwd_from.modify_argv_for_launch_with_cwd(self.argv, env, hold_after_ssh=hold_after_ssh) or cwd except Exception as err: log_error(f'Failed to read cwd of {cwd_from} with error: {err}') else: diff --git a/kitty/launch.py b/kitty/launch.py index 92f28858b..1889f74cd 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -140,6 +140,8 @@ by the shell (needs :ref:`shell_integration` to work). The special value oldest foreground process associated with the currently active window rather than the newest foreground process. Finally, the special value :code:`root` refers to the process that was originally started when the window was created. +When running :code:`kitten ssh`, using :option:`--hold-after-ssh` will cause a shell +in the working directory that started the :code:`kitten ssh` to be opened after disconnecting. --env @@ -393,6 +395,11 @@ and :option:`--config `. Can be specified multiple For example, to create a desktop panel at the bottom of the screen two lines high:: launch --type os-panel --os-panel lines=2 --os-panel edge=bottom sh -c "echo; echo; echo hello; sleep 5s" + + +--hold-after-ssh +type=bool-set +When using :option:`--cwd=current` from a kitten ssh session, after disconnecting from the session on the new window, a shell will spawn. """ @@ -536,6 +543,7 @@ class LaunchKwds(TypedDict): stdin: bytes | None hold: bool bias: float | None + hold_after_ssh: bool def apply_colors(window: Window, spec: Sequence[str]) -> None: @@ -636,6 +644,7 @@ def _launch( 'stdin': None, 'hold': False, 'bias': None, + 'hold_after_ssh': False } spacing = {} if opts.spacing: @@ -658,6 +667,11 @@ def _launch( kw['cwd_from'] = CwdRequest(source_window, CwdRequestType.root) else: kw['cwd'] = opts.cwd + if opts.hold_after_ssh: + if opts.cwd != 'current': + raise ValueError("--hold_after_ssh can only be supplied if --cwd=current is also supplied") + kw['hold_after_ssh'] = True + if opts.location != 'default': kw['location'] = opts.location if opts.copy_colors and source_window: @@ -804,7 +818,7 @@ def clone_safe_opts() -> frozenset[str]: return frozenset(( 'window_title', 'tab_title', 'type', 'keep_focus', 'cwd', 'env', 'var', 'hold', 'location', 'os_window_class', 'os_window_name', 'os_window_title', 'os_window_state', - 'logo', 'logo_position', 'logo_alpha', 'color', 'spacing', 'next_to', + 'logo', 'logo_position', 'logo_alpha', 'color', 'spacing', 'next_to', 'hold_after_ssh' )) diff --git a/kitty/rc/launch.py b/kitty/rc/launch.py index 635238c83..2b962e80a 100644 --- a/kitty/rc/launch.py +++ b/kitty/rc/launch.py @@ -57,6 +57,7 @@ class Launch(RemoteCommand): watcher/list.str: list of paths to watcher files bias/float: The bias with which to create the new window in the current layout wait_for_child_to_exit/bool: Boolean indicating whether to wait and return child exit code + hold_after_ssh/bool: Boolean indicating whether to spawn a shell after exiting a kitten ssh opened by this launch, requires --cwd=current to also be supplied ''' short_desc = 'Run an arbitrary process in a new window/tab' diff --git a/kitty/tabs.py b/kitty/tabs.py index 342990148..da22cbc06 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -480,6 +480,7 @@ class Tab: # {{{ hold: bool = False, pass_fds: tuple[int, ...] = (), remote_control_fd: int = -1, + hold_after_ssh: bool = False ) -> Child: check_for_suitability = True if cmd is None: @@ -529,7 +530,7 @@ class Tab: # {{{ fenv['WINDOWID'] = str(pwid) ans = Child( cmd, cwd or self.cwd, stdin, fenv, cwd_from, is_clone_launch=is_clone_launch, - add_listen_on_env_var=add_listen_on_env_var, hold=hold, pass_fds=pass_fds, remote_control_fd=remote_control_fd) + add_listen_on_env_var=add_listen_on_env_var, hold=hold, pass_fds=pass_fds, remote_control_fd=remote_control_fd, hold_after_ssh=hold_after_ssh) ans.fork() return ans @@ -568,11 +569,12 @@ class Tab: # {{{ pass_fds: tuple[int, ...] = (), remote_control_fd: int = -1, next_to: Window | None = None, + hold_after_ssh: bool = False ) -> Window: child = self.launch_child( use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env, is_clone_launch=is_clone_launch, add_listen_on_env_var=False if allow_remote_control and remote_control_passwords else True, - hold=hold, pass_fds=pass_fds, remote_control_fd=remote_control_fd, + hold=hold, pass_fds=pass_fds, remote_control_fd=remote_control_fd, hold_after_ssh=hold_after_ssh ) window = Window( self, child, self.args, override_title=override_title, diff --git a/kitty/window.py b/kitty/window.py index 951a77803..69fa46507 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -155,7 +155,7 @@ class CwdRequest: return window.get_cwd_of_root_child() or '' return window.get_cwd_of_child(oldest=self.request_type is CwdRequestType.oldest) or '' - def modify_argv_for_launch_with_cwd(self, argv: list[str], env: dict[str, str] | None=None) -> str: + def modify_argv_for_launch_with_cwd(self, argv: list[str], env: dict[str, str] | None=None, hold_after_ssh: bool = False) -> str: window = self.window if not window: return '' @@ -166,9 +166,13 @@ class CwdRequest: run_shell = argv[0] == resolved_shell(get_options())[0] server_args = [] if run_shell else list(argv) from kittens.ssh.utils import set_cwd_in_cmdline, set_env_in_cmdline, set_server_args_in_cmdline - argv[:] = ssh_kitten_cmdline - if argv and argv[0] == 'kitten': - argv[0] = kitten_exe() + if ssh_kitten_cmdline and ssh_kitten_cmdline[0] == 'kitten': + if hold_after_ssh: + argv[:] = [kitten_exe(), "run-shell", kitten_exe()] +ssh_kitten_cmdline[1:] + else: + argv[:] = [kitten_exe()]+ssh_kitten_cmdline[1:] + else: + argv[:] = ssh_kitten_cmdline set_cwd_in_cmdline(reported_cwd, argv) set_server_args_in_cmdline(server_args, argv, allocate_tty=not run_shell) if env is not None: