Clean up code for matching windows/tabs in rc

This commit is contained in:
Kovid Goyal
2020-03-13 21:01:10 +05:30
parent 60995ff04b
commit 626a96e20f
28 changed files with 177 additions and 247 deletions

View File

@@ -0,0 +1 @@

View File

@@ -15,9 +15,10 @@ from kitty.constants import appname, running_in_kitty
if TYPE_CHECKING: if TYPE_CHECKING:
from kitty.boss import Boss from kitty.boss import Boss
from kitty.window import Window from kitty.window import Window
Boss, Window from kitty.tabs import Tab
Boss, Window, Tab
else: else:
Boss = Window = None Boss = Window = Tab = None
class NoResponse: class NoResponse:
@@ -90,24 +91,6 @@ for that window is used.
''' '''
def windows_for_payload(boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> Tuple['Window', ...]:
if payload_get('all'):
windows = tuple(boss.all_windows)
else:
windows = (window or boss.active_window,)
if payload_get('match_window'):
windows = tuple(boss.match_windows(payload_get('match_window')))
if not windows:
raise MatchError(payload_get('match_window'))
if payload_get('match_tab'):
tabs = tuple(boss.match_tabs(payload_get('match_tab')))
if not tabs:
raise MatchError(payload_get('match_tab'), 'tabs')
for tab in tabs:
windows += tuple(tab)
return windows
class RemoteCommand: class RemoteCommand:
name: str = '' name: str = ''
@@ -139,10 +122,61 @@ class RemoteCommand:
return self.defaults.get(name, missing) return self.defaults.get(name, missing)
return missing return missing
def windows_for_match_payload(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> List['Window']:
if payload_get('all'):
windows = list(boss.all_windows)
else:
if payload_get('self') in (None, True):
window = window or boss.active_window
else:
window = boss.active_window or window
windows = [window] if window else []
if payload_get('match'):
windows = list(boss.match_windows(payload_get('match')))
if not windows:
raise MatchError(payload_get('match'))
return windows
def tabs_for_match_payload(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> List['Tab']:
if payload_get('all'):
return list(boss.all_tabs)
match = payload_get('match')
if match:
tabs = list(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
return tabs
if window and payload_get('self') in (None, True):
q = boss.tab_for_window(window)
if q:
return [q]
t = boss.active_tab
if t:
return [t]
return []
def windows_for_payload(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> List['Window']:
if payload_get('all'):
windows = list(boss.all_windows)
else:
window = window or boss.active_window
windows = [window] if window else []
if payload_get('match_window'):
windows = list(boss.match_windows(payload_get('match_window')))
if not windows:
raise MatchError(payload_get('match_window'))
if payload_get('match_tab'):
tabs = tuple(boss.match_tabs(payload_get('match_tab')))
if not tabs:
raise MatchError(payload_get('match_tab'), 'tabs')
for tab in tabs:
windows += list(tab)
return windows
def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType:
raise NotImplementedError() raise NotImplementedError()
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> ResponseType:
raise NotImplementedError() raise NotImplementedError()

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -32,15 +32,8 @@ If specified close the tab this command is run in, rather than the active tab.
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'self': opts.self} return {'match': opts.match, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') for tab in self.tabs_for_match_payload(boss, window, payload_get):
if match:
tabs = list(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = [boss.tab_for_window(window) if window and payload_get('self') else boss.active_tab]
for tab in tabs:
if window: if window:
if tab: if tab:
boss.close_tab(tab) boss.close_tab(tab)

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RCOptions, RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -31,15 +31,8 @@ If specified close the window this command is run in, rather than the active win
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'self': opts.self} return {'match': opts.match, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') for window in self.windows_for_match_payload(boss, window, payload_get):
if match:
windows = list(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = [window if window and payload_get('self') else boss.active_window]
for window in windows:
if window: if window:
boss.close_window(window) boss.close_window(window)

View File

@@ -2,12 +2,12 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from kitty.config import parse_marker_spec from kitty.config import parse_marker_spec
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window PayloadType, RCOptions, RemoteCommand, ResponseType, Window
) )
@@ -41,17 +41,9 @@ If specified apply marker to the window this command is run in, rather than the
parse_marker_spec(args[0], args[1:]) parse_marker_spec(args[0], args[1:])
return {'match': opts.match, 'self': opts.self, 'marker_spec': args} return {'match': opts.match, 'self': opts.self, 'marker_spec': args}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match')
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = tuple(window if window and payload_get('self') else boss.active_window)
args = payload_get('marker_spec') args = payload_get('marker_spec')
for window in self.windows_for_match_payload(boss, window, payload_get):
for window in windows:
window.set_marker(args) window.set_marker(args)

View File

@@ -2,7 +2,7 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType,
@@ -36,15 +36,18 @@ If specified detach the tab this command is run in, rather than the active tab.
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self} return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') match = payload_get('match')
if match: if match:
tabs = tuple(boss.match_tabs(match)) tabs = list(boss.match_tabs(match))
if not tabs: if not tabs:
raise MatchError(match) raise MatchError(match)
else: else:
tab = window.tabref() if payload_get('self') and window:
tabs = tuple(tab if payload_get('self') and window and tab else boss.active_tab) tab = window.tabref() or boss.active_tab
else:
tab = boss.active_tab
tabs = [tab] if tab else []
match = payload_get('target_tab') match = payload_get('target_tab')
kwargs = {} kwargs = {}
if match: if match:

View File

@@ -2,7 +2,7 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional, Union
from .base import ( from .base import (
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError,
@@ -38,27 +38,20 @@ If specified detach the window this command is run in, rather than the active wi
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self} return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') windows = self.windows_for_match_payload(boss, window, payload_get)
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = tuple(window if window and payload_get('self') else boss.active_window)
match = payload_get('target_tab') match = payload_get('target_tab')
kwargs = {} target_tab_id: Optional[Union[str, int]] = None
newval: Union[str, int] = 'new'
if match: if match:
if match == 'new': if match == 'new':
kwargs['target_tab_id'] = 'new' target_tab_id = newval
else: else:
tabs = tuple(boss.match_tabs(match)) tabs = tuple(boss.match_tabs(match))
if not tabs: if not tabs:
raise MatchError(match, 'tabs') raise MatchError(match, 'tabs')
kwargs['target_tab_id'] = tabs[0].id target_tab_id = tabs[0].id
if not kwargs: kwargs = {'target_os_window_id': newval} if target_tab_id is None else {'target_tab_id': target_tab_id}
kwargs['target_os_window_id'] = 'new'
for window in windows: for window in windows:
boss._move_window_to(window=window, **kwargs) boss._move_window_to(window=window, **kwargs)

View File

@@ -3,12 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window, PayloadType, RCOptions, RemoteCommand, ResponseType, Window
windows_for_payload
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -51,8 +50,8 @@ cause ligatures to be changed in all windows.
'all': opts.all, 'all': opts.all,
} }
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = windows_for_payload(boss, window, payload_get) windows = self.windows_for_payload(boss, window, payload_get)
boss.disable_ligatures_in(windows, payload_get('strategy')) boss.disable_ligatures_in(windows, payload_get('strategy'))
# }}} # }}}

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -37,16 +37,10 @@ using this option means that you will not be notified of failures.
global_opts.no_command_response = True global_opts.no_command_response = True
return {'match': opts.match} return {'match': opts.match}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') tabs = self.tabs_for_match_payload(boss, window, payload_get)
if match: if tabs:
tabs = tuple(boss.match_tabs(match)) boss.set_active_tab(tabs[0])
else:
tabs = tuple(boss.tab_for_window(window) if window else boss.active_tab)
if not tabs:
raise MatchError(match, 'tabs')
tab = tabs[0]
boss.set_active_tab(tab)
focus_tab = FocusTab() focus_tab = FocusTab()

View File

@@ -3,13 +3,13 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from kitty.fast_data_types import focus_os_window from kitty.fast_data_types import focus_os_window
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RCOptions, RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -37,14 +37,8 @@ the command will exit with a success code.
global_opts.no_command_response = True global_opts.no_command_response = True
return {'match': opts.match, 'no_response': opts.no_response} return {'match': opts.match, 'no_response': opts.no_response}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = [window or boss.active_window] for window in self.windows_for_match_payload(boss, window, payload_get):
match = payload_get('match')
if match:
windows = [boss.match_windows(match)]
if not windows:
raise MatchError(match)
for window in windows:
if window: if window:
os_window_id = boss.set_active_window(window) os_window_id = boss.set_active_window(window)
if os_window_id: if os_window_id:

View File

@@ -2,14 +2,14 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from kitty.rgb import Color, color_as_sharp, color_from_int from kitty.rgb import Color, color_as_sharp, color_from_int
from kitty.utils import natsort_ints from kitty.utils import natsort_ints
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RCOptions, RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -39,14 +39,10 @@ configured colors.
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'configured': opts.configured, 'match': opts.match} return {'configured': opts.configured, 'match': opts.match}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
ans = {k: getattr(boss.opts, k) for k in boss.opts if isinstance(getattr(boss.opts, k), Color)} ans = {k: getattr(boss.opts, k) for k in boss.opts if isinstance(getattr(boss.opts, k), Color)}
if not payload_get('configured'): if not payload_get('configured'):
windows = [window or boss.active_window] windows = self.windows_for_match_payload(boss, window, payload_get)
if payload_get('match'):
windows = list(boss.match_windows(payload_get('match')))
if not windows:
raise MatchError(payload_get('match'))
ans.update({k: color_from_int(v) for k, v in windows[0].current_colors.items()}) ans.update({k: color_from_int(v) for k, v in windows[0].current_colors.items()})
all_keys = natsort_ints(ans) all_keys = natsort_ints(ans)
maxlen = max(map(len, all_keys)) maxlen = max(map(len, all_keys))

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RCOptions, RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -48,15 +48,8 @@ If specified get text from the window this command is run in, rather than the ac
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self} return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') window = self.windows_for_match_payload(boss, window, payload_get)[0]
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = tuple(window if window and payload_get('self') else boss.active_window)
window = windows[0]
if payload_get('extent') == 'selection': if payload_get('extent') == 'selection':
ans = window.text_for_selection() ans = window.text_for_selection()
else: else:

View File

@@ -2,11 +2,11 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, PayloadType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
RCOptions, RemoteCommand, ResponseType, UnknownLayout, Window RemoteCommand, ResponseType, UnknownLayout, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -34,17 +34,8 @@ class GotoLayout(RemoteCommand):
except IndexError: except IndexError:
raise self.fatal('No layout specified') raise self.fatal('No layout specified')
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') tabs = self.tabs_for_match_payload(boss, window, payload_get)
if match:
if match == 'all':
tabs = tuple(boss.all_tabs)
else:
tabs = tuple(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = tuple(boss.tab_for_window(window) if window else boss.active_tab)
for tab in tabs: for tab in tabs:
if tab: if tab:
try: try:

View File

@@ -2,7 +2,7 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType,
@@ -36,7 +36,7 @@ class Kitten(RemoteCommand):
self.fatal('Must specify kitten name') self.fatal('Must specify kitten name')
return {'match': opts.match, 'args': list(args)[1:], 'kitten': args[0]} return {'match': opts.match, 'args': list(args)[1:], 'kitten': args[0]}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = [window or boss.active_window] windows = [window or boss.active_window]
match = payload_get('match') match = payload_get('match')
if match: if match:

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -17,30 +17,23 @@ if TYPE_CHECKING:
class LastUsedLayout(RemoteCommand): class LastUsedLayout(RemoteCommand):
''' '''
match: Which tab to change the layout of match: Which tab to change the layout of
all: Boolean to match all tabs
''' '''
short_desc = 'Switch to the last used layout' short_desc = 'Switch to the last used layout'
desc = ( desc = (
'Switch to the last used window layout in the specified tab (or the active tab if not specified).' 'Switch to the last used window layout in the specified tab (or the active tab if not specified).'
' You can use special match value :italic:`all` to set the layout in all tabs.'
) )
options_spec = MATCH_TAB_OPTION options_spec = '''\
--all -a
type=bool-set
Change the layout in all tabs.''' + '\n\n\n' + MATCH_TAB_OPTION
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match} return {'match': opts.match, 'all': opts.all}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') for tab in self.tabs_for_match_payload(boss, window, payload_get):
if match:
if match == 'all':
tabs = tuple(boss.all_tabs)
else:
tabs = tuple(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = tuple(boss.tab_for_window(window) if window else boss.active_tab)
for tab in tabs:
if tab: if tab:
tab.last_used_layout() tab.last_used_layout()

View File

@@ -3,7 +3,7 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from kitty.launch import ( from kitty.launch import (
LaunchCLIOptions, launch as do_launch, options_spec as launch_options_spec, LaunchCLIOptions, launch as do_launch, options_spec as launch_options_spec,
@@ -11,7 +11,7 @@ from kitty.launch import (
) )
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, PayloadType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
RCOptions, RemoteCommand, ResponseType, Window RCOptions, RemoteCommand, ResponseType, Window
) )
@@ -70,7 +70,7 @@ instead of the active tab
ans[attr] = val ans[attr] = val
return ans return ans
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
default_opts = parse_launch_args()[0] default_opts = parse_launch_args()[0]
opts = LaunchCLIOptions() opts = LaunchCLIOptions()
for key, default_value in default_opts.__dict__.items(): for key, default_value in default_opts.__dict__.items():
@@ -78,16 +78,7 @@ instead of the active tab
if val is None: if val is None:
val = default_value val = default_value
setattr(opts, key, val) setattr(opts, key, val)
match = payload_get('match') tab = self.tabs_for_match_payload(boss, window, payload_get)[0]
if match:
tabs = list(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = [boss.active_tab]
if payload_get('self') and window and window.tabref():
tabs = [window.tabref()]
tab = tabs[0]
w = do_launch(boss, opts, payload_get('args') or [], target_tab=tab) w = do_launch(boss, opts, payload_get('args') or [], target_tab=tab)
return None if payload_get('no_response') else str(getattr(w, 'id', 0)) return None if payload_get('no_response') else str(getattr(w, 'id', 0))

View File

@@ -3,7 +3,7 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import json import json
from typing import Any from typing import Any, Optional
from kitty.constants import appname from kitty.constants import appname
@@ -32,7 +32,7 @@ class LS(RemoteCommand):
def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType:
pass pass
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
data = list(boss.list_os_windows()) data = list(boss.list_os_windows())
return json.dumps(data, indent=2, sort_keys=True) return json.dumps(data, indent=2, sort_keys=True)

View File

@@ -2,14 +2,14 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from kitty.fast_data_types import focus_os_window from kitty.fast_data_types import focus_os_window
from kitty.tabs import SpecialWindow from kitty.tabs import SpecialWindow
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, PayloadType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
RCOptions, RemoteCommand, ResponseType, Window RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -86,36 +86,29 @@ the id of the new window will not be printed out.
'window_type': opts.window_type, 'no_response': opts.no_response, 'window_type': opts.window_type, 'no_response': opts.no_response,
'keep_focus': opts.keep_focus, 'args': args or []} 'keep_focus': opts.keep_focus, 'args': args or []}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
w = SpecialWindow(cmd=payload_get('args') or None, override_title=payload_get('title'), cwd=payload_get('cwd')) w = SpecialWindow(cmd=payload_get('args') or None, override_title=payload_get('title'), cwd=payload_get('cwd'))
old_window = boss.active_window old_window = boss.active_window
if payload_get('new_tab'): if payload_get('new_tab'):
boss._new_tab(w) boss._new_tab(w)
tab = boss.active_tab tab = boss.active_tab
if payload_get('tab_title'): if payload_get('tab_title') and tab:
tab.set_title(payload_get('tab_title')) tab.set_title(payload_get('tab_title'))
wid = boss.active_window.id aw = boss.active_window
if payload_get('keep_focus') and old_window: if payload_get('keep_focus') and old_window:
boss.set_active_window(old_window) boss.set_active_window(old_window)
return None if payload_get('no_response') else str(wid) return None if not aw or payload_get('no_response') else str(aw.id)
if payload_get('window_type') == 'os': if payload_get('window_type') == 'os':
boss._new_os_window(w) boss._new_os_window(w)
wid = boss.active_window.id aw = boss.active_window
if payload_get('keep_focus') and old_window: if payload_get('keep_focus') and old_window:
os_window_id = boss.set_active_window(old_window) os_window_id = boss.set_active_window(old_window)
if os_window_id: if os_window_id:
focus_os_window(os_window_id) focus_os_window(os_window_id)
return None if payload_get('no_response') else str(wid) return None if not aw or payload_get('no_response') else str(aw.id)
match = payload_get('match') tab = self.tabs_for_match_payload(boss, window, payload_get)[0]
if match:
tabs = list(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = [boss.active_tab]
tab = tabs[0]
ans = tab.new_special_window(w) ans = tab.new_special_window(w)
if payload_get('keep_focus') and old_window: if payload_get('keep_focus') and old_window:
boss.set_active_window(old_window) boss.set_active_window(old_window)

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RCOptions, RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -32,16 +32,8 @@ If specified apply marker to the window this command is run in, rather than the
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'self': opts.self} return {'match': opts.match, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') for window in self.windows_for_match_payload(boss, window, payload_get):
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = tuple(window if window and payload_get('self') else boss.active_window)
for window in windows:
window.remove_marker() window.remove_marker()

View File

@@ -2,10 +2,10 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window PayloadType, RCOptions, RemoteCommand, ResponseType, Window
) )
@@ -53,14 +53,8 @@ If specified resize the window this command is run in, rather than the active wi
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'increment': opts.increment, 'axis': opts.axis, 'self': opts.self} return {'match': opts.match, 'increment': opts.increment, 'axis': opts.axis, 'self': opts.self}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') windows = self.windows_for_match_payload(boss, window, payload_get)
if match:
windows = list(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = [window if window and payload_get('self') else boss.active_window]
resized = False resized = False
if windows and windows[0]: if windows and windows[0]:
resized = boss.resize_layout_window( resized = boss.resize_layout_window(

View File

@@ -45,7 +45,7 @@ class ScrollWindow(RemoteCommand):
return {'match': opts.match, 'amount': amount} return {'match': opts.match, 'amount': amount}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = [window or boss.active_window] windows = [window or boss.active_window]
match = payload_get('match') match = payload_get('match')
amt = payload_get('amount') amt = payload_get('amount')

View File

@@ -5,7 +5,7 @@
import base64 import base64
import os import os
import sys import sys
from typing import TYPE_CHECKING, Dict, Generator from typing import TYPE_CHECKING, Dict, Generator, Optional
from kitty.config import parse_send_text_bytes from kitty.config import parse_send_text_bytes
@@ -108,7 +108,7 @@ are sent as is, not interpreted for escapes.
yield from src yield from src
return chain() return chain()
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = [boss.active_window] windows = [boss.active_window]
match = payload_get('match') match = payload_get('match')
if match: if match:

View File

@@ -10,8 +10,7 @@ from uuid import uuid4
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, PayloadType,
RCOptions, RemoteCommand, ResponseType, Window, RCOptions, RemoteCommand, ResponseType, Window
windows_for_payload
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -90,7 +89,7 @@ How the image should be displayed. The value of configured will use the configur
yield ret yield ret
return file_pipe(path) return file_pipe(path)
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
data = payload_get('data') data = payload_get('data')
if data != '-': if data != '-':
img_id = payload_get('img_id') img_id = payload_get('img_id')
@@ -102,7 +101,7 @@ How the image should be displayed. The value of configured will use the configur
set_background_image.current_file_obj.write(standard_b64decode(data)) set_background_image.current_file_obj.write(standard_b64decode(data))
return None return None
windows = windows_for_payload(boss, window, payload_get) windows = self.windows_for_payload(boss, window, payload_get)
os_windows = tuple({w.os_window_id for w in windows}) os_windows = tuple({w.os_window_id for w in windows})
layout = payload_get('layout') layout = payload_get('layout')
if data == '-': if data == '-':

View File

@@ -3,12 +3,12 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, OpacityError, MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, OpacityError,
PayloadGetType, PayloadType, RCOptions, RemoteCommand, ResponseType, PayloadGetType, PayloadType, RCOptions, RemoteCommand, ResponseType,
Window, windows_for_payload Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -47,10 +47,10 @@ cause colors to be changed in all windows.
'all': opts.all, 'match_tab': opts.match_tab 'all': opts.all, 'match_tab': opts.match_tab
} }
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
if not boss.opts.dynamic_background_opacity: if not boss.opts.dynamic_background_opacity:
raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity') raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity')
windows = windows_for_payload(boss, window, payload_get) windows = self.windows_for_payload(boss, window, payload_get)
for os_window_id in {w.os_window_id for w in windows}: for os_window_id in {w.os_window_id for w in windows}:
boss._set_os_window_background_opacity(os_window_id, payload_get('opacity')) boss._set_os_window_background_opacity(os_window_id, payload_get('opacity'))

View File

@@ -12,8 +12,7 @@ from kitty.rgb import Color, color_as_int
from .base import ( from .base import (
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType, MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window, PayloadType, RCOptions, RemoteCommand, ResponseType, Window
windows_for_payload
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -84,8 +83,8 @@ this option, any color arguments are ignored and --configured and --all are impl
del ans['dummy'] del ans['dummy']
return ans return ans
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = windows_for_payload(boss, window, payload_get) windows = self.windows_for_payload(boss, window, payload_get)
colors = payload_get('colors') colors = payload_get('colors')
cursor_text_color = payload_get('cursor_text_color') or False cursor_text_color = payload_get('cursor_text_color') or False
if payload_get('reset'): if payload_get('reset'):

View File

@@ -2,7 +2,7 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
ArgsType, Boss, PayloadGetType, PayloadType, RCOptions, RemoteCommand, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions, RemoteCommand,
@@ -45,7 +45,7 @@ this option will cause it to be changed in all OS windows.
inc = fs[0] if fs and fs[0] in '+-' else None inc = fs[0] if fs and fs[0] in '+-' else None
return {'size': abs(float(fs)), 'all': opts.all, 'increment_op': inc} return {'size': abs(float(fs)), 'all': opts.all, 'increment_op': inc}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
boss.change_font_size( boss.change_font_size(
payload_get('all'), payload_get('all'),
payload_get('increment_op'), payload_get('size')) payload_get('increment_op'), payload_get('size'))

View File

@@ -3,11 +3,11 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_TAB_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window RemoteCommand, ResponseType, Window
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -34,15 +34,8 @@ class SetTabTitle(RemoteCommand):
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'title': ' '.join(args), 'match': opts.match} return {'title': ' '.join(args), 'match': opts.match}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
match = payload_get('match') for tab in self.tabs_for_match_payload(boss, window, payload_get):
if match:
tabs = tuple(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = tuple(boss.tab_for_window(window) if window else boss.active_tab)
for tab in tabs:
if tab: if tab:
tab.set_title(payload_get('title')) tab.set_title(payload_get('title'))

View File

@@ -2,7 +2,7 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from .base import ( from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType, MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType,
@@ -40,7 +40,7 @@ want to allow other programs to change it afterwards, use this option.
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'title': ' '.join(args), 'match': opts.match, 'temporary': opts.temporary} return {'title': ' '.join(args), 'match': opts.match, 'temporary': opts.temporary}
def response_from_kitty(self, boss: 'Boss', window: 'Window', payload_get: PayloadGetType) -> ResponseType: def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = [window or boss.active_window] windows = [window or boss.active_window]
match = payload_get('match') match = payload_get('match')
if match: if match: