diff --git a/kitty/boss.py b/kitty/boss.py index 6017a24d6..1146b06cc 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -370,7 +370,7 @@ class Boss: for tab in self.all_tabs: yield from tab - def match_windows(self, match: str) -> Iterator[Window]: + def match_windows(self, match: str, self_window: Optional['Window'] = None) -> Iterator[Window]: if match == 'all': yield from self.all_windows return @@ -390,7 +390,7 @@ class Boss: return set() if q < 0: query = str(window_id_limit + q) - return {wid for wid in candidates if self.window_id_map[wid].matches_query(location, query, tab)} + return {wid for wid in candidates if self.window_id_map[wid].matches_query(location, query, tab, self_window)} for wid in search(match, ( 'id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'recent', 'state' diff --git a/kitty/rc/base.py b/kitty/rc/base.py index 07b678b60..89dcfa4da 100644 --- a/kitty/rc/base.py +++ b/kitty/rc/base.py @@ -117,10 +117,16 @@ active window, one being the previously active window and so on. When using the :code:`env` field to match on environment variables, you can specify only the environment variable name or a name and value, for example, :code:`env:MY_ENV_VAR=2`. -The field :code:`state` matches on the state of the window. Supported states are: -:code:`active`, :code:`focused`, :code:`needs_attention`, :code:`parent_active` and :code:`parent_focused`. -Active windows are the windows that are active in their parent tab. There is only one focused window and it is the -window to which keyboard events are delivered. If no window is focused, the last focused window is matched. +The field :code:`state` matches on the state of the window. Supported states +are: :code:`active`, :code:`focused`, :code:`needs_attention`, +:code:`parent_active`, :code:`parent_focused`, :code:`self`, +:code:`overlay_parent`. Active windows are the windows that are active in +their parent tab. There is only one focused window and it is the window to +which keyboard events are delivered. If no window is focused, the last focused +window is matched. The value :code:`self` matches the window in which the +remote control command is run. The value :code:`overlay_parent` matches the +window that is under the :code:`self` window, when the self window is an +overlay. Note that you can use the :ref:`kitty @ ls ` command to get a list of windows. ''' @@ -341,13 +347,14 @@ class RemoteCommand: if payload_get('all'): windows = list(boss.all_windows) else: + self_window = window if payload_get('self') in (None, True): window = window or boss.active_window else: window = boss.active_window or window windows = [window] if window else [] if payload_get('match'): - windows = list(boss.match_windows(payload_get('match'))) + windows = list(boss.match_windows(payload_get('match'), self_window)) if not windows: raise MatchError(payload_get('match')) return windows diff --git a/kitty/tabs.py b/kitty/tabs.py index ba363c161..266896630 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -496,6 +496,14 @@ class Tab: # {{{ def move_window_to_top_of_group(self, window: Window) -> bool: return self.windows.move_window_to_top_of_group(window) + def overlay_parent(self, window: Window) -> Optional[Window]: + prev: Optional[Window] = None + for x in self.windows.windows_in_group_of(window): + if x is window: + break + prev = x + return prev + def remove_window(self, window: Window, destroy: bool = True) -> None: self.windows.remove_window(window) if destroy: diff --git a/kitty/window.py b/kitty/window.py index 5fcd1aac1..096b89139 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -652,6 +652,13 @@ class Window: ans['overlay_type'] = self.overlay_type.value return ans + @property + def overlay_parent(self) -> Optional['Window']: + tab = self.tabref() + if tab is None: + return None + return tab.overlay_parent(self) + @property def current_colors(self) -> Dict[str, Optional[int]]: return self.screen.color_profile.as_dict() @@ -692,7 +699,7 @@ class Window: return False return False - def matches_query(self, field: str, query: str, active_tab: Optional[TabType] = None) -> bool: + def matches_query(self, field: str, query: str, active_tab: Optional[TabType] = None, self_window: Optional['Window'] = None) -> bool: if field in ('num', 'recent'): if active_tab is not None: try: @@ -720,6 +727,10 @@ class Window: return False if query == 'parent_focused': return active_tab is not None and self.tabref() is active_tab and last_focused_os_window_id() == self.os_window_id + if query == 'self': + return self is self_window + if query == 'overlay_parent': + return self_window is not None and self is self_window.overlay_parent return False pat = compile_match_query(query, field != 'env') return self.matches(field, pat)