Cache parsed save as session options spec

This commit is contained in:
Kovid Goyal 2025-08-16 09:46:03 +05:30
parent ca715c4cae
commit 0fb1835af1
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 36 additions and 17 deletions

View file

@ -601,6 +601,17 @@ def apply_preparsed_cli_flags(preparsed_from_c: PreparsedCLIFlags, ans: Any, cre
return preparsed_from_c[1] return preparsed_from_c[1]
def parse_cmdline_inner(
args: list[str], oc: Options, disabled: OptionSpecSeq, names_map: dict[str, OptionDict], values_map: dict[str, OptionDict], ans: Any
) -> list[str]:
preparsed = parse_cli_from_spec(args, names_map, values_map)
leftover_args = apply_preparsed_cli_flags(preparsed, ans, lambda: oc)
for opt in disabled:
if not isinstance(opt, str):
setattr(ans, opt['dest'], defval_for_opt(opt))
return leftover_args
def parse_cmdline(oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str] | None = None) -> list[str]: def parse_cmdline(oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str] | None = None) -> list[str]:
names_map = oc.names_map.copy() names_map = oc.names_map.copy()
values_map = oc.values_map.copy() values_map = oc.values_map.copy()
@ -611,18 +622,24 @@ def parse_cmdline(oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str
names_map['version'] = {'type': 'bool-set', 'aliases': ('--version', '-v')} # type: ignore names_map['version'] = {'type': 'bool-set', 'aliases': ('--version', '-v')} # type: ignore
values_map['version'] = False values_map['version'] = False
try: try:
preparsed = parse_cli_from_spec(sys.argv[1:] if args is None else args, names_map, values_map) return parse_cmdline_inner(sys.argv[1:] if args is None else args, oc, disabled, names_map, values_map, ans)
except Exception as e: except Exception as e:
raise SystemExit(str(e)) raise SystemExit(str(e))
leftover_args = apply_preparsed_cli_flags(preparsed, ans, lambda: oc)
for opt in disabled:
if not isinstance(opt, str): spec_cache: dict[str, tuple[Options, OptionSpecSeq]] = {}
setattr(ans, opt['dest'], defval_for_opt(opt))
def cached_parse_cmdline(spec: str, args: list[str], ans: Any) -> list[str]:
if (x := spec_cache.get(spec)) is None:
seq, disabled = parse_option_spec(spec)
oc = Options(seq, '', '', '')
x = spec_cache[spec] = oc, disabled
oc, disabled = x
leftover_args = parse_cmdline_inner(args, oc, disabled, oc.names_map, oc.values_map, ans)
return leftover_args return leftover_args
def options_for_completion() -> OptionSpecSeq: def options_for_completion() -> OptionSpecSeq:
raw = '--help -h\ntype=bool-set\nShow help for {appname} command line options\n\n{raw}'.format( raw = '--help -h\ntype=bool-set\nShow help for {appname} command line options\n\n{raw}'.format(
appname=appname, raw=kitty_options_spec()) appname=appname, raw=kitty_options_spec())

View file

@ -467,17 +467,19 @@ def save_as_session_part2(boss: BossType, opts: SaveAsSessionOptions, path: str)
boss.edit_file(path) boss.edit_file(path)
def parse_save_as_options_spec_args(args: list[str]) -> tuple[SaveAsSessionOptions, list[str]]:
from kitty.cli import cached_parse_cmdline
ans = SaveAsSessionOptions()
leftover_args = cached_parse_cmdline(save_as_session_options(), args, ans)
return ans, leftover_args
def default_save_as_session_opts() -> SaveAsSessionOptions: def default_save_as_session_opts() -> SaveAsSessionOptions:
from kitty.cli import parse_args return parse_save_as_options_spec_args([])[0]
return parse_args(
[], save_as_session_options, result_class=SaveAsSessionOptions)[0]
def save_as_session(boss: BossType, cmdline: Sequence[str]) -> None: def save_as_session(boss: BossType, cmdline: Sequence[str]) -> None:
from kitty.cli import parse_args opts, args = parse_save_as_options_spec_args(list(cmdline))
opts: SaveAsSessionOptions
opts, args = parse_args(
list(cmdline), save_as_session_options, result_class=SaveAsSessionOptions)
path = args[0] if args else '' path = args[0] if args else ''
if path: if path:
save_as_session_part2(boss, opts, path) save_as_session_part2(boss, opts, path)

View file

@ -8,7 +8,7 @@ import re
import sys import sys
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum, auto from enum import Enum, auto
from typing import Any, Iterator, TypedDict from typing import Any, Iterator, Sequence, TypedDict
try: try:
from kitty.constants import appname, is_macos from kitty.constants import appname, is_macos
@ -118,7 +118,7 @@ class OptionDict(TypedDict):
completion: CompletionSpec completion: CompletionSpec
OptionSpecSeq = list[str | OptionDict] OptionSpecSeq = Sequence[str | OptionDict]
def parse_option_spec(spec: str | None = None) -> tuple[OptionSpecSeq, OptionSpecSeq]: def parse_option_spec(spec: str | None = None) -> tuple[OptionSpecSeq, OptionSpecSeq]:
@ -129,8 +129,8 @@ def parse_option_spec(spec: str | None = None) -> tuple[OptionSpecSeq, OptionSpe
lines = spec.splitlines() lines = spec.splitlines()
prev_line = '' prev_line = ''
prev_indent = 0 prev_indent = 0
seq: OptionSpecSeq = [] seq: list[str | OptionDict] = []
disabled: OptionSpecSeq = [] disabled: list[str | OptionDict] = []
mpat = re.compile('([a-z]+)=(.+)') mpat = re.compile('([a-z]+)=(.+)')
current_cmd: OptionDict = { current_cmd: OptionDict = {
'dest': '', 'aliases': (), 'help': '', 'choices': (), 'dest': '', 'aliases': (), 'help': '', 'choices': (),