Matching windows/tabs: allow matching by recency

``recent:0`` matches the active window/tab, ``recent:1`` matches the
previous window/tab and so on
This commit is contained in:
Kovid Goyal
2021-08-16 18:29:06 +05:30
parent c00e945f6e
commit 4333552523
4 changed files with 48 additions and 6 deletions

View File

@@ -267,6 +267,17 @@ class Boss:
if w is not None:
yield w
return
if field == 'recent':
tab = self.active_tab
if tab is not None:
try:
num = int(exp)
except Exception:
return
w = self.window_id_map.get(tab.nth_active_window_id(num))
if w is not None:
yield w
return
if field != 'env':
pat: MatchPatternType = re.compile(exp)
else:
@@ -310,6 +321,17 @@ class Boss:
idx = (int(pat.pattern) + len(tm.tabs)) % len(tm.tabs)
found = True
yield tm.tabs[idx]
elif field == 'recent':
tm = self.active_tab_manager
if tm is not None and len(tm.tabs) > 0:
try:
num = int(exp)
except Exception:
return
q = tm.nth_active_tab(num)
if q is not None:
found = True
yield q
if not found:
tabs = {self.tab_for_window(w) for w in self.match_windows(match)}
for q in tabs:

View File

@@ -76,13 +76,15 @@ ArgsType = List[str]
MATCH_WINDOW_OPTION = '''\
--match -m
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.
:italic:`field:regexp`. Where field can be one of: id, title, pid, cwd, cmdline, num, env and recent.
You can use the :italic:`ls` command to get a list of windows. Note that for
numeric fields such as id, pid and num the expression is interpreted as a number,
numeric fields such as id, pid, recent and num the expression is interpreted as a number,
not a regular expression. The field 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
windows are reported by the :italic:`ls` command). The window id of the current window
is available as the KITTY_WINDOW_ID environment variable. When using the :italic:`env` field
is available as the KITTY_WINDOW_ID environment variable. The field 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. When using the :italic:`env` field
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`
'''
@@ -90,14 +92,16 @@ MATCH_TAB_OPTION = '''\
--match -m
The tab to match. Match specifications are of the form:
:italic:`field:regexp`. Where field can be one of:
id, index, title, window_id, window_title, pid, cwd, env, cmdline.
id, index, title, window_id, window_title, pid, cwd, env, cmdline and recent.
You can use the :italic:`ls` command to get a list of tabs. Note that for
numeric fields such as id, index and pid the expression is interpreted as a number,
numeric fields such as id, recent, index and pid the expression is interpreted as a number,
not a regular expression. When using title or id, first a matching tab is
looked for and if not found a matching window is looked for, and the tab
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
is used to match the nth tab in the currently active OS window.
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
active tab, one the previously active tab and so on.
'''

View File

@@ -511,6 +511,12 @@ class Tab: # {{{
if groups:
return groups[0]
def nth_active_window_id(self, n: int = 0) -> int:
if n <= 0:
return self.active_window.id if self.active_window else 0
ids = tuple(reversed(self.windows.active_window_history))
return ids[min(n - 1, len(ids) - 1)] if ids else 0
def neighboring_group_id(self, which: EdgeLiteral) -> Optional[int]:
neighbors = self.current_layout.neighbors(self.windows)
candidates = neighbors.get(which)
@@ -748,6 +754,12 @@ class TabManager: # {{{
self.set_active_tab_idx(idx)
break
def nth_active_tab(self, n: int = 0) -> Optional[Tab]:
if n <= 0:
return self.active_tab
tab_ids = tuple(reversed(self.active_tab_history))
return self.tab_for_id(tab_ids[min(n - 1, len(tab_ids) - 1)]) if tab_ids else None
def __iter__(self) -> Iterator[Tab]:
return iter(self.tabs)