diff --git a/docs/changelog.rst b/docs/changelog.rst index 08bfc2cff..6bae033dc 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -133,6 +133,8 @@ To update |kitty|, :doc:`follow the instructions `. - Wayland: Fix pasting from applications that use a MIME type of "text/plain" rather than "text/plain;charset=utf-8" not working (:iss:`4183`) +- A new mappable action to close windows with a confirmation (:iss:`4195`) + 0.23.1 [2021-08-17] ---------------------- diff --git a/kitty/boss.py b/kitty/boss.py index fd62035b2..869d67897 100755 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -585,8 +585,13 @@ class Boss: if window is not None: window.focus_changed(True) - def mark_window_for_close(self, window: Optional[Window] = None) -> None: - window = window or self.active_window + def mark_window_for_close(self, q: Union[Window, None, int] = None) -> None: + if isinstance(q, int): + window = self.window_id_map.get(q) + if window is None: + return + else: + window = q or self.active_window if window: self.child_monitor.mark_for_close(window.id) @@ -594,6 +599,36 @@ class Boss: def close_window(self) -> None: self.mark_window_for_close() + @ac('win', ''' + Close window with confirmation + + Asks for confirmation before closing the window. If you don't want the + confirmation when the window is sitting at a shell prompt + (requires :ref:`shell_integration`), use:: + + map f1 close_window_with_confirmation ignore-shell + ''') + def close_window_with_confirmation(self, ignore_shell: bool = False) -> None: + window = self.active_window + if window is None: + return + if not ignore_shell or window.has_running_program: + msg = _('Are you sure you want to close this window?') + if window.has_running_program: + msg += ' ' + _('It is running a program.') + self._run_kitten( + 'ask', ['--type=yesno', '--message', msg], + window=window, + custom_callback=partial(self.handle_close_window_confirmation, window.id) + ) + else: + self.mark_window_for_close(window) + + def handle_close_window_confirmation(self, window_id: int, data: Dict[str, Any], *a: Any) -> None: + if data['response'] != 'y': + return + self.mark_window_for_close(window_id) + @ac('tab', 'Close the current tab') def close_tab(self, tab: Optional[Tab] = None) -> None: tab = tab or self.active_tab diff --git a/kitty/conf/types.py b/kitty/conf/types.py index 8af3e98fc..5435083f2 100644 --- a/kitty/conf/types.py +++ b/kitty/conf/types.py @@ -48,6 +48,7 @@ def remove_markup(text: str) -> str: 'sessions': f'{website_url("overview")}#startup-sessions', 'functional': f'{website_url("keyboard-protocol")}#functional-key-definitions', 'action-select_tab': f'{website_url("actions")}#select-tab', + 'action-close_window_with_confirmation': f'{website_url("actions")}#close-window-with-confirmation', 'shell_integration': website_url("shell-integration"), } diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 9e3c2ade6..e6dfe618a 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -892,14 +892,15 @@ opt('confirm_os_window_close', '0', option_type='int', long_text=''' Ask for confirmation when closing an OS window or a Tab with at least this -number of kitty windows in it by window manager (e.g. clicking the window -close button or pressing the shortcut alt+f4, shift+cmd+w) or by the -:sc:`close_tab` action. A value of zero disables confirmation. This confirmation -also applies to requests to quit the entire application (all OS windows, via the -quit action). Negative values are converted to positive ones, however, with -:ref:`shell_integration` enabled, using negative values means windows sitting at -a shell prompt are not counted, only windows where some command is currently -running. +number of kitty windows in it by window manager (e.g. clicking the window close +button or pressing the Operating system shortcut to close windows) or by the +:sc:`close_tab` action. A value of zero disables confirmation. This +confirmation also applies to requests to quit the entire application (all OS +windows, via the quit action). Negative values are converted to positive ones, +however, with :ref:`shell_integration` enabled, using negative values means +windows sitting at a shell prompt are not counted, only windows where some +command is currently running. Note that if you want confirmation when closing +individual windows, you can map the :ref:`action-close_window_with_confirmation` action. ''' ) egr() # }}} diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 94b605344..3cca64b21 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -108,6 +108,12 @@ def detach_window_parse(func: str, rest: str) -> FuncArgsType: return func, (rest,) +@func_with_args('close_window_with_confirmation') +def close_window_with_confirmation(func: str, rest: str) -> FuncArgsType: + ignore_shell = rest == 'ignore-shell' + return func, (ignore_shell,) + + @func_with_args('detach_tab') def detach_tab_parse(func: str, rest: str) -> FuncArgsType: if rest not in ('new', 'ask'):