Exclude the currently active window when visually selecting

This commit is contained in:
Kovid Goyal 2021-10-31 11:37:38 +05:30
parent 8458b9e7d6
commit dc09a5183a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 43 additions and 14 deletions

View File

@ -9,7 +9,8 @@ from contextlib import suppress
from functools import partial
from gettext import gettext as _
from typing import (
Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast
Any, Callable, Container, Dict, Iterable, Iterator, List, Optional, Tuple,
Union, cast
)
from weakref import WeakValueDictionary
@ -859,29 +860,38 @@ class Boss:
self.current_visual_select.cancel()
self.current_visual_select = None
def visual_window_select_action(self, tab: Tab, callback: Callable[[Optional[Tab], Optional[Window]], None], choose_msg: str) -> None:
def visual_window_select_action(
self, tab: Tab,
callback: Callable[[Optional[Tab], Optional[Window]], None],
choose_msg: str,
only_window_ids: Container[int] = ()
) -> None:
self.cancel_current_visual_select()
tm = tab.tab_manager_ref()
if tm is not None:
tm.set_active_tab(tab)
self.current_visual_select = VisualSelect(tab.id, tab.os_window_id, choose_msg, callback)
if tab.current_layout.only_active_window_visible:
self.select_window_in_tab_using_overlay(tab, choose_msg)
self.select_window_in_tab_using_overlay(tab, choose_msg, only_window_ids)
return
pending_sequences: SubSequenceMap = {}
fmap = get_name_to_functional_number_map()
num = 0
for idx, window in tab.windows.iter_windows_with_number(only_visible=True):
if idx > 9:
break
num = idx + 1
if only_window_ids and window.id not in only_window_ids:
continue
ac = KeyAction('visual_window_select_action_trigger', (window.id,))
if num == 10:
num += 1
is_last = num == 10
if is_last:
num = 0
window.screen.set_window_number(num)
self.current_visual_select.window_ids.append(window.id)
for mods in (0, GLFW_MOD_CONTROL, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT, GLFW_MOD_SUPER, GLFW_MOD_ALT, GLFW_MOD_SHIFT):
pending_sequences[(SingleKey(mods=mods, key=ord(str(num))),)] = ac
pending_sequences[(SingleKey(mods=mods, key=fmap[f'KP_{num}']),)] = ac
if is_last:
break
if len(self.current_visual_select.window_ids) > 1:
self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('visual_window_select_action_trigger', (0,)))
redirect_mouse_handling(True)
@ -914,8 +924,9 @@ class Boss:
ev = WindowSystemMouseEvent(in_tab_bar, window_id, action, modifiers, button, currently_pressed_button, x, y)
self.mouse_handler(ev)
def select_window_in_tab_using_overlay(self, tab: Tab, msg: str) -> None:
windows = tuple((w.id, w.title) for i, w in tab.windows.iter_windows_with_number(only_visible=False))
def select_window_in_tab_using_overlay(self, tab: Tab, msg: str, only_window_ids: Container[int] = ()) -> None:
windows = tuple((w.id, w.title) for i, w in tab.windows.iter_windows_with_number(only_visible=False)
if not only_window_ids or w.id in only_window_ids)
if len(windows) < 1:
self.visual_window_select_action_trigger(windows[0][0] if windows else 0)
if get_options().enable_audio_bell:

View File

@ -19,6 +19,7 @@ class SelectWindow(RemoteCommand):
match: The tab to open the new window in
self: Boolean, if True use tab the command was run in
title: A title for this selection
exclude_active: Exclude the currently active window from the list to pick
'''
short_desc = 'Visually select a window in the specified tab'
@ -41,11 +42,16 @@ instead of the active tab.
--title
A title that will be displayed to the user to describe what this selection is for
--exclude-active
type=bool-set
Exclude the currently active window from the list of windows to pick
'''
is_asynchronous = True
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
ans = {'self': opts.self, 'match': opts.match, 'title': opts.title}
ans = {'self': opts.self, 'match': opts.match, 'title': opts.title, 'exclude_active': opts.exclude_active}
return ans
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
@ -58,7 +64,11 @@ A title that will be displayed to the user to describe what this selection is fo
responder.send_error('No window selected')
for tab in self.tabs_for_match_payload(boss, window, payload_get):
if tab:
boss.visual_window_select_action(tab, callback, payload_get('title') or 'Choose window')
if payload_get('exclude_active'):
wids = tab.all_window_ids_except_active_window
else:
wids = set()
boss.visual_window_select_action(tab, callback, payload_get('title') or 'Choose window', only_window_ids=wids)
break
return no_response

View File

@ -11,7 +11,7 @@ from operator import attrgetter
from time import monotonic
from typing import (
Any, Deque, Dict, Generator, Iterable, Iterator, List, NamedTuple,
Optional, Pattern, Sequence, Tuple, Union, cast
Optional, Pattern, Sequence, Set, Tuple, Union, cast
)
from .borders import Border, Borders
@ -596,6 +596,14 @@ class Tab: # {{{
if self.current_layout.move_window_to_group(self.windows, group.id):
self.relayout()
@property
def all_window_ids_except_active_window(self) -> Set[int]:
all_window_ids = {w.id for w in self}
aw = self.active_window
if aw is not None:
all_window_ids.discard(aw.id)
return all_window_ids
@ac('win', '''
Focus a visible window by pressing the number of the window. Window numbers are displayed
over the windows for easy selection in this mode.
@ -605,14 +613,14 @@ class Tab: # {{{
if tab and window:
tab.set_active_window(window)
get_boss().visual_window_select_action(self, callback, 'Choose window to switch to')
get_boss().visual_window_select_action(self, callback, 'Choose window to switch to', only_window_ids=self.all_window_ids_except_active_window)
@ac('win', 'Swap the current window with another window in the current tab, selected visually')
def swap_with_window(self) -> None:
def callback(tab: Optional[Tab], window: Optional[Window]) -> None:
if tab and window:
tab.swap_active_window_with(window.id)
get_boss().visual_window_select_action(self, callback, 'Choose window to swap with')
get_boss().visual_window_select_action(self, callback, 'Choose window to swap with', only_window_ids=self.all_window_ids_except_active_window)
@ac('win', 'Move active window to the top (make it the first window)')
def move_window_to_top(self) -> None: