diff --git a/docs/changelog.rst b/docs/changelog.rst index 643102ce4..dfece10f6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -41,6 +41,8 @@ Detailed list of changes - Sessions: Fix :code:`os_window_size` and :code:`os_window_class` not applying to the first OS Window (:iss:`4957`) +- Allow using the cwd of the oldest as well as the newest foreground process for :option:`launch --cwd` (:disc:`4869`) + 0.25.0 [2022-04-11] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/child.py b/kitty/child.py index e676c2c23..e64cf4eeb 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -352,8 +352,7 @@ class Child: return cwd_of_process(self.pid) return None - @property - def pid_for_cwd(self) -> Optional[int]: + def get_pid_for_cwd(self, oldest: bool = False) -> Optional[int]: with suppress(Exception): assert self.child_fd is not None pgrp = os.tcgetpgrp(self.child_fd) @@ -369,25 +368,32 @@ class Child: # vim # With this script , the foreground process group will contain # both the bash instance running the script and vim. - return max(foreground_processes) + return min(foreground_processes) if oldest else max(foreground_processes) return self.pid @property - def foreground_cwd(self) -> Optional[str]: + def pid_for_cwd(self) -> Optional[int]: + return self.get_pid_for_cwd() + + def get_foreground_cwd(self, oldest: bool = False) -> Optional[str]: with suppress(Exception): - assert self.pid_for_cwd is not None - return cwd_of_process(self.pid_for_cwd) or None + pid = self.get_pid_for_cwd(oldest) + if pid is not None: + return cwd_of_process(pid) or None return None + @property + def foreground_cwd(self) -> Optional[str]: + return self.get_foreground_cwd() + @property def foreground_environ(self) -> Dict[str, str]: - try: - assert self.pid_for_cwd is not None - return environ_of_process(self.pid_for_cwd) - except Exception: - try: - assert self.pid is not None - return environ_of_process(self.pid) - except Exception: - pass + pid = self.pid_for_cwd + if pid is not None: + with suppress(Exception): + return environ_of_process(pid) + pid = self.pid + if pid is not None: + with suppress(Exception): + return environ_of_process(pid) return {} diff --git a/kitty/launch.py b/kitty/launch.py index 3e48ba980..9276d6e6f 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -67,7 +67,10 @@ to the newly opened window. The working directory for the newly launched child. Use the special value :code:`current` to use the working directory of the currently active window. The special value :code:`last_reported` uses the last working directory -reported by the shell (needs :ref:`shell_integration` to work). +reported by the shell (needs :ref:`shell_integration` to work). The special +value :code:`oldest` works like :code:`current` but uses the working directory +of the oldest foreground process associated with the currently active window +rather than the newest foreground process. --env @@ -382,6 +385,8 @@ def launch( elif opts.cwd == 'last_reported': if active: kw['cwd_from'] = CwdRequest(active, CwdRequestType.last_reported) + elif opts.cwd == 'oldest': + kw['cwd_from'] = CwdRequest(active, CwdRequestType.last_reported) else: kw['cwd'] = opts.cwd if opts.location != 'default': diff --git a/kitty/window.py b/kitty/window.py index 09276dc29..54077d3cf 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -61,6 +61,7 @@ if TYPE_CHECKING: class CwdRequestType(Enum): current: int = auto() last_reported: int = auto() + oldest: int = auto() class CwdRequest: @@ -84,7 +85,7 @@ class CwdRequest: reported_cwd = path_from_osc7_url(window.screen.last_reported_cwd) if window.screen.last_reported_cwd else '' if reported_cwd and not window.child_is_remote and (self.request_type is CwdRequestType.last_reported or window.at_prompt): return reported_cwd - return window.cwd_of_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]) -> str: window = self.window @@ -1272,9 +1273,12 @@ class Window: def cmd_output(self, which: CommandOutput = CommandOutput.last_run, as_ansi: bool = False, add_wrap_markers: bool = False) -> str: return cmd_output(self.screen, which, as_ansi, add_wrap_markers) + def get_cwd_of_child(self, oldest: bool = False) -> Optional[str]: + return self.child.get_foreground_cwd(oldest) or self.child.current_cwd + @property def cwd_of_child(self) -> Optional[str]: - return self.child.foreground_cwd or self.child.current_cwd + return self.get_cwd_of_child() @property def child_is_remote(self) -> bool: