diff --git a/kitty/cli.py b/kitty/cli.py index 993f050ff..e19cbf091 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -565,21 +565,32 @@ class Options: self.seq = seq self.usage, self.message, self.appname = usage, message, appname self.names_map, self.alias_map, self.values_map = get_option_maps(seq) + self.help_called = self.version_called = False def handle_help(self) -> NoReturn: if self.do_print: print_help_for_seq(self.seq, self.usage, self.message, self.appname or appname) + self.help_called = True raise SystemExit(0) def handle_version(self) -> NoReturn: + self.version_called = True if self.do_print: print(version()) raise SystemExit(0) def parse_cmdline(oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str] | None = None) -> list[str]: + names_map = oc.names_map.copy() + values_map = oc.values_map.copy() + if 'help' not in names_map: + names_map['help'] = {'type': 'bool-set', 'aliases': ('--help', '-h')} # type: ignore + values_map['help'] = False + if 'version' not in names_map: + names_map['version'] = {'type': 'bool-set', 'aliases': ('--version', '-v')} # type: ignore + values_map['version'] = False try: - vals, leftover_args = parse_cli_from_spec(sys.argv[1:] if args is None else args, oc.names_map, oc.values_map) + vals, leftover_args = parse_cli_from_spec(sys.argv[1:] if args is None else args, names_map, values_map) except Exception as e: raise SystemExit(str(e)) diff --git a/kitty/launcher/cli-parser.h b/kitty/launcher/cli-parser.h index 23ce2261c..2f68b76db 100644 --- a/kitty/launcher/cli-parser.h +++ b/kitty/launcher/cli-parser.h @@ -274,7 +274,7 @@ parse_cli_loop(CLISpec *spec, int argc, char **argv) { // argv must contain arg if (!process_cli_arg(spec, flag, payload)) return false; } else { state = EXPECTING_ARG; - current_option = arg; + current_option = flag; } if (spec->errmsg) return false; } diff --git a/kitty/simple_cli_definitions.py b/kitty/simple_cli_definitions.py index 53f5c4b37..0aa7970f0 100644 --- a/kitty/simple_cli_definitions.py +++ b/kitty/simple_cli_definitions.py @@ -252,6 +252,13 @@ def c_str(x: str) -> str: def generate_c_parser_for(funcname: str, spec: str) -> Iterator[str]: names_map, _, defaults_map = get_option_maps(parse_option_spec(spec)[0]) + if 'help' not in names_map: + names_map['help'] = {'type': 'bool-set', 'aliases': ('--help', '-h')} # type: ignore + defaults_map['help'] = False + if 'version' not in names_map: + names_map['version'] = {'type': 'bool-set', 'aliases': ('--version', '-v')} # type: ignore + defaults_map['version'] = False + yield f'static void\nparse_cli_for_{funcname}(CLISpec *spec, int argc, char **argv) {{' # }} yield '\tFlagSpec flag;' for name, opt in names_map.items(): diff --git a/kitty_tests/options.py b/kitty_tests/options.py index 5751529e0..b76e1db26 100644 --- a/kitty_tests/options.py +++ b/kitty_tests/options.py @@ -77,18 +77,25 @@ version oc = Options(seq, usage='xxx', message='yyy', appname='test') oc.do_print = False - def t(args, leftover=(), fails=False, **expected): + def t(args, leftover=(), fails=False, version_called=False, help_called=False, **expected): + oc.help_called = oc.version_called = False args = list(shlex_split(args)) ans = CLIOptions() if fails: - with self.assertRaises(SystemExit): - parse_cmdline(oc, disabled, ans, args=args) + if isinstance(fails, str): + with self.assertRaisesRegex(SystemExit, fails): + parse_cmdline(oc, disabled, ans, args=args) + else: + with self.assertRaises(SystemExit): + parse_cmdline(oc, disabled, ans, args=args) else: actual_leftover = parse_cmdline(oc, disabled, ans, args=args) self.assertEqual(tuple(leftover), tuple(actual_leftover), f'{args}\n{ans}') for dest, defval in oc.values_map.items(): val = expected.get(dest, defval) self.assertEqual(val, getattr(ans, dest, BaseTest), f'Failed to parse {dest} correctly for: {args} \n{ans}') + self.assertEqual(version_called, oc.version_called) + self.assertEqual(help_called, oc.help_called) t('-1', bool_set=True) t('-01', bool_reset=False, bool_set=True) @@ -101,14 +108,14 @@ version t('--simple-string --help -- -1', leftover=['-1'], simple_string='--help') t('-1l=a --list=b -c b --list c', bool_set=True, choice='b', list=list('abc')) t('-1s= -l "" --list= x', leftover=['x'], bool_set=True, simple_string='', list=['', '']) - t('--choice moo', fails=True) - t('-1c moo', fails=True) - t('-10c=moo', fails=True) - t('-1 -h', fails=True) - t('-1 --help', fails=True) - t('-1 -0v', fails=True) - t('-1 -v0', fails=True) - t('-1 --version', fails=True) + t('--choice moo', fails='a, b, c') + t('-1c moo', fails='a, b, c') + t('-10c=moo', fails='a, b, c') + t('-1 -h', fails=True, help_called=True) + t('-1 --help', fails=True, help_called=True) + t('-1 -0v', fails=True, version_called=True) + t('-1 -v0', fails=True, version_called=True) + t('-1 --version', fails=True, version_called=True) t('-f=3.142 --int 17', float=3.142, int=17)