diff --git a/docs/changelog.rst b/docs/changelog.rst index 35284578e..55e6b9267 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -51,6 +51,10 @@ Detailed list of changes - Fix tab selection when closing a new tab not correct in some scenarios (:iss:`4987`) +- A new action :ac:`open_url` to open the specified URL (:pull:`5004`) + +- macOS: Make the global menu shortcut to open kitty website configurable (:pull:`5004`) + 0.25.0 [2022-04-11] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/boss.py b/kitty/boss.py index 9979d99a3..8de17eb2b 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -1513,6 +1513,7 @@ class Boss: if tab: tab.set_active_window(window_id) + @ac('misc', 'Open the specified URL') def open_url(self, url: str, program: Optional[Union[str, List[str]]] = None, cwd: Optional[str] = None) -> None: if not url: return diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 7a233bba1..b1b85f127 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -1041,6 +1041,7 @@ process_cocoa_pending_actions(void) { 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); } + if (cocoa_pending_actions[OPEN_KITTY_WEBSITE]) { call_boss(open_url, "s", "https://sw.kovidgoyal.net/kitty/"); } if (cocoa_pending_actions_data.wd) { if (cocoa_pending_actions[NEW_OS_WINDOW_WITH_WD]) { call_boss(new_os_window_with_wd, "sO", cocoa_pending_actions_data.wd, Py_True); } if (cocoa_pending_actions[NEW_TAB_WITH_WD]) { call_boss(new_tab_with_wd, "sO", cocoa_pending_actions_data.wd, Py_True); } diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index 7eb0924da..0f1616281 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -235,11 +235,7 @@ PENDING(clear_terminal_and_scrollback, CLEAR_TERMINAL_AND_SCROLLBACK) PENDING(reload_config, RELOAD_CONFIG) PENDING(toggle_macos_secure_keyboard_entry, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY) PENDING(toggle_fullscreen, TOGGLE_FULLSCREEN) - -- (void)open_kitty_website_url:(id)sender { - (void)sender; - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://sw.kovidgoyal.net/kitty/"]]; -} +PENDING(open_kitty_website, OPEN_KITTY_WEBSITE) - (BOOL)validateMenuItem:(NSMenuItem *)item { if (item.action == @selector(toggle_macos_secure_keyboard_entry:)) { @@ -275,7 +271,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, clear_terminal_and_scrollback; - GlobalShortcut toggle_macos_secure_keyboard_entry, toggle_fullscreen; + GlobalShortcut toggle_macos_secure_keyboard_entry, toggle_fullscreen, open_kitty_website; } GlobalShortcuts; static GlobalShortcuts global_shortcuts; @@ -290,7 +286,7 @@ 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(reload_config); - else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); + else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); else Q(open_kitty_website); #undef Q if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; } int cocoa_mods; @@ -652,10 +648,8 @@ cocoa_create_global_menu(void) { keyEquivalent:@""]; NSMenu* helpMenu = [[NSMenu alloc] initWithTitle:@"Help"]; [helpMenuItem setSubmenu:helpMenu]; - [[helpMenu addItemWithTitle:[NSString stringWithFormat:@"Visit %@ Website", app_name] - action:@selector(open_kitty_website_url:) - keyEquivalent:@"?"] - setTarget:global_menu_target]; + + MENU_ITEM(helpMenu, @"Visit kitty Website", open_kitty_website); [NSApp setHelpMenu:helpMenu]; [helpMenu release]; diff --git a/kitty/main.py b/kitty/main.py index ac7bde156..8b1cb9cd6 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -17,7 +17,7 @@ from .conf.utils import BadLine from .config import cached_values_for from .constants import ( appname, beam_cursor_data_file, config_dir, glfw_path, is_macos, - is_wayland, kitty_exe, logo_png_file, running_in_kitty + is_wayland, kitty_exe, logo_png_file, running_in_kitty, website_url ) from .fast_data_types import ( GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, create_os_window, @@ -163,6 +163,9 @@ def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) val = get_macos_shortcut_for(func_map, 'load_config_file', lookup_name='reload_config') if val is not None: global_shortcuts['reload_config'] = val + val = get_macos_shortcut_for(func_map, f'open_url {website_url()}', lookup_name='open_kitty_website') + if val is not None: + global_shortcuts['open_kitty_website'] = val if is_macos and opts.macos_custom_beam_cursor: set_custom_ibeam_cursor() if not is_wayland() and not is_macos: # no window icons on wayland diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 4124f8730..74a326241 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -5,6 +5,7 @@ import string from kitty.conf.types import Action, Definition +from kitty.constants import website_url definition = Definition( @@ -3786,5 +3787,10 @@ Some more examples:: map ctrl+alt+a send_text normal,application some command with arguments\\r ''' ) + +map('Open kitty Website', + f'open_kitty_website shift+cmd+/ open_url {website_url()}', + only='macos', + ) egr() # }}} egr() # }}} diff --git a/kitty/options/types.py b/kitty/options/types.py index 6bf2e1f43..bd3c8a3d7 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -922,6 +922,7 @@ if is_macos: defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=107), definition='clear_terminal to_cursor active')) # noqa defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=44), definition='load_config_file')) # noqa defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=44), definition='debug_config')) # noqa + defaults.map.append(KeyDefinition(trigger=SingleKey(mods=9, key=47), definition='open_url https://sw.kovidgoyal.net/kitty/')) # noqa defaults.mouse_map = [ # click_url_or_select MouseMapping(repeat_count=-2, definition='mouse_handle_click selection link prompt'), # noqa diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 87916f39c..fdb5b45ee 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -91,6 +91,20 @@ def kitten_parse(func: str, rest: str) -> FuncArgsType: return func, [args[0]] + (to_cmdline(args[1]) if len(args) > 1 else []) +@func_with_args('open_url') +def open_url_parse(func: str, rest: str) -> FuncArgsType: + from urllib.parse import urlparse + url = '' + try: + url = python_string(rest) + tokens = urlparse(url) + if not all((tokens.scheme, tokens.netloc,)): + raise ValueError('Invalid URL') + except Exception: + log_error('Ignoring invalid URL string: ' + rest) + return func, (url,) + + @func_with_args('goto_tab') def goto_tab_parse(func: str, rest: str) -> FuncArgsType: args = (max(0, int(rest)), ) diff --git a/kitty/state.h b/kitty/state.h index 8f17dcec0..53bf0352b 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -309,6 +309,7 @@ typedef enum { RELOAD_CONFIG, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY, TOGGLE_FULLSCREEN, + OPEN_KITTY_WEBSITE, NUM_COCOA_PENDING_ACTIONS } CocoaPendingAction;