Remote control: Allow matching the parent of an overlay window

This commit is contained in:
Kovid Goyal 2022-12-30 11:29:05 +05:30
parent 080d1bf935
commit c18bff7821
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 34 additions and 8 deletions

View File

@ -370,7 +370,7 @@ class Boss:
for tab in self.all_tabs: for tab in self.all_tabs:
yield from tab 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': if match == 'all':
yield from self.all_windows yield from self.all_windows
return return
@ -390,7 +390,7 @@ class Boss:
return set() return set()
if q < 0: if q < 0:
query = str(window_id_limit + q) 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, ( for wid in search(match, (
'id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'recent', 'state' 'id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'recent', 'state'

View File

@ -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 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`. 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: The field :code:`state` matches on the state of the window. Supported states
:code:`active`, :code:`focused`, :code:`needs_attention`, :code:`parent_active` and :code:`parent_focused`. are: :code:`active`, :code:`focused`, :code:`needs_attention`,
Active windows are the windows that are active in their parent tab. There is only one focused window and it is the :code:`parent_active`, :code:`parent_focused`, :code:`self`,
window to which keyboard events are delivered. If no window is focused, the last focused window is matched. :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 <at-ls>` command to get a list of windows. Note that you can use the :ref:`kitty @ ls <at-ls>` command to get a list of windows.
''' '''
@ -341,13 +347,14 @@ class RemoteCommand:
if payload_get('all'): if payload_get('all'):
windows = list(boss.all_windows) windows = list(boss.all_windows)
else: else:
self_window = window
if payload_get('self') in (None, True): if payload_get('self') in (None, True):
window = window or boss.active_window window = window or boss.active_window
else: else:
window = boss.active_window or window window = boss.active_window or window
windows = [window] if window else [] windows = [window] if window else []
if payload_get('match'): 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: if not windows:
raise MatchError(payload_get('match')) raise MatchError(payload_get('match'))
return windows return windows

View File

@ -496,6 +496,14 @@ class Tab: # {{{
def move_window_to_top_of_group(self, window: Window) -> bool: def move_window_to_top_of_group(self, window: Window) -> bool:
return self.windows.move_window_to_top_of_group(window) 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: def remove_window(self, window: Window, destroy: bool = True) -> None:
self.windows.remove_window(window) self.windows.remove_window(window)
if destroy: if destroy:

View File

@ -652,6 +652,13 @@ class Window:
ans['overlay_type'] = self.overlay_type.value ans['overlay_type'] = self.overlay_type.value
return ans return ans
@property
def overlay_parent(self) -> Optional['Window']:
tab = self.tabref()
if tab is None:
return None
return tab.overlay_parent(self)
@property @property
def current_colors(self) -> Dict[str, Optional[int]]: def current_colors(self) -> Dict[str, Optional[int]]:
return self.screen.color_profile.as_dict() return self.screen.color_profile.as_dict()
@ -692,7 +699,7 @@ class Window:
return False return False
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 field in ('num', 'recent'):
if active_tab is not None: if active_tab is not None:
try: try:
@ -720,6 +727,10 @@ class Window:
return False return False
if query == 'parent_focused': 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 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 return False
pat = compile_match_query(query, field != 'env') pat = compile_match_query(query, field != 'env')
return self.matches(field, pat) return self.matches(field, pat)