diff --git a/kitty/boss.py b/kitty/boss.py index 9ce4e3641..4bd92a05d 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -62,7 +62,7 @@ from .utils import ( safe_print, set_primary_selection, single_instance, startup_notification_handler, which ) -from .window import CommandOutput, MatchPatternType, Window +from .window import CommandOutput, CwdRequest, MatchPatternType, Window class OSWindowDict(TypedDict): @@ -439,7 +439,7 @@ class Boss: return os_window_id return None - def _new_os_window(self, args: Union[SpecialWindowInstance, Iterable[str]], cwd_from: Optional[Window] = None) -> int: + def _new_os_window(self, args: Union[SpecialWindowInstance, Iterable[str]], cwd_from: Optional[CwdRequest] = None) -> int: if isinstance(args, SpecialWindowInstance): sw: Optional[SpecialWindowInstance] = args else: @@ -461,7 +461,7 @@ class Boss: @ac('win', 'New OS Window with the same working directory as the currently active window') def new_os_window_with_cwd(self, *args: str) -> None: w = self.active_window_for_cwd - self._new_os_window(args, w) + self._new_os_window(args, CwdRequest(w)) def new_os_window_with_wd(self, wd: str) -> None: special_window = SpecialWindow(None, cwd=wd) @@ -1717,7 +1717,7 @@ class Boss: self, cmd: List[str], window: Optional[Window] = None, stdin: Optional[str] = None, - cwd_from: Optional[Window] = None, + cwd_from: Optional[CwdRequest] = None, as_overlay: bool = False ) -> SpecialWindowInstance: w = window or self.active_window @@ -1739,7 +1739,7 @@ class Boss: cwd: Optional[str] = None, env: Optional[Dict[str, str]] = None, stdin: Optional[bytes] = None, - cwd_from: Optional[Window] = None + cwd_from: Optional[CwdRequest] = None ) -> None: import subprocess env = env or None @@ -1766,7 +1766,8 @@ class Boss: def pipe(self, source: str, dest: str, exe: str, *args: str) -> Optional[Window]: cmd = [exe] + list(args) - window = cwd_from = self.active_window + window = self.active_window + cwd_from = CwdRequest(window) if window else None def create_window() -> SpecialWindowInstance: return self.special_window_for_cmd( @@ -1794,7 +1795,7 @@ class Boss: self.run_background_process(cmd, cwd_from=cwd_from, stdin=stdin, env=env) return None - def args_to_special_window(self, args: Iterable[str], cwd_from: Optional[Window] = None) -> SpecialWindowInstance: + def args_to_special_window(self, args: Iterable[str], cwd_from: Optional[CwdRequest] = None) -> SpecialWindowInstance: args = list(args) stdin = None w = self.active_window @@ -1815,7 +1816,7 @@ class Boss: cmd.append(arg) return SpecialWindow(cmd, stdin, cwd_from=cwd_from) - def _new_tab(self, args: Union[SpecialWindowInstance, Iterable[str]], cwd_from: Optional[Window] = None, as_neighbor: bool = False) -> Optional[Tab]: + def _new_tab(self, args: Union[SpecialWindowInstance, Iterable[str]], cwd_from: Optional[CwdRequest] = None, as_neighbor: bool = False) -> Optional[Tab]: special_window = None if args: if isinstance(args, SpecialWindowInstance): @@ -1827,7 +1828,7 @@ class Boss: return tm.new_tab(special_window=special_window, cwd_from=cwd_from, as_neighbor=as_neighbor) return None - def _create_tab(self, args: List[str], cwd_from: Optional[Window] = None) -> None: + def _create_tab(self, args: List[str], cwd_from: Optional[CwdRequest] = None) -> None: as_neighbor = False if args and args[0].startswith('!'): as_neighbor = 'neighbor' in args[0][1:].split(',') @@ -1840,7 +1841,7 @@ class Boss: @ac('tab', 'Create a new tab with working directory for the window in it set to the same as the active window') def new_tab_with_cwd(self, *args: str) -> None: - self._create_tab(list(args), cwd_from=self.active_window_for_cwd) + self._create_tab(list(args), cwd_from=CwdRequest(self.active_window_for_cwd)) def new_tab_with_wd(self, wd: str) -> None: if not self.os_window_map: @@ -1848,7 +1849,7 @@ class Boss: special_window = SpecialWindow(None, cwd=wd) self._new_tab(special_window) - def _new_window(self, args: List[str], cwd_from: Optional[Window] = None) -> Optional[Window]: + def _new_window(self, args: List[str], cwd_from: Optional[CwdRequest] = None) -> Optional[Window]: tab = self.active_tab if tab is None: return None @@ -1876,7 +1877,7 @@ class Boss: w = self.active_window_for_cwd if w is None: return self.new_window(*args) - self._new_window(list(args), cwd_from=w) + self._new_window(list(args), cwd_from=CwdRequest(w)) @ac('misc', ''' Launch the specified program in a new window/tab/etc. diff --git a/kitty/child.py b/kitty/child.py index a210630b5..f08b57932 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -21,7 +21,7 @@ try: except ImportError: TypedDict = dict if TYPE_CHECKING: - from .window import Window + from .window import CwdRequest if is_macos: @@ -194,12 +194,12 @@ class Child: cwd: str, stdin: Optional[bytes] = None, env: Optional[Dict[str, str]] = None, - cwd_from: Optional['Window'] = None, + cwd_from: Optional['CwdRequest'] = None, allow_remote_control: bool = False ): self.allow_remote_control = allow_remote_control self.argv = list(argv) - if cwd_from is not None: + if cwd_from: try: cwd = cwd_from.modify_argv_for_launch_with_cwd(self.argv) or cwd except Exception as err: diff --git a/kitty/launch.py b/kitty/launch.py index 9c9cf4432..c5762ac77 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -14,7 +14,7 @@ from .options.utils import env as parse_env from .tabs import Tab, TabManager from .types import run_once from .utils import log_error, resolve_custom_file, set_primary_selection, which -from .window import Watchers, Window +from .window import CwdRequest, Watchers, Window try: from typing import TypedDict @@ -290,7 +290,7 @@ def load_watch_modules(watchers: Iterable[str]) -> Optional[Watchers]: class LaunchKwds(TypedDict): allow_remote_control: bool - cwd_from: Optional[Window] + cwd_from: Optional[CwdRequest] cwd: Optional[str] location: Optional[str] override_title: Optional[str] @@ -358,7 +358,7 @@ def launch( if opts.cwd: if opts.cwd == 'current': if active: - kw['cwd_from'] = active + kw['cwd_from'] = CwdRequest(active) else: kw['cwd'] = opts.cwd if opts.location != 'default': diff --git a/kitty/session.py b/kitty/session.py index 105d20f79..c46b9c59a 100644 --- a/kitty/session.py +++ b/kitty/session.py @@ -16,7 +16,7 @@ from .utils import log_error, resolved_shell if TYPE_CHECKING: - from .window import Window + from .window import CwdRequest def get_os_window_sizing_data(opts: Options, session: Optional['Session'] = None) -> WindowSizeData: @@ -150,7 +150,7 @@ def create_sessions( opts: Options, args: Optional[CLIOptions] = None, special_window: Optional['SpecialWindowInstance'] = None, - cwd_from: Optional['Window'] = None, + cwd_from: Optional['CwdRequest'] = None, respect_cwd: bool = False, default_session: Optional[str] = None ) -> Generator[Session, None, None]: diff --git a/kitty/tabs.py b/kitty/tabs.py index 2d60ef3c0..a906e71aa 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -30,7 +30,7 @@ from .tab_bar import TabBar, TabBarData from .types import ac from .typing import EdgeLiteral, SessionTab, SessionType, TypedDict from .utils import log_error, platform_window_id, resolved_shell -from .window import Watchers, Window, WindowDict +from .window import CwdRequest, Watchers, Window, WindowDict from .window_list import WindowList @@ -58,7 +58,7 @@ class SpecialWindowInstance(NamedTuple): cmd: Optional[List[str]] stdin: Optional[bytes] override_title: Optional[str] - cwd_from: Optional[Window] + cwd_from: Optional[CwdRequest] cwd: Optional[str] overlay_for: Optional[int] env: Optional[Dict[str, str]] @@ -69,7 +69,7 @@ def SpecialWindow( cmd: Optional[List[str]], stdin: Optional[bytes] = None, override_title: Optional[str] = None, - cwd_from: Optional[Window] = None, + cwd_from: Optional[CwdRequest] = None, cwd: Optional[str] = None, overlay_for: Optional[int] = None, env: Optional[Dict[str, str]] = None, @@ -98,7 +98,7 @@ class Tab: # {{{ tab_manager: 'TabManager', session_tab: Optional['SessionTab'] = None, special_window: Optional[SpecialWindowInstance] = None, - cwd_from: Optional[Window] = None, + cwd_from: Optional[CwdRequest] = None, no_initial_window: bool = False ): self.tab_manager_ref = weakref.ref(tab_manager) @@ -347,7 +347,7 @@ class Tab: # {{{ use_shell: bool = False, cmd: Optional[List[str]] = None, stdin: Optional[bytes] = None, - cwd_from: Optional[Window] = None, + cwd_from: Optional[CwdRequest] = None, cwd: Optional[str] = None, env: Optional[Dict[str, str]] = None, allow_remote_control: bool = False @@ -414,7 +414,7 @@ class Tab: # {{{ cmd: Optional[List[str]] = None, stdin: Optional[bytes] = None, override_title: Optional[str] = None, - cwd_from: Optional[Window] = None, + cwd_from: Optional[CwdRequest] = None, cwd: Optional[str] = None, overlay_for: Optional[int] = None, env: Optional[Dict[str, str]] = None, @@ -942,7 +942,7 @@ class TabManager: # {{{ def new_tab( self, special_window: Optional[SpecialWindowInstance] = None, - cwd_from: Optional[Window] = None, + cwd_from: Optional[CwdRequest] = None, as_neighbor: bool = False, empty_tab: bool = False, location: str = 'last' diff --git a/kitty/window.py b/kitty/window.py index bdfb7158e..57c4fd6b5 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -7,7 +7,7 @@ import re import sys import weakref from collections import deque -from enum import IntEnum +from enum import Enum, IntEnum, auto from functools import partial from gettext import gettext as _ from itertools import chain @@ -57,6 +57,30 @@ if TYPE_CHECKING: from .file_transmission import FileTransmission +class CwdRequestType(Enum): + current: int = auto() + last_reported: int = auto() + + +class CwdRequest: + + def __init__(self, window: Optional['Window'] = None, request_type: CwdRequestType = CwdRequestType.current) -> None: + self.window_id = -1 if window is None else window.id + self.request_type = request_type + + def __bool__(self) -> bool: + return self.window_id > -1 + + def modify_argv_for_launch_with_cwd(self, argv: List[str]) -> str: + window = get_boss().window_id_map.get(self.window_id) + return window.modify_argv_for_launch_with_cwd(argv) if window else '' + + @property + def cwd_of_child(self) -> Optional[str]: + window = get_boss().window_id_map.get(self.window_id) + return window.cwd_of_child if window else None + + def process_title_from_child(title: str, is_base64: bool) -> str: if is_base64: from base64 import standard_b64decode