mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-28 12:21:55 +00:00
Remote control: @ action: Fix some actions being performed on the active window instead of the matched window
Fixes #7438
This commit is contained in:
parent
4e3f643cf5
commit
eb2221b11a
2 changed files with 97 additions and 50 deletions
|
|
@ -88,6 +88,8 @@ Detailed list of changes
|
|||
|
||||
- Mouse reporting: Fix horizontal scroll events inverted (:iss:`7439`)
|
||||
|
||||
- Remote control: @ action: Fix some actions being performed on the active window instead of the matched window (:iss:`7438`)
|
||||
|
||||
0.34.1 [2024-04-19]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
145
kitty/boss.py
145
kitty/boss.py
|
|
@ -332,6 +332,7 @@ class Boss:
|
|||
):
|
||||
set_layout_options(opts)
|
||||
self.clipboard = Clipboard()
|
||||
self.window_for_dispatch: Optional[Window] = None
|
||||
self.primary_selection = Clipboard(ClipboardType.primary_selection)
|
||||
self.update_check_started = False
|
||||
self.peer_data_map: Dict[int, Optional[Dict[str, Sequence[str]]]] = {}
|
||||
|
|
@ -573,7 +574,7 @@ class Boss:
|
|||
|
||||
@ac('win', 'New OS Window with the same working directory as the currently active window')
|
||||
def new_os_window_with_cwd(self, *args: str) -> None:
|
||||
w = self.active_window_for_cwd
|
||||
w = self.window_for_dispatch or self.active_window_for_cwd
|
||||
self._new_os_window(args, CwdRequest(w))
|
||||
|
||||
def new_os_window_with_wd(self, wd: Union[str, List[str]], str_is_multiple_paths: bool = False) -> None:
|
||||
|
|
@ -722,7 +723,7 @@ class Boss:
|
|||
''')
|
||||
def remote_control(self, *args: str) -> None:
|
||||
try:
|
||||
self.call_remote_control(self.active_window, args)
|
||||
self.call_remote_control(self.window_for_dispatch or self.active_window, args)
|
||||
except (Exception, SystemExit) as e:
|
||||
import shlex
|
||||
self.show_error(_('remote_control mapping failed'), shlex.join(args) + '\n' + str(e))
|
||||
|
|
@ -921,7 +922,7 @@ class Boss:
|
|||
|
||||
@ac('win', 'Close the currently active window')
|
||||
def close_window(self) -> None:
|
||||
self.mark_window_for_close()
|
||||
self.mark_window_for_close(self.window_for_dispatch)
|
||||
|
||||
@ac('win', '''
|
||||
Close window with confirmation
|
||||
|
|
@ -933,7 +934,7 @@ class Boss:
|
|||
map f1 close_window_with_confirmation ignore-shell
|
||||
''')
|
||||
def close_window_with_confirmation(self, ignore_shell: bool = False) -> None:
|
||||
window = self.active_window
|
||||
window = self.window_for_dispatch or self.active_window
|
||||
if window is None:
|
||||
return
|
||||
if not ignore_shell or window.has_running_program:
|
||||
|
|
@ -952,13 +953,24 @@ class Boss:
|
|||
|
||||
@ac('tab', 'Close the current tab')
|
||||
def close_tab(self, tab: Optional[Tab] = None) -> None:
|
||||
if tab is None and self.window_for_dispatch:
|
||||
tab = self.window_for_dispatch.tabref()
|
||||
tab = tab or self.active_tab
|
||||
if tab:
|
||||
self.confirm_tab_close(tab)
|
||||
|
||||
@property
|
||||
def active_tab_manager_with_dispatch(self) -> Optional[TabManager]:
|
||||
if self.window_for_dispatch:
|
||||
td = self.window_for_dispatch.tabref()
|
||||
tm = td.tab_manager_ref() if td else None
|
||||
else:
|
||||
tm = self.active_tab_manager
|
||||
return tm
|
||||
|
||||
@ac('tab', 'Close all the tabs in the current OS window other than the currently active tab')
|
||||
def close_other_tabs_in_os_window(self) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None and len(tm.tabs) > 1:
|
||||
active_tab = self.active_tab
|
||||
for tab in tm:
|
||||
|
|
@ -967,7 +979,7 @@ class Boss:
|
|||
|
||||
@ac('win', 'Close all other OS Windows other than the OS Window containing the currently active window')
|
||||
def close_other_os_windows(self) -> None:
|
||||
active = self.active_tab_manager
|
||||
active = self.active_tab_manager_with_dispatch
|
||||
if active is not None:
|
||||
for x in self.os_window_map.values():
|
||||
if x is not active:
|
||||
|
|
@ -1121,10 +1133,18 @@ class Boss:
|
|||
|
||||
@ac('win', 'Toggle the fullscreen status of the active OS Window')
|
||||
def toggle_fullscreen(self, os_window_id: int = 0) -> None:
|
||||
if os_window_id == 0:
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm:
|
||||
os_window_id = tm.os_window_id
|
||||
toggle_fullscreen(os_window_id)
|
||||
|
||||
@ac('win', 'Toggle the maximized status of the active OS Window')
|
||||
def toggle_maximized(self, os_window_id: int = 0) -> None:
|
||||
if os_window_id == 0:
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm:
|
||||
os_window_id = tm.os_window_id
|
||||
toggle_maximized(os_window_id)
|
||||
|
||||
@ac('misc', 'Toggle macOS secure keyboard entry')
|
||||
|
|
@ -1141,7 +1161,13 @@ class Boss:
|
|||
|
||||
@ac('misc', 'Minimize macOS window')
|
||||
def minimize_macos_window(self) -> None:
|
||||
osw_id = current_os_window()
|
||||
osw_id = None
|
||||
if self.window_for_dispatch:
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm:
|
||||
osw_id = tm.os_window_id
|
||||
else:
|
||||
osw_id = current_os_window()
|
||||
if osw_id is not None:
|
||||
cocoa_minimize_os_window(osw_id)
|
||||
|
||||
|
|
@ -1200,7 +1226,7 @@ class Boss:
|
|||
def clear_terminal(self, action: str, only_active: bool) -> None:
|
||||
if only_active:
|
||||
windows = []
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is not None:
|
||||
windows.append(w)
|
||||
else:
|
||||
|
|
@ -1266,7 +1292,7 @@ class Boss:
|
|||
os_windows = list(self.os_window_map.keys())
|
||||
else:
|
||||
os_windows = []
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is not None:
|
||||
os_windows.append(w.os_window_id)
|
||||
if os_windows:
|
||||
|
|
@ -1311,7 +1337,7 @@ class Boss:
|
|||
map f3 set_background_opacity 0.5
|
||||
''')
|
||||
def set_background_opacity(self, opacity: str) -> None:
|
||||
window = self.active_window
|
||||
window = self.window_for_dispatch or self.active_window
|
||||
if window is None or not opacity:
|
||||
return
|
||||
if not get_options().dynamic_background_opacity:
|
||||
|
|
@ -1480,7 +1506,7 @@ class Boss:
|
|||
See :ref:`window_resizing` for details.
|
||||
''')
|
||||
def start_resizing_window(self) -> None:
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is None:
|
||||
return
|
||||
overlay_window = self.run_kitten_with_metadata('resize_window', args=[
|
||||
|
|
@ -1544,10 +1570,14 @@ class Boss:
|
|||
if key_action is not None:
|
||||
f = getattr(self, key_action.func, None)
|
||||
if f is not None:
|
||||
report_match(f)
|
||||
passthrough = f(*key_action.args)
|
||||
if passthrough is not True:
|
||||
return True
|
||||
orig, self.window_for_dispatch = self.window_for_dispatch, window_for_dispatch
|
||||
try:
|
||||
report_match(f)
|
||||
passthrough = f(*key_action.args)
|
||||
if passthrough is not True:
|
||||
return True
|
||||
finally:
|
||||
self.window_for_dispatch = orig
|
||||
if window_for_dispatch is None:
|
||||
tab = self.active_tab
|
||||
window = self.active_window
|
||||
|
|
@ -1676,7 +1706,7 @@ class Boss:
|
|||
|
||||
@ac('win', 'Close the currently active OS Window')
|
||||
def close_os_window(self) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None:
|
||||
self.confirm_os_window_close(tm.os_window_id)
|
||||
|
||||
|
|
@ -1931,7 +1961,7 @@ class Boss:
|
|||
|
||||
@ac('misc', 'Run the specified kitten. See :doc:`/kittens/custom` for details')
|
||||
def kitten(self, kitten: str, *kargs: str) -> None:
|
||||
self.run_kitten_with_metadata(kitten, kargs)
|
||||
self.run_kitten_with_metadata(kitten, kargs, window=self.window_for_dispatch)
|
||||
|
||||
def run_kitten(self, kitten: str, *args: str) -> None:
|
||||
self.run_kitten_with_metadata(kitten, args)
|
||||
|
|
@ -1949,7 +1979,7 @@ class Boss:
|
|||
|
||||
@ac('misc', 'Input an arbitrary unicode character. See :doc:`/kittens/unicode_input` for details.')
|
||||
def input_unicode_character(self) -> None:
|
||||
self.run_kitten_with_metadata('unicode_input')
|
||||
self.run_kitten_with_metadata('unicode_input', window=self.window_for_dispatch)
|
||||
|
||||
@ac(
|
||||
'tab', '''
|
||||
|
|
@ -1969,7 +1999,7 @@ class Boss:
|
|||
'''
|
||||
)
|
||||
def set_tab_title(self, title: Optional[str] = None) -> None:
|
||||
tab = self.active_tab
|
||||
tab = self.window_for_dispatch.tabref() if self.window_for_dispatch else self.active_tab
|
||||
if tab:
|
||||
if title is not None and title not in ('" "', "' '"):
|
||||
if title in ('""', "''"):
|
||||
|
|
@ -2002,14 +2032,15 @@ class Boss:
|
|||
|
||||
@ac('misc', 'Show an error message with the specified title and text')
|
||||
def show_error(self, title: str, msg: str) -> None:
|
||||
tab = self.active_tab
|
||||
w = self.active_window
|
||||
if w is not None and tab is not None:
|
||||
tab.new_special_window(self.create_special_window_for_show_error(title, msg, w.id), copy_colors_from=w)
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w:
|
||||
tab = w.tabref()
|
||||
if w is not None and tab is not None:
|
||||
tab.new_special_window(self.create_special_window_for_show_error(title, msg, w.id), copy_colors_from=w)
|
||||
|
||||
@ac('mk', 'Create a new marker')
|
||||
def create_marker(self) -> None:
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w:
|
||||
spec = None
|
||||
|
||||
|
|
@ -2035,7 +2066,7 @@ class Boss:
|
|||
def kitty_shell(self, window_type: str = 'window') -> None:
|
||||
kw: Dict[str, Any] = {}
|
||||
cmd = [kitty_exe(), '@']
|
||||
aw = self.active_window
|
||||
aw = self.window_for_dispatch or self.active_window
|
||||
if aw is not None:
|
||||
env = {'KITTY_SHELL_ACTIVE_WINDOW_ID': str(aw.id)}
|
||||
at = self.active_tab
|
||||
|
|
@ -2110,7 +2141,7 @@ class Boss:
|
|||
|
||||
@ac('misc', 'Click a URL using the keyboard')
|
||||
def open_url_with_hints(self) -> None:
|
||||
self.run_kitten_with_metadata('hints')
|
||||
self.run_kitten_with_metadata('hints', window=self.window_for_dispatch)
|
||||
|
||||
def drain_actions(self, actions: List[KeyAction], window_for_dispatch: Optional[Window] = None, dispatch_type: str = 'KeyPress') -> None:
|
||||
|
||||
|
|
@ -2140,7 +2171,10 @@ class Boss:
|
|||
@ac('cp', 'Paste from the clipboard to the active window')
|
||||
def paste_from_clipboard(self) -> None:
|
||||
text = get_clipboard_string()
|
||||
self.paste_to_active_window(text)
|
||||
if text:
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is not None:
|
||||
w.paste_with_actions(text)
|
||||
|
||||
def current_primary_selection(self) -> str:
|
||||
return get_primary_selection() if supports_primary_selection else ''
|
||||
|
|
@ -2151,7 +2185,10 @@ class Boss:
|
|||
@ac('cp', 'Paste from the primary selection, if present, otherwise the clipboard to the active window')
|
||||
def paste_from_selection(self) -> None:
|
||||
text = self.current_primary_selection_or_clipboard()
|
||||
self.paste_to_active_window(text)
|
||||
if text:
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is not None:
|
||||
w.paste_with_actions(text)
|
||||
|
||||
def set_primary_selection(self) -> None:
|
||||
w = self.active_window
|
||||
|
|
@ -2190,7 +2227,7 @@ class Boss:
|
|||
See :ref:`cpbuf` for details.
|
||||
''')
|
||||
def copy_to_buffer(self, buffer_name: str) -> None:
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is not None and not w.destroyed:
|
||||
text = w.text_for_selection()
|
||||
if text:
|
||||
|
|
@ -2214,7 +2251,9 @@ class Boss:
|
|||
else:
|
||||
text = self.get_clipboard_buffer(buffer_name)
|
||||
if text:
|
||||
self.paste_to_active_window(text)
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w:
|
||||
w.paste_with_actions(text)
|
||||
|
||||
@ac('tab', '''
|
||||
Go to the specified tab, by number, starting with 1
|
||||
|
|
@ -2224,7 +2263,7 @@ class Boss:
|
|||
to go to.
|
||||
''')
|
||||
def goto_tab(self, tab_num: int) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None:
|
||||
tm.goto_tab(tab_num - 1)
|
||||
|
||||
|
|
@ -2236,13 +2275,13 @@ class Boss:
|
|||
|
||||
@ac('tab', 'Make the next tab active')
|
||||
def next_tab(self) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None:
|
||||
tm.next_tab()
|
||||
|
||||
@ac('tab', 'Make the previous tab active')
|
||||
def previous_tab(self) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None:
|
||||
tm.next_tab(-1)
|
||||
|
||||
|
|
@ -2477,7 +2516,7 @@ class Boss:
|
|||
|
||||
@ac('tab', 'Create a new tab with working directory for the window in it set to the same as the active window')
|
||||
def new_tab_with_cwd(self, *args: str) -> None:
|
||||
self._create_tab(list(args), cwd_from=CwdRequest(self.active_window_for_cwd))
|
||||
self._create_tab(list(args), cwd_from=CwdRequest(self.window_for_dispatch or self.active_window_for_cwd))
|
||||
|
||||
def new_tab_with_wd(self, wd: Union[str, List[str]], str_is_multiple_paths: bool = False) -> None:
|
||||
if isinstance(wd, str):
|
||||
|
|
@ -2516,7 +2555,7 @@ class Boss:
|
|||
|
||||
@ac('win', 'Create a new window with working directory same as that of the active window')
|
||||
def new_window_with_cwd(self, *args: str) -> None:
|
||||
w = self.active_window_for_cwd
|
||||
w = self.window_for_dispatch or self.active_window_for_cwd
|
||||
if w is None:
|
||||
return self.new_window(*args)
|
||||
self._new_window(list(args), cwd_from=CwdRequest(w))
|
||||
|
|
@ -2529,7 +2568,7 @@ class Boss:
|
|||
def launch(self, *args: str) -> None:
|
||||
from kitty.launch import launch, parse_launch_args
|
||||
opts, args_ = parse_launch_args(args)
|
||||
launch(self, opts, args_)
|
||||
launch(self, opts, args_, active=self.window_for_dispatch)
|
||||
|
||||
@ac('tab', 'Move the active tab forward')
|
||||
def move_tab_forward(self) -> None:
|
||||
|
|
@ -2539,7 +2578,7 @@ class Boss:
|
|||
|
||||
@ac('tab', 'Move the active tab backward')
|
||||
def move_tab_backward(self) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None:
|
||||
tm.move_tab(-1)
|
||||
|
||||
|
|
@ -2549,16 +2588,19 @@ class Boss:
|
|||
See :opt:`disable_ligatures` for details
|
||||
''')
|
||||
def disable_ligatures_in(self, where: Union[str, Iterable[Window]], strategy: int) -> None:
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if isinstance(where, str):
|
||||
windows: List[Window] = []
|
||||
if where == 'active':
|
||||
if self.active_window is not None:
|
||||
windows = [self.active_window]
|
||||
if w:
|
||||
windows = [w]
|
||||
elif where == 'all':
|
||||
windows = list(self.all_windows)
|
||||
elif where == 'tab':
|
||||
if self.active_tab is not None:
|
||||
windows = list(self.active_tab)
|
||||
if w:
|
||||
tab = w.tabref()
|
||||
if tab:
|
||||
windows = list(tab)
|
||||
else:
|
||||
windows = list(where)
|
||||
for window in windows:
|
||||
|
|
@ -2741,7 +2783,7 @@ class Boss:
|
|||
except (Exception, SystemExit) as err:
|
||||
self.show_error('Failed to set colors', str(err))
|
||||
return
|
||||
c.response_from_kitty(self, self.active_window, PayloadGetter(c, payload if isinstance(payload, dict) else {}))
|
||||
c.response_from_kitty(self, self.window_for_dispatch or self.active_window, PayloadGetter(c, payload if isinstance(payload, dict) else {}))
|
||||
|
||||
def _move_window_to(
|
||||
self,
|
||||
|
|
@ -2847,7 +2889,8 @@ class Boss:
|
|||
w = 'windows' if tab.num_window_groups > 1 else 'window'
|
||||
return f'{tab.name or tab.title} [{tab.num_window_groups} {w}]'
|
||||
|
||||
ct = self.active_tab
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
ct = w.tabref() if w else None
|
||||
self.choose_entry(
|
||||
'Choose a tab to switch to',
|
||||
((None, f'Current tab: {format_tab_title(t)}') if t is ct else (t.id, format_tab_title(t)) for t in self.all_tabs),
|
||||
|
|
@ -2872,11 +2915,12 @@ class Boss:
|
|||
else:
|
||||
where = args[0][4:]
|
||||
return self._move_window_to(target_tab_id=where)
|
||||
ct = self.active_tab
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
ct = w.tabref() if w else None
|
||||
items: List[Tuple[Union[str, int], str]] = [(t.id, t.effective_title) for t in self.all_tabs if t is not ct]
|
||||
items.append(('new_tab', 'New tab'))
|
||||
items.append(('new_os_window', 'New OS Window'))
|
||||
target_window = self.active_window
|
||||
target_window = w
|
||||
|
||||
def chosen(ans: Union[None, str, int]) -> None:
|
||||
if ans is not None:
|
||||
|
|
@ -2900,12 +2944,13 @@ class Boss:
|
|||
return self._move_tab_to()
|
||||
|
||||
items: List[Tuple[Union[str, int], str]] = []
|
||||
ct = self.active_tab_manager
|
||||
ct = self.active_tab_manager_with_dispatch
|
||||
for osw_id, tm in self.os_window_map.items():
|
||||
if tm is not ct and tm.active_tab:
|
||||
items.append((osw_id, tm.active_tab.title))
|
||||
items.append(('new', 'New OS Window'))
|
||||
target_tab = self.active_tab
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
target_tab = w.tabref() if w else None
|
||||
|
||||
def chosen(ans: Union[None, int, str]) -> None:
|
||||
if ans is not None:
|
||||
|
|
@ -2937,7 +2982,7 @@ class Boss:
|
|||
|
||||
@ac('debug', 'Show the environment variables that the kitty process sees')
|
||||
def show_kitty_env_vars(self) -> None:
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
env = os.environ.copy()
|
||||
if is_macos and env.get('LC_CTYPE') == 'UTF-8' and not getattr(sys, 'kitty_run_data').get('lc_ctype_before_python'):
|
||||
del env['LC_CTYPE']
|
||||
|
|
@ -2999,7 +3044,7 @@ class Boss:
|
|||
@ac('debug', 'Show the effective configuration kitty is running with')
|
||||
def debug_config(self) -> None:
|
||||
from .debug_config import debug_config
|
||||
w = self.active_window
|
||||
w = self.window_for_dispatch or self.active_window
|
||||
if w is not None:
|
||||
output = debug_config(get_options())
|
||||
set_clipboard_string(re.sub(r'\x1b.+?m', '', output))
|
||||
|
|
@ -3029,6 +3074,6 @@ class Boss:
|
|||
map f1 toggle_tab title:mytab
|
||||
''')
|
||||
def toggle_tab(self, match_expression: str) -> None:
|
||||
tm = self.active_tab_manager
|
||||
tm = self.active_tab_manager_with_dispatch
|
||||
if tm is not None:
|
||||
tm.toggle_tab(match_expression)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue