Merge branch 'done-notification' of https://github.com/jinliu/kitty

This commit is contained in:
Kovid Goyal 2023-11-14 14:34:20 +05:30
commit b5067c1369
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
7 changed files with 102 additions and 2 deletions

View file

@ -145,6 +145,10 @@ functions for the events you are interested in, for example:
# when a title change was requested via escape code from the program
# running in the terminal
def on_cmd_startstop(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
# called when the shell starts/stops executing a command. Here
# data will contain is_start and time.
Every callback is passed a reference to the global ``Boss`` object as well as
the ``Window`` object the action is occurring on. The ``data`` object is a dict
that contains event dependent data. Some useful methods and attributes for the

View file

@ -398,6 +398,15 @@ def load_watch_modules(watchers: Iterable[str]) -> Optional[Watchers]:
w = m.get('on_focus_change')
if callable(w):
ans.on_focus_change.append(w)
w = m.get('on_set_user_var')
if callable(w):
ans.on_set_user_var.append(w)
w = m.get('on_title_change')
if callable(w):
ans.on_title_change.append(w)
w = m.get('on_cmd_startstop')
if callable(w):
ans.on_cmd_startstop.append(w)
return ans

View file

@ -3149,6 +3149,39 @@
'''
)
opt('notify_on_cmd_finish', 'never',
choices=('never', 'unfocused', 'invisible', 'always'),
long_text='''
Whether to send a desktop notification when a long-running command finishes
(needs :opt:`shell_integration`).
The possible values are:
:code:`never`
Never send a notification.
:code:`unfocused`
Only send a notification when the window does not have keyboard focus.
:code:`invisible`
Only send a notification when the window both is unfocused and not visible
to the user, for example, because it is in an inactive tab or its OS window
is not currently active.
:code:`always`
Always send a notification, even if the window is focused.
'''
)
opt('notify_on_cmd_finish_min_duration', '5.0',
option_type="float",
long_text='''
Only send a notification if a command takes more than specified seconds of time.
It's not recommended to set a value too small, as you probably don't want a
notification when a command launches a new window and exit immediately (e.g. the
`code` command from vscode).
'''
)
opt('term', 'xterm-kitty',
long_text='''
The value of the :envvar:`TERM` environment variable to set. Changing this can

11
kitty/options/parse.py generated
View file

@ -1120,6 +1120,17 @@ def narrow_symbols(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
for k, v in narrow_symbols(val):
ans["narrow_symbols"][k] = v
def notify_on_cmd_finish(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_notify_on_cmd_finish:
raise ValueError(f"The value {val} is not a valid choice for notify_on_cmd_finish")
ans["notify_on_cmd_finish"] = val
choices_for_notify_on_cmd_finish = frozenset(('never', 'unfocused', 'invisible', 'always'))
def notify_on_cmd_finish_min_duration(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['notify_on_cmd_finish_min_duration'] = float(val)
def open_url_with(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['open_url_with'] = to_cmdline(val)

View file

@ -20,6 +20,7 @@
choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
choices_for_macos_colorspace = typing.Literal['srgb', 'default', 'displayp3']
choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window']
choices_for_notify_on_cmd_finish = typing.Literal['never', 'unfocused', 'invisible', 'always']
choices_for_placement_strategy = typing.Literal['center', 'top-left']
choices_for_pointer_shape_when_dragging = choices_for_default_pointer_shape
choices_for_pointer_shape_when_grabbed = choices_for_default_pointer_shape
@ -386,6 +387,8 @@
'mouse_hide_wait',
'mouse_map',
'narrow_symbols',
'notify_on_cmd_finish',
'notify_on_cmd_finish_min_duration',
'open_url_with',
'paste_actions',
'placement_strategy',
@ -545,6 +548,8 @@ class Options:
mark3_background: Color = Color(242, 116, 188)
mark3_foreground: Color = Color(0, 0, 0)
mouse_hide_wait: float = 0.0 if is_macos else 3.0
notify_on_cmd_finish: choices_for_notify_on_cmd_finish = 'never'
notify_on_cmd_finish_min_duration: float = 5.0
open_url_with: typing.List[str] = ['default']
paste_actions: typing.FrozenSet[str] = frozenset({'confirm', 'quote-urls-at-prompt'})
placement_strategy: choices_for_placement_strategy = 'center'

View file

@ -2216,9 +2216,12 @@ shell_prompt_marking(Screen *self, PyObject *data) {
}
if (PyErr_Occurred()) PyErr_Print();
self->linebuf->line_attrs[self->cursor->y].prompt_kind = pk;
if (pk == PROMPT_START)
CALLBACK("cmd_output_marking", "i", 0);
} break;
case 'C':
self->linebuf->line_attrs[self->cursor->y].prompt_kind = OUTPUT_START;
CALLBACK("cmd_output_marking", "i", 1);
break;
}
}

View file

@ -83,7 +83,9 @@
from .keys import keyboard_mode_name, mod_mask
from .notify import (
NotificationCommand,
OnlyWhen,
handle_notification_cmd,
notify_with_command,
sanitize_identifier_pat,
)
from .options.types import Options
@ -259,6 +261,7 @@ class Watchers:
on_focus_change: List[Watcher]
on_set_user_var: List[Watcher]
on_title_change: List[Watcher]
on_cmd_startstop: List[Watcher]
def __init__(self) -> None:
self.on_resize = []
@ -266,6 +269,7 @@ def __init__(self) -> None:
self.on_focus_change = []
self.on_set_user_var = []
self.on_title_change = []
self.on_cmd_startstop = []
def add(self, others: 'Watchers') -> None:
def merge(base: List[Watcher], other: List[Watcher]) -> None:
@ -277,10 +281,11 @@ def merge(base: List[Watcher], other: List[Watcher]) -> None:
merge(self.on_focus_change, others.on_focus_change)
merge(self.on_set_user_var, others.on_set_user_var)
merge(self.on_title_change, others.on_title_change)
merge(self.on_cmd_startstop, others.on_cmd_startstop)
def clear(self) -> None:
del self.on_close[:], self.on_resize[:], self.on_focus_change[:]
del self.on_set_user_var[:], self.on_title_change[:]
del self.on_set_user_var[:], self.on_title_change[:], self.on_cmd_startstop[:]
def copy(self) -> 'Watchers':
ans = Watchers()
@ -289,11 +294,13 @@ def copy(self) -> 'Watchers':
ans.on_focus_change = self.on_focus_change[:]
ans.on_set_user_var = self.on_set_user_var[:]
ans.on_title_change = self.on_title_change[:]
ans.on_cmd_startstop = self.on_cmd_startstop[:]
return ans
@property
def has_watchers(self) -> bool:
return bool(self.on_close or self.on_resize or self.on_focus_change)
return bool(self.on_close or self.on_resize or self.on_focus_change
or self.on_set_user_var or self.on_title_change or self.on_cmd_startstop)
def call_watchers(windowref: Callable[[], Optional['Window']], which: str, data: Dict[str, Any]) -> None:
@ -536,6 +543,7 @@ def __init__(
self.current_mouse_event_button = 0
self.current_clipboard_read_ask: Optional[bool] = None
self.prev_osc99_cmd = NotificationCommand()
self.last_cmd_output_start_time = 0
self.actions_on_close: List[Callable[['Window'], None]] = []
self.actions_on_focus_change: List[Callable[['Window', bool], None]] = []
self.actions_on_removal: List[Callable[['Window'], None]] = []
@ -1315,6 +1323,33 @@ def manipulate_title_stack(self, pop: bool, title: str, icon: Any) -> None:
else:
if self.child_title:
self.title_stack.append(self.child_title)
def cmd_output_marking(self, is_start: int) -> None:
if is_start:
start_time = monotonic()
self.last_cmd_output_start_time = start_time
self.call_watchers(self.watchers.on_cmd_startstop, {"is_start": True, "time": start_time})
else:
if self.last_cmd_output_start_time > 0:
end_time = monotonic()
last_cmd_output_duration = end_time - self.last_cmd_output_start_time
self.last_cmd_output_start_time = 0
self.call_watchers(self.watchers.on_cmd_startstop, {"is_start": False, "time": end_time})
opts = get_options()
mode = opts.notify_on_cmd_finish
if mode == 'never':
return
if last_cmd_output_duration >= opts.notify_on_cmd_finish_min_duration:
cmd = NotificationCommand()
cmd.title = 'kitty'
cmd.body = 'Command finished in a background window.\nClick to focus.'
cmd.actions = 'focus'
cmd.only_when = OnlyWhen(mode)
notify_with_command(cmd, self.id)
# }}}
# mouse actions {{{