Remote control: Allow matching by neighbor of active window

This commit is contained in:
Kovid Goyal 2023-08-25 13:48:53 +05:30
parent 1cb4cdbaea
commit f50660bb30
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 28 additions and 2 deletions

View file

@ -59,6 +59,8 @@ Detailed list of changes
- X11: Print an error to :file:`STDERR` instead of refusing to start when the user sets a custom window icon larger than 128x128 (:iss:`6507`)
- Remote control: Allow matching by neighbor of active window. Useful for navigation plugins like vim-kitty-navigator
0.29.2 [2023-07-27]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -489,7 +489,7 @@ def get_matches(location: str, query: str, candidates: Set[int]) -> Set[int]:
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', 'var', 'recent', 'state'
'id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'var', 'recent', 'state', 'neighbor',
), set(self.window_id_map), get_matches):
yield self.window_id_map[wid]

View file

@ -83,7 +83,7 @@ def __call__(self, key: str, opt_name: Optional[str] = None, missing: Any = None
--match -m
The window to match. Match specifications are of the form: :italic:`field:query`.
Where :italic:`field` can be one of: :code:`id`, :code:`title`, :code:`pid`, :code:`cwd`, :code:`cmdline`, :code:`num`,
:code:`env`, :code:`var`, :code:`state`, and :code:`recent`.
:code:`env`, :code:`var`, :code:`state`, :code:`neighbor`, and :code:`recent`.
:italic:`query` is the expression to match. Expressions can be either a number or a regular expression, and can be
:ref:`combined using Boolean operators <search_syntax>`.
@ -101,6 +101,9 @@ def __call__(self, key: str, opt_name: Optional[str] = None, missing: Any = None
The field :code:`recent` refers to recently active windows in the currently active tab, with zero being the currently
active window, one being the previously active window and so on.
The field :code:`neighbor` refers to a neighbor of the active window in the specified direction, which can be:
:code:`left`, :code:`right`, :code:`top` or :code:`bottom`.
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`.

View file

@ -755,6 +755,21 @@ def matches_query(self, field: str, query: str, active_tab: Optional[TabType] =
if query == 'overlay_parent':
return self_window is not None and self is self_window.overlay_parent
return False
if field == 'neighbor':
t = get_boss().active_tab
if t is None:
return False
gid: Optional[int] = None
if query == 'left':
gid = t.neighboring_group_id("left")
elif query == 'right':
gid = t.neighboring_group_id("right")
elif query == 'top':
gid = t.neighboring_group_id("top")
elif query == 'bottom':
gid = t.neighboring_group_id("bottom")
return gid is not None and t.windows.active_window_in_group_id(gid) is self
pat = compile_match_query(query, field not in ('env', 'var'))
return self.matches(field, pat)

View file

@ -395,6 +395,12 @@ def active_window_in_nth_group(self, n: int, clamp: bool = False) -> Optional[Wi
return self.id_map.get(self.groups[n].active_window_id)
return None
def active_window_in_group_id(self, group_id: int) -> Optional[WindowType]:
for g in self.groups:
if g.id == group_id:
return self.id_map.get(g.active_window_id)
return None
def activate_next_window_group(self, delta: int) -> None:
self.set_active_group_idx(wrap_increment(self.active_group_idx, self.num_groups, delta))