Allow matching on window/tab state

This commit is contained in:
Kovid Goyal 2022-04-12 20:14:01 +05:30
parent ade38870a0
commit b3fa7310cb
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 41 additions and 13 deletions

View File

@ -346,7 +346,9 @@ class Boss:
def get_matches(location: str, query: str, candidates: Set[int]) -> Set[int]: 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)} return {wid for wid in candidates if self.window_id_map[wid].matches_query(location, query, tab)}
for wid in search(match, ('id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'recent',), set(self.window_id_map), get_matches): for wid in search(match, (
'id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'recent', 'state'
), set(self.window_id_map), get_matches):
yield self.window_id_map[wid] yield self.window_id_map[wid]
def tab_for_window(self, window: Window) -> Optional[Tab]: def tab_for_window(self, window: Window) -> Optional[Tab]:
@ -365,7 +367,9 @@ class Boss:
return {wid for wid in candidates if tim[wid].matches_query(location, query, tm)} return {wid for wid in candidates if tim[wid].matches_query(location, query, tm)}
found = False found = False
for tid in search(match, ('id', 'index', 'title', 'window_id', 'window_title', 'pid', 'cwd', 'env', 'cmdline', 'recent',), set(tim), get_matches): for tid in search(match, (
'id', 'index', 'title', 'window_id', 'window_title', 'pid', 'cwd', 'env', 'cmdline', 'recent', 'state'
), set(tim), get_matches):
found = True found = True
yield tim[tid] yield tim[tid]

View File

@ -76,18 +76,21 @@ ArgsType = List[str]
MATCH_WINDOW_OPTION = '''\ MATCH_WINDOW_OPTION = '''\
--match -m --match -m
The window to match. Match specifications are of the form: The window to match. Match specifications are of the form:
:italic:`field:regexp`. Where field can be one of: id, title, pid, cwd, cmdline, num, env and recent. :italic:`field:regexp`. Where field can be one of: id, title, pid, cwd, cmdline, num, env, state and recent.
You can use the :italic:`ls` command to get a list of windows. Expressions can You can use the :italic:`ls` command to get a list of windows. Expressions can
be :ref:`combined using Boolean operators <search_syntax>`. Note that for be :ref:`combined using Boolean operators <search_syntax>`. Note that for
numeric fields such as id, pid, recent and num the expression is interpreted as a number, numeric fields such as :code:`id`, :code:`pid`, :code:`recent` and :code:`num` the expression is interpreted as a number,
not a regular expression. The field num refers to the window position in the current tab, not a regular expression. The field :code:`num` refers to the window position in the current tab,
starting from zero and counting clockwise (this is the same as the order in which the starting from zero and counting clockwise (this is the same as the order in which the
windows are reported by the :italic:`ls` command). The window id of the current window windows are reported by the :italic:`ls` command). The window id of the current window
is available as the KITTY_WINDOW_ID environment variable. The field recent refers to recently is available as the KITTY_WINDOW_ID environment variable. 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 active windows in the currently active tab, with zero being the currently active window, one being the previously active
window and so on. When using the :italic:`env` field window and so on. When using the :italic:`env` field
to match on environment variables you can specify only the environment variable name or a name to match on environment variables you can specify only the environment variable name or a name
and value, for example, :italic:`env:MY_ENV_VAR=2` and value, for example, :italic:`env:MY_ENV_VAR=2`. The field :code:`state` matches
on the state of the window. Supported states are: :code:`active`, :code:`focused` and :code:`needs_attention`.
Active windows are windows that are the active window in their parent tab. There is only one focused window
and it is the window to which keyboard events are delivered.
''' '''
MATCH_TAB_OPTION = '''\ MATCH_TAB_OPTION = '''\
--match -m --match -m
@ -103,7 +106,10 @@ for that window is used. You can also use window_id and window_title to match
the tab that contains the window with the specified id or title. The index number the tab that contains the window with the specified id or title. The index number
is used to match the nth tab in the currently active OS window. The recent number is used to match the nth tab in the currently active OS window. The recent number
matches recently active tabs in the currently active OS window, with zero being the currently matches recently active tabs in the currently active OS window, with zero being the currently
active tab, one the previously active tab and so on. active tab, one the previously active tab and so on. The field :code:`state` matches
on the state of the tab. Supported states are: :code:`active`, :code:`focused` and :code:`needs_attention`.
Active tabs are tabs that are the active tab in their parent OS Window. There is only one focused tab
and it is the tab to which keyboard events are delivered.
''' '''

View File

@ -20,10 +20,10 @@ from .cli_stub import CLIOptions
from .constants import appname, kitty_exe from .constants import appname, kitty_exe
from .fast_data_types import ( from .fast_data_types import (
GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE,
add_tab, attach_window, detach_window, get_boss, get_click_interval, add_tab, attach_window, current_os_window, detach_window, get_boss,
get_options, mark_tab_bar_dirty, next_window_id, remove_tab, remove_window, get_click_interval, get_options, mark_tab_bar_dirty, next_window_id,
ring_bell, set_active_tab, set_active_window, swap_tabs, remove_tab, remove_window, ring_bell, set_active_tab, set_active_window,
sync_os_window_title swap_tabs, sync_os_window_title
) )
from .layout.base import Layout from .layout.base import Layout
from .layout.interface import create_layout_object_for, evict_cached_layouts from .layout.interface import create_layout_object_for, evict_cached_layouts
@ -708,6 +708,16 @@ class Tab: # {{{
if active_tab_manager and len(active_tab_manager.tabs): if active_tab_manager and len(active_tab_manager.tabs):
return self is active_tab_manager.nth_active_tab(int(query)) return self is active_tab_manager.nth_active_tab(int(query))
return False return False
if field == 'state':
if query == 'active':
return active_tab_manager is not None and self is active_tab_manager.active_tab
if query == 'focused':
return active_tab_manager is not None and self is active_tab_manager.active_tab and self.os_window_id == current_os_window()
if query == 'needs_attention':
for w in self:
if w.needs_attention:
return True
return False
return False return False
def __iter__(self) -> Iterator[Window]: def __iter__(self) -> Iterator[Window]:

View File

@ -660,7 +660,15 @@ class Window:
if field == 'num': if field == 'num':
return active_tab.get_nth_window(q) is self return active_tab.get_nth_window(q) is self
return active_tab.nth_active_window_id(q) == self.id return active_tab.nth_active_window_id(q) == self.id
return False return False
if field == 'state':
if query == 'active':
return active_tab is not None and self is active_tab.active_window
if query == 'focused':
return active_tab is not None and self is active_tab.active_window and current_os_window() == self.os_window_id
if query == 'needs_attention':
return self.needs_attention
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)