From 581db0ab7ab5e26d3e9ac084c6d6ee2b010f9359 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 22 Jun 2024 12:27:29 +0530 Subject: [PATCH] Make kitty --version fast It's now approx 3ms on my system and 1.23 times faster than alacritty --version --- kitty/data-types.c | 2 +- kitty/launcher/main.c | 52 +++++++++++++++++++++++++++++++++++++++++++ setup.py | 26 ++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/kitty/data-types.c b/kitty/data-types.c index a6b718805..c0414d2dd 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -249,7 +249,7 @@ get_docs_ref_map(PyObject *self UNUSED, PyObject *args UNUSED) { static PyObject* wrapped_kittens(PyObject *self UNUSED, PyObject *args UNUSED) { - const char *wrapped_kitten_names = WRAPPED_KITTENS; + static const char *wrapped_kitten_names = WRAPPED_KITTENS; PyObject *ans = PyUnicode_FromString(wrapped_kitten_names); if (ans == NULL) return NULL; PyObject *s = PyUnicode_Split(ans, NULL, -1); diff --git a/kitty/launcher/main.c b/kitty/launcher/main.c index bdee1fe18..1b755c4b7 100644 --- a/kitty/launcher/main.c +++ b/kitty/launcher/main.c @@ -356,6 +356,57 @@ delegate_to_kitten_if_possible(int argc, char *argv[], char* exe_dir) { if (argc > 3 && strcmp(argv[1], "+") == 0 && strcmp(argv[2], "kitten") == 0 && is_wrapped_kitten(argv[3])) exec_kitten(argc - 2, argv + 2, exe_dir); } +static bool +is_boolean_flag(const char *x) { + static const char *all_boolean_options = KITTY_CLI_BOOL_OPTIONS; + char buf[128]; + snprintf(buf, sizeof(buf), " %s ", x); + return strstr(all_boolean_options, buf) != NULL; +} + +static void +handle_fast_commandline(int argc, char *argv[]) { + char current_option_expecting_argument[128] = {0}; + bool version_requested = false; + for (int i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (current_option_expecting_argument[0]) { + current_option_expecting_argument[0] = 0; + } else { + if (!arg || !arg[0] || !arg[1] || arg[0] != '-' || strcmp(arg, "--") == 0) break; + if (arg[1] == '-') { // long opt + const char *equal = strchr(arg, '='); + if (equal == NULL) { + if (strcmp(arg+2, "version") == 0) { + version_requested = true; + } else if (!is_boolean_flag(arg+2)) { + strncpy(current_option_expecting_argument, arg+2, sizeof(current_option_expecting_argument)-1); + } + } + } else { + char buf[2] = {0}; + for (int i = 1; arg[i] != 0; i++) { + switch(arg[i]) { + case 'v': version_requested = true; break; + default: + buf[0] = arg[i]; buf[1] = 0; + if (!is_boolean_flag(buf)) { current_option_expecting_argument[0] = arg[i]; current_option_expecting_argument[1] = 0; } + } + } + } + } + } + + if (version_requested) { + if (isatty(STDOUT_FILENO)) { + printf("\x1b[3mkitty\x1b[23m \x1b[32m%s\x1b[39m created by \x1b[1;34mKovid Goyal\x1b[22;39m\n", KITTY_VERSION); + } else { + printf("kitty %s created by Kovid Goyal\n", KITTY_VERSION); + } + exit(0); + } +} + int main(int argc, char *argv[], char* envp[]) { if (argc < 1 || !argv) { fprintf(stderr, "Invalid argc/argv\n"); return 1; } if (!ensure_working_stdio()) return 1; @@ -370,6 +421,7 @@ int main(int argc, char *argv[], char* envp[]) { strncpy(exe_dir_buf, exe, sizeof(exe_dir_buf)); char *exe_dir = dirname(exe_dir_buf); delegate_to_kitten_if_possible(argc, argv, exe_dir); + handle_fast_commandline(argc, argv); int num, ret=0; char lib[PATH_MAX+1] = {0}; if (KITTY_LIB_PATH[0] == '/') { diff --git a/setup.py b/setup.py index 7d0172534..294348103 100755 --- a/setup.py +++ b/setup.py @@ -1203,6 +1203,30 @@ def build_static_binaries(args: Options, launcher_dir: str) -> None: build_static_kittens(args, launcher_dir, args.dir_for_static_binaries, for_platform=(os_, arch)) +@lru_cache(2) +def kitty_cli_boolean_options() -> Tuple[str, ...]: + with open(os.path.join(src_base, 'kitty/cli.py')) as f: + raw = f.read() + m = re.search(r"^\s*OPTIONS = '''(.+?)'''", raw, flags=re.MULTILINE | re.DOTALL) + assert m is not None + ans: List[str] = [] + in_option: List[str] = [] + prev_line_was_blank = False + for line in m.group(1).splitlines(): + if in_option: + is_blank = not line.strip() + if is_blank: + if prev_line_was_blank: + in_option = [] + prev_line_was_blank = is_blank + if line.startswith('type=bool-'): + ans.extend(x.lstrip('-') for x in in_option) + else: + if line.startswith('-'): + in_option = line.strip().split() + return tuple(ans) + + def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 'source') -> None: werror = '' if args.ignore_compiler_warnings else '-pedantic-errors -Werror' cflags = f'-Wall {werror} -fpie'.split() @@ -1260,6 +1284,8 @@ def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 's os.makedirs(launcher_dir, exist_ok=True) os.makedirs(build_dir, exist_ok=True) objects = [] + cppflags.append('-DKITTY_CLI_BOOL_OPTIONS=" ' + ' '.join(kitty_cli_boolean_options()) + ' "') + cppflags.append('-DKITTY_VERSION="' + '.'.join(map(str, version)) + '"') for src in ('kitty/launcher/main.c',): obj = os.path.join(build_dir, src.replace('/', '-').replace('.c', '.o')) objects.append(obj)