Automap a bunch of json fields from identically named options

This commit is contained in:
Kovid Goyal 2022-08-29 12:10:23 +05:30
parent b33a684357
commit ef71b071db
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
11 changed files with 42 additions and 28 deletions

View file

@ -4,13 +4,15 @@
import io
import json
import os
import sys
from contextlib import contextmanager, suppress
from typing import Dict, Iterator, List, Tuple, Union
import kitty.constants as kc
from kittens.tui.operations import Mode
from kitty.cli import (
GoOption, OptionSpecSeq, parse_option_spec, serialize_as_go_string
GoOption, OptionSpecSeq, go_options_for_seq, parse_option_spec,
serialize_as_go_string
)
from kitty.key_encoding import config_mod_map
from kitty.key_names import (
@ -98,24 +100,34 @@ def build_go_code(name: str, cmd: RemoteCommand, seq: OptionSpecSeq, template: s
alias_map = {}
od: List[str] = []
ov: List[str] = []
for x in seq:
if isinstance(x, str):
continue
o = GoOption(name, x)
option_map: Dict[str, GoOption] = {}
for o in go_options_for_seq(seq):
field_dest = o.go_var_name.rstrip('_')
option_map[field_dest] = o
if o.aliases:
alias_map[o.long] = tuple(o.aliases)
a(o.to_flag_definition())
if o.dest in ('no_response', 'response_timeout'):
continue
od.append(f'{o.go_var_name} {o.go_type}')
ov.append(o.set_flag_value())
ov.append(o.set_flag_value(f'options_{name}'))
jd: List[str] = []
json_fields = []
for line in cmd.protocol_spec.splitlines():
line = line.strip()
if ':' not in line:
continue
f = JSONField(line)
json_fields.append(f)
jd.append(f.go_declaration())
jc: List[str] = []
for field in json_fields:
if field.field in option_map:
o = option_map[field.field]
jc.append(f'payload.{field.struct_field_name} = options_{name}.{o.go_var_name}')
else:
print(f'Cant map field: {field.field} for cmd: {name}', file=sys.stderr)
continue
ans = replace(
template,
@ -129,6 +141,7 @@ def build_go_code(name: str, cmd: RemoteCommand, seq: OptionSpecSeq, template: s
OPTIONS_DECLARATION_CODE='\n'.join(od),
SET_OPTION_VALUES_CODE='\n'.join(ov),
JSON_DECLARATION_CODE='\n'.join(jd),
JSON_INIT_CODE='\n'.join(jc),
STRING_RESPONSE_IS_ERROR='true' if cmd.string_return_is_error else 'false',
)
return ans

View file

@ -49,8 +49,7 @@ def serialize_as_go_string(x: str) -> str:
class GoOption:
def __init__(self, cmd_name: str, x: OptionDict) -> None:
self.cmd_name = cmd_name
def __init__(self, x: OptionDict) -> None:
flags = sorted(x['aliases'], key=len)
short = ''
self.aliases = []
@ -107,13 +106,19 @@ def to_flag_definition(self, base: str = 'ans.Flags()') -> str:
else:
raise TypeError(f'Unknown type of CLI option: {self.type} for {self.long}')
def set_flag_value(self, cmd: str = 'cmd') -> str:
def set_flag_value(self, struct_name: str, 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'
ans += f'\n{struct_name}.{self.go_var_name} = {self.go_var_name}_temp'
return ans
def go_options_for_seq(seq: 'OptionSpecSeq') -> Iterator[GoOption]:
for x in seq:
if not isinstance(x, str):
yield GoOption(x)
CONFIG_HELP = '''\
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.

View file

@ -17,7 +17,6 @@ class CloseTab(RemoteCommand):
protocol_spec = __doc__ = '''
match/str: Which tab to close
no_response/bool: Boolean indicating whether to wait for a response
self/bool: Boolean indicating whether to close the tab of the window the command is run in
ignore_no_match/bool: Boolean indicating whether no matches should be ignored or return an error
'''

View file

@ -16,7 +16,6 @@
class CloseWindow(RemoteCommand):
protocol_spec = __doc__ = '''
match/str: Which window to close
no_response/bool: Boolean indicating whether to wait for a response
self/bool: Boolean indicating whether to close the window the command is run in
ignore_no_match/bool: Boolean indicating whether no matches should be ignored or return an error
'''

View file

@ -60,6 +60,7 @@ class GetText(RemoteCommand):
--clear-selection
type=bool-set
Clear the selection in the matched window, if any.

View file

@ -42,7 +42,6 @@ class Launch(RemoteCommand):
stdin_add_formatting/bool: Boolean indicating whether to add formatting codes to stdin
stdin_add_line_wrap_markers/bool: Boolean indicating whether to add line wrap markers to stdin
spacing/list.str: A list of spacing specifications, see the docs for the set-spacing command
no_response/bool: Boolean indicating whether to send back the window id
marker/str: Specification for marker for new window, for example: "text 1 ERROR"
logo/str: Path to window logo
logo_position/str: Window logo position as string or empty string to use default

View file

@ -23,7 +23,6 @@ class NewWindow(RemoteCommand):
window_type/choices.kitty.os: One of :code:`kitty` or :code:`os`
new_tab/bool: Boolean indicating whether to open a new tab
tab_title/str: Title for the new tab
no_response/bool: Boolean indicating whether to send back the window id
'''
short_desc = 'Open new window'

View file

@ -21,7 +21,6 @@ class ScrollWindow(RemoteCommand):
And the second item being either 'p' for pages or 'l' for lines or 'u'
for unscrolling by lines.
match/str: The window to scroll
no_response/bool: Boolean indicating whether to wait for a response
'''
short_desc = 'Scroll the specified windows'

View file

@ -17,7 +17,6 @@ class SignalChild(RemoteCommand):
protocol_spec = __doc__ = '''
signals/list.str: The signals, a list of names, such as :code:`SIGTERM`, :code:`SIGKILL`, :code:`SIGUSR1`, etc.
match/str: Which windows to send the signals to
no_response/bool: Boolean indicating whether to wait for a response
'''
short_desc = 'Send a signal to the foreground process in the specified windows'

View file

@ -26,9 +26,10 @@ type CMD_NAME_json_type struct {
JSON_DECLARATION_CODE
}
var CMD_NAME_json CMD_NAME_json_type
func create_payload_CMD_NAME(io_data *rc_io_data, args []string) (err error) {
func create_payload_CMD_NAME(io_data *rc_io_data, flags *pflag.FlagSet, args []string) (err error) {
payload := CMD_NAME_json_type{}
JSON_INIT_CODE
io_data.rc.Payload = payload
return
}
@ -70,7 +71,7 @@ func run_CMD_NAME(cmd *cobra.Command, args []string) (err error) {
timeout: time.Duration(timeout * float64(time.Second)),
string_response_is_err: STRING_RESPONSE_IS_ERROR,
}
err = create_payload_CMD_NAME(&io_data, args)
err = create_payload_CMD_NAME(&io_data, cmd.Flags(), args)
if err != nil {
return err
}

View file

@ -3,14 +3,14 @@
package utils
type RemoteControlCmd struct {
Cmd string `json:"cmd"`
Version [3]int `json:"version"`
NoResponse bool `json:"no_response,omitempty"`
Payload *interface{} `json:"payload,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
Password string `json:"password,omitempty"`
Async string `json:"async,omitempty"`
CancelAsync bool `json:"cancel_async,omitempty"`
Cmd string `json:"cmd"`
Version [3]int `json:"version"`
NoResponse bool `json:"no_response,omitempty"`
Payload interface{} `json:"payload,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
Password string `json:"password,omitempty"`
Async string `json:"async,omitempty"`
CancelAsync bool `json:"cancel_async,omitempty"`
}
type EncryptedRemoteControlCmd struct {