Move GoOption migration code to cli.py for re-use

This commit is contained in:
Kovid Goyal 2022-08-29 10:43:33 +05:30
parent 3b2c4561c2
commit 43b35f6f4e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 85 additions and 83 deletions

View File

@ -1,31 +1,29 @@
#!./kitty/launcher/kitty +launch #!./kitty/launcher/kitty +launch
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import json
import io import io
import json
import os import os
from contextlib import contextmanager, suppress from contextlib import contextmanager, suppress
from typing import Dict, Iterator, List, Tuple, Union from typing import Dict, Iterator, List, Tuple, Union
import kitty.constants as kc import kitty.constants as kc
from kittens.tui.operations import Mode from kittens.tui.operations import Mode
from kitty.rgb import color_names from kitty.cli import (
from kitty.cli import OptionDict, OptionSpecSeq, parse_option_spec GoOption, OptionSpecSeq, parse_option_spec, serialize_as_go_string
from kitty.options.types import Options )
from kitty.key_encoding import config_mod_map from kitty.key_encoding import config_mod_map
from kitty.key_names import ( from kitty.key_names import (
character_key_name_aliases, functional_key_name_aliases character_key_name_aliases, functional_key_name_aliases
) )
from kitty.options.types import Options
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
from kitty.rgb import color_names
changed: List[str] = [] changed: List[str] = []
# Utils {{{ # Utils {{{
def serialize_as_go_string(x: str) -> str:
return x.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')
def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int], Dict[str, str]]) -> str: def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int], Dict[str, str]]) -> str:
ans = [] ans = []
@ -47,80 +45,6 @@ def replace(template: str, **kw: str) -> str:
# }}} # }}}
go_type_map = {'bool-set': 'bool', 'bool-reset': 'bool', 'int': 'int', 'float': 'float64', '': 'string', 'list': '[]string', 'choices': 'string'}
go_getter_map = {
'bool-set': 'GetBool', 'bool-reset': 'GetBool', 'int': 'GetInt', 'float': 'GetFloat64', '': 'GetString',
'list': 'GetStringArray', 'choices': 'GetString'
}
class Option:
def __init__(self, cmd_name: str, x: OptionDict) -> None:
self.cmd_name = cmd_name
flags = sorted(x['aliases'], key=len)
short = ''
self.aliases = []
if len(flags) > 1 and not flags[0].startswith("--"):
short = flags[0][1:]
del flags[0]
self.short, self.long = short, x['name'].replace('_', '-')
for f in flags:
q = f[2:]
if q != self.long:
self.aliases.append(q)
self.usage = serialize_as_go_string(x['help'].strip())
self.type = x['type']
self.dest = x['dest']
self.default = x['default']
self.obj_dict = x
self.go_type = go_type_map[self.type]
self.go_var_name = self.long.replace('-', '_')
if self.go_var_name == 'type':
self.go_var_name += '_'
def to_flag_definition(self, base: str = 'ans.Flags()') -> str:
if self.type.startswith('bool-'):
defval = 'false' if self.type == 'bool-set' else 'true'
if self.short:
return f'{base}.BoolP("{self.long}", "{self.short}", {defval}, "{self.usage}")'
return f'{base}.Bool("{self.long}", {defval}, "{self.usage}")'
elif not self.type:
defval = f'''"{serialize_as_go_string(self.default or '')}"'''
if self.short:
return f'{base}.StringP("{self.long}", "{self.short}", {defval}, "{self.usage}")'
return f'{base}.String("{self.long}", {defval}, "{self.usage}")'
elif self.type == 'int':
if self.short:
return f'{base}.IntP("{self.long}", "{self.short}", {self.default or 0}, "{self.usage}")'
return f'{base}.Int("{self.long}", {self.default or 0}, "{self.usage}")'
elif self.type == 'float':
if self.short:
return f'{base}.Float64P("{self.long}", "{self.short}", {self.default or 0}, "{self.usage}")'
return f'{base}.Float64("{self.long}", {self.default or 0}, "{self.usage}")'
elif self.type == 'list':
defval = f'[]string{{"{serialize_as_go_string(self.default)}"}}' if self.default else '[]string{}'
if self.short:
return f'{base}.StringArrayP("{self.long}", "{self.short}", {defval}, "{self.usage}")'
return f'{base}.StringArray("{self.long}", {defval}, "{self.usage}")'
elif self.type == 'choices':
choices = sorted(self.obj_dict['choices'])
choices.remove(self.default or '')
choices.insert(0, self.default or '')
cx = ', '.join(f'"{serialize_as_go_string(x)}"' for x in choices)
if self.short:
return f'cli.ChoicesP({base}, "{self.long}", "{self.short}", "{self.usage}", {cx})'
return f'cli.Choices({base}, "{self.long}", "{self.usage}", {cx})'
else:
raise TypeError(f'Unknown type of CLI option: {self.type} for {self.long}')
def set_flag_value(self, cmd: str = 'cmd') -> str:
func = go_getter_map[self.type]
ans = f'{self.go_var_name}_temp, err := {cmd}.Flags().{func}("{self.long}")\n if err != nil {{ return err }}'
ans += f'\noptions_{self.cmd_name}.{self.go_var_name} = {self.go_var_name}_temp'
return ans
json_field_types: Dict[str, str] = { json_field_types: Dict[str, str] = {
'bool': 'bool', 'str': 'string', 'list.str': '[]string', 'dict.str': 'map[string]string', 'float': 'float64', 'int': 'int', 'bool': 'bool', 'str': 'string', 'list.str': '[]string', 'dict.str': 'map[string]string', 'float': 'float64', 'int': 'int',
'scroll_amount': '[2]interface{}', 'spacing': 'interface{}', 'colors': 'interface{}', 'scroll_amount': '[2]interface{}', 'spacing': 'interface{}', 'colors': 'interface{}',
@ -177,7 +101,7 @@ def build_go_code(name: str, cmd: RemoteCommand, seq: OptionSpecSeq, template: s
for x in seq: for x in seq:
if isinstance(x, str): if isinstance(x, str):
continue continue
o = Option(name, x) o = GoOption(name, x)
if o.aliases: if o.aliases:
alias_map[o.long] = tuple(o.aliases) alias_map[o.long] = tuple(o.aliases)
a(o.to_flag_definition()) a(o.to_flag_definition())

View File

@ -36,6 +36,84 @@ class OptionDict(TypedDict):
completion: Dict[str, str] completion: Dict[str, str]
def serialize_as_go_string(x: str) -> str:
return x.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')
go_type_map = {'bool-set': 'bool', 'bool-reset': 'bool', 'int': 'int', 'float': 'float64', '': 'string', 'list': '[]string', 'choices': 'string'}
go_getter_map = {
'bool-set': 'GetBool', 'bool-reset': 'GetBool', 'int': 'GetInt', 'float': 'GetFloat64', '': 'GetString',
'list': 'GetStringArray', 'choices': 'GetString'
}
class GoOption:
def __init__(self, cmd_name: str, x: OptionDict) -> None:
self.cmd_name = cmd_name
flags = sorted(x['aliases'], key=len)
short = ''
self.aliases = []
if len(flags) > 1 and not flags[0].startswith("--"):
short = flags[0][1:]
del flags[0]
self.short, self.long = short, x['name'].replace('_', '-')
for f in flags:
q = f[2:]
if q != self.long:
self.aliases.append(q)
self.usage = serialize_as_go_string(x['help'].strip())
self.type = x['type']
self.dest = x['dest']
self.default = x['default']
self.obj_dict = x
self.go_type = go_type_map[self.type]
self.go_var_name = self.long.replace('-', '_')
if self.go_var_name == 'type':
self.go_var_name += '_'
def to_flag_definition(self, base: str = 'ans.Flags()') -> str:
if self.type.startswith('bool-'):
defval = 'false' if self.type == 'bool-set' else 'true'
if self.short:
return f'{base}.BoolP("{self.long}", "{self.short}", {defval}, "{self.usage}")'
return f'{base}.Bool("{self.long}", {defval}, "{self.usage}")'
elif not self.type:
defval = f'''"{serialize_as_go_string(self.default or '')}"'''
if self.short:
return f'{base}.StringP("{self.long}", "{self.short}", {defval}, "{self.usage}")'
return f'{base}.String("{self.long}", {defval}, "{self.usage}")'
elif self.type == 'int':
if self.short:
return f'{base}.IntP("{self.long}", "{self.short}", {self.default or 0}, "{self.usage}")'
return f'{base}.Int("{self.long}", {self.default or 0}, "{self.usage}")'
elif self.type == 'float':
if self.short:
return f'{base}.Float64P("{self.long}", "{self.short}", {self.default or 0}, "{self.usage}")'
return f'{base}.Float64("{self.long}", {self.default or 0}, "{self.usage}")'
elif self.type == 'list':
defval = f'[]string{{"{serialize_as_go_string(self.default)}"}}' if self.default else '[]string{}'
if self.short:
return f'{base}.StringArrayP("{self.long}", "{self.short}", {defval}, "{self.usage}")'
return f'{base}.StringArray("{self.long}", {defval}, "{self.usage}")'
elif self.type == 'choices':
choices = sorted(self.obj_dict['choices'])
choices.remove(self.default or '')
choices.insert(0, self.default or '')
cx = ', '.join(f'"{serialize_as_go_string(x)}"' for x in choices)
if self.short:
return f'cli.ChoicesP({base}, "{self.long}", "{self.short}", "{self.usage}", {cx})'
return f'cli.Choices({base}, "{self.long}", "{self.usage}", {cx})'
else:
raise TypeError(f'Unknown type of CLI option: {self.type} for {self.long}')
def set_flag_value(self, cmd: str = 'cmd') -> str:
func = go_getter_map[self.type]
ans = f'{self.go_var_name}_temp, err := {cmd}.Flags().{func}("{self.long}")\n if err != nil {{ return err }}'
ans += f'\noptions_{self.cmd_name}.{self.go_var_name} = {self.go_var_name}_temp'
return ans
CONFIG_HELP = '''\ CONFIG_HELP = '''\
Specify a path to the configuration file(s) to use. All configuration files are Specify a path to the configuration file(s) to use. All configuration files are
merged onto the builtin :file:`{conf_name}.conf`, overriding the builtin values. merged onto the builtin :file:`{conf_name}.conf`, overriding the builtin values.