diff --git a/docs/changelog.rst b/docs/changelog.rst index acc23a2c9..0ab978ca2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -112,6 +112,9 @@ Detailed list of changes - A new :opt:`cursor_trail_color` setting to independently control the color of cursor trails (:pull:`8830`) +- macOS: Add the default :kbd:`Cmd+L` mapping from Terminal.app to erase the + last command and its output (:disc:`6040`) + - Wayland: Fix incorrect window size calculation when transitioning from full screen to non-full screen with client side decorations (:iss:`8826`) diff --git a/kitty/boss.py b/kitty/boss.py index e686edb8e..ab91614ac 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -1306,6 +1306,8 @@ class Boss: map f1 clear_terminal to_cursor active # Same as above except cleared lines are moved into scrollback map f1 clear_terminal to_cursor_scroll active + # Erase the last command and its output (needs shell integration to work) + map f1 clear_terminal last_command active ''') def clear_terminal(self, action: str, only_active: bool) -> None: if only_active: @@ -1333,6 +1335,9 @@ class Boss: elif action == 'to_cursor_scroll': for w in windows: w.scroll_prompt_to_top(clear_scrollback=False) + elif action == 'last_command': + for w in windows: + w.screen.erase_last_command() else: self.show_error(_('Unknown clear type'), _('The clear type: {} is unknown').format(action)) diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 240e7badf..a259c74e6 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -1234,6 +1234,7 @@ process_cocoa_pending_actions(void) { if (cocoa_pending_actions[CLEAR_TERMINAL_AND_SCROLLBACK]) { call_boss(clear_terminal, "sO", "to_cursor", Py_True ); } if (cocoa_pending_actions[CLEAR_SCROLLBACK]) { call_boss(clear_terminal, "sO", "scrollback", Py_True ); } if (cocoa_pending_actions[CLEAR_SCREEN]) { call_boss(clear_terminal, "sO", "to_cursor_scroll", Py_True ); } + if (cocoa_pending_actions[CLEAR_LAST_COMMAND]) { call_boss(clear_terminal, "sO", "last_command", Py_True ); } if (cocoa_pending_actions[RELOAD_CONFIG]) { call_boss(load_config_file, NULL); } if (cocoa_pending_actions[TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY]) { call_boss(toggle_macos_secure_keyboard_entry, NULL); } if (cocoa_pending_actions[TOGGLE_FULLSCREEN]) { call_boss(toggle_fullscreen, NULL); } diff --git a/kitty/cocoa_window.h b/kitty/cocoa_window.h index ce76b9d2e..7f11516df 100644 --- a/kitty/cocoa_window.h +++ b/kitty/cocoa_window.h @@ -27,6 +27,7 @@ typedef enum { CLEAR_TERMINAL_AND_SCROLLBACK, CLEAR_SCROLLBACK, CLEAR_SCREEN, + CLEAR_LAST_COMMAND, RELOAD_CONFIG, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY, TOGGLE_FULLSCREEN, diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index c7ab12ad1..e41a84787 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -255,6 +255,7 @@ PENDING(reset_terminal, RESET_TERMINAL) PENDING(clear_terminal_and_scrollback, CLEAR_TERMINAL_AND_SCROLLBACK) PENDING(clear_scrollback, CLEAR_SCROLLBACK) PENDING(clear_screen, CLEAR_SCREEN) +PENDING(clear_last_command, CLEAR_LAST_COMMAND) PENDING(reload_config, RELOAD_CONFIG) PENDING(toggle_macos_secure_keyboard_entry, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY) PENDING(toggle_fullscreen, TOGGLE_FULLSCREEN) @@ -278,6 +279,7 @@ PENDING(quit, QUIT) item.action == @selector(close_window:) || item.action == @selector(reset_terminal:) || item.action == @selector(clear_terminal_and_scrollback:) || + item.action == @selector(clear_last_command:) || item.action == @selector(clear_scrollback:) || item.action == @selector(clear_screen:) || item.action == @selector(previous_tab:) || @@ -314,7 +316,7 @@ typedef struct { typedef struct { GlobalShortcut new_os_window, close_os_window, close_tab, edit_config_file, reload_config; GlobalShortcut previous_tab, next_tab, new_tab, new_window, close_window, reset_terminal; - GlobalShortcut clear_terminal_and_scrollback, clear_screen, clear_scrollback; + GlobalShortcut clear_terminal_and_scrollback, clear_screen, clear_scrollback, clear_last_command; GlobalShortcut toggle_macos_secure_keyboard_entry, toggle_fullscreen, open_kitty_website; GlobalShortcut hide_macos_app, hide_macos_other_apps, minimize_macos_window, quit; } GlobalShortcuts; @@ -331,9 +333,10 @@ cocoa_set_global_shortcut(PyObject *self UNUSED, PyObject *args) { Q(new_os_window); else Q(close_os_window); else Q(close_tab); else Q(edit_config_file); else Q(new_tab); else Q(next_tab); else Q(previous_tab); else Q(new_window); else Q(close_window); else Q(reset_terminal); - else Q(clear_terminal_and_scrollback); else Q(clear_scrollback); else Q(clear_screen); else Q(reload_config); - else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); else Q(open_kitty_website); - else Q(hide_macos_app); else Q(hide_macos_other_apps); else Q(minimize_macos_window); else Q(quit); + else Q(clear_terminal_and_scrollback); else Q(clear_scrollback); else Q(clear_screen); else Q(clear_last_command); + else Q(reload_config); else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); + else Q(open_kitty_website); else Q(hide_macos_app); else Q(hide_macos_other_apps); + else Q(minimize_macos_window); else Q(quit); #undef Q if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; } int cocoa_mods; @@ -787,6 +790,7 @@ cocoa_create_global_menu(void) { MENU_ITEM(editMenu, @"Clear to Start", clear_terminal_and_scrollback); MENU_ITEM(editMenu, @"Clear Scrollback", clear_scrollback); MENU_ITEM(editMenu, @"Clear Screen", clear_screen); + MENU_ITEM(editMenu, @"Clear Last Command", clear_last_command); [editMenu release]; NSMenuItem* windowMenuItem = diff --git a/kitty/main.py b/kitty/main.py index b540c15f3..9746fd95c 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -207,6 +207,9 @@ def set_cocoa_global_shortcuts(opts: Options) -> dict[str, SingleKey]: val = get_macos_shortcut_for(func_map, 'clear_terminal to_cursor_scroll active', lookup_name='clear_screen') if val is not None: global_shortcuts['clear_screen'] = val + val = get_macos_shortcut_for(func_map, 'clear_terminal last_command active', lookup_name='clear_last_command') + if val is not None: + global_shortcuts['clear_last_command'] = val val = get_macos_shortcut_for(func_map, 'load_config_file', lookup_name='reload_config') if val is not None: global_shortcuts['reload_config'] = val diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 0ac63c6b0..9bfc92b4c 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -4361,6 +4361,8 @@ You can create shortcuts to clear/reset the terminal. For example:: map f1 clear_terminal to_cursor active # Same as above except cleared lines are moved into scrollback map f1 clear_terminal to_cursor_scroll active + # Erase the last command and its output (needs shell integration to work) + map f1 clear_terminal last_command active If you want to operate on all kitty windows instead of just the current one, use :italic:`all` instead of :italic:`active`. @@ -4416,6 +4418,11 @@ map('Clear scrollback', only='macos', ) +map('Clear the last command', + 'clear_last_command cmd+l clear_terminal last_command active', + only='macos', + ) + map('Clear screen', 'clear_screen cmd+ctrl+l clear_terminal to_cursor_scroll active', only='macos', diff --git a/kitty/options/types.py b/kitty/options/types.py index 4a5db05c5..18ec1f166 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -979,6 +979,7 @@ if is_macos: defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=114), definition='clear_terminal reset active')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=107), definition='clear_terminal to_cursor active')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=107), definition='clear_terminal scrollback active')) + defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=108), definition='clear_terminal last_command active')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=108), definition='clear_terminal to_cursor_scroll active')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=44), definition='load_config_file')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=44), definition='debug_config')) diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 2cb44c2fd..4fbb230a0 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -213,7 +213,7 @@ def clear_terminal(func: str, rest: str) -> FuncArgsType: args = ['reset', True] else: action = vals[0].lower() - if action not in ('reset', 'scroll', 'scrollback', 'clear', 'to_cursor', 'to_cursor_scroll'): + if action not in ('reset', 'scroll', 'scrollback', 'clear', 'to_cursor', 'to_cursor_scroll', 'last_command'): log_error(f'{action} is unknown for clear_terminal, using reset') action = 'reset' args = [action, vals[1].lower() == 'active']