Work on conversion of args parsing to go code
This commit is contained in:
parent
441e4edfb2
commit
79c8862d4c
@ -113,12 +113,14 @@ def build_go_code(name: str, cmd: RemoteCommand, seq: OptionSpecSeq, template: s
|
|||||||
ov.append(o.set_flag_value(f'options_{name}'))
|
ov.append(o.set_flag_value(f'options_{name}'))
|
||||||
jd: List[str] = []
|
jd: List[str] = []
|
||||||
json_fields = []
|
json_fields = []
|
||||||
|
field_types: Dict[str, str] = {}
|
||||||
for line in cmd.protocol_spec.splitlines():
|
for line in cmd.protocol_spec.splitlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if ':' not in line:
|
if ':' not in line:
|
||||||
continue
|
continue
|
||||||
f = JSONField(line)
|
f = JSONField(line)
|
||||||
json_fields.append(f)
|
json_fields.append(f)
|
||||||
|
field_types[f.field] = f.field_type
|
||||||
jd.append(f.go_declaration())
|
jd.append(f.go_declaration())
|
||||||
jc: List[str] = []
|
jc: List[str] = []
|
||||||
for field in json_fields:
|
for field in json_fields:
|
||||||
@ -128,7 +130,16 @@ def build_go_code(name: str, cmd: RemoteCommand, seq: OptionSpecSeq, template: s
|
|||||||
else:
|
else:
|
||||||
print(f'Cant map field: {field.field} for cmd: {name}', file=sys.stderr)
|
print(f'Cant map field: {field.field} for cmd: {name}', file=sys.stderr)
|
||||||
continue
|
continue
|
||||||
|
try:
|
||||||
|
jc.extend(cmd.args.as_go_code(name, field_types))
|
||||||
|
except TypeError:
|
||||||
|
print(f'Cant parse args for cmd: {name}', file=sys.stderr)
|
||||||
|
|
||||||
|
print('TODO: test set_window_logo, send_text, env, scroll_window', file=sys.stderr)
|
||||||
|
|
||||||
|
argspec = cmd.args.spec
|
||||||
|
if argspec:
|
||||||
|
argspec = ' ' + argspec
|
||||||
ans = replace(
|
ans = replace(
|
||||||
template,
|
template,
|
||||||
CMD_NAME=name, __FILE__=__file__, CLI_NAME=name.replace('_', '-'),
|
CMD_NAME=name, __FILE__=__file__, CLI_NAME=name.replace('_', '-'),
|
||||||
@ -141,7 +152,7 @@ def build_go_code(name: str, cmd: RemoteCommand, seq: OptionSpecSeq, template: s
|
|||||||
OPTIONS_DECLARATION_CODE='\n'.join(od),
|
OPTIONS_DECLARATION_CODE='\n'.join(od),
|
||||||
SET_OPTION_VALUES_CODE='\n'.join(ov),
|
SET_OPTION_VALUES_CODE='\n'.join(ov),
|
||||||
JSON_DECLARATION_CODE='\n'.join(jd),
|
JSON_DECLARATION_CODE='\n'.join(jd),
|
||||||
JSON_INIT_CODE='\n'.join(jc),
|
JSON_INIT_CODE='\n'.join(jc), ARGSPEC=argspec,
|
||||||
STRING_RESPONSE_IS_ERROR='true' if cmd.string_return_is_error else 'false',
|
STRING_RESPONSE_IS_ERROR='true' if cmd.string_return_is_error else 'false',
|
||||||
)
|
)
|
||||||
return ans
|
return ans
|
||||||
|
|||||||
@ -492,7 +492,7 @@ def global_options_for_remote_cmd() -> Dict[str, OptionDict]:
|
|||||||
def complete_remote_command(ans: Completions, cmd_name: str, words: Sequence[str], new_word: bool) -> None:
|
def complete_remote_command(ans: Completions, cmd_name: str, words: Sequence[str], new_word: bool) -> None:
|
||||||
aliases, alias_map = options_for_cmd(cmd_name)
|
aliases, alias_map = options_for_cmd(cmd_name)
|
||||||
try:
|
try:
|
||||||
args_completion = command_for_name(cmd_name).args_completion
|
args_completion = command_for_name(cmd_name).args.completion
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
args_completer: CompleteArgsFunc = basic_option_arg_completer
|
args_completer: CompleteArgsFunc = basic_option_arg_completer
|
||||||
|
|||||||
@ -2,9 +2,10 @@
|
|||||||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING, Any, Callable, Dict, FrozenSet, Iterable, Iterator, List,
|
TYPE_CHECKING, Any, Callable, Dict, FrozenSet, Iterable, Iterator, List,
|
||||||
NoReturn, Optional, Tuple, Type, Union, cast
|
NoReturn, Optional, Set, Tuple, Type, Union, cast
|
||||||
)
|
)
|
||||||
|
|
||||||
from kitty.cli import get_defaults_from_seq, parse_args, parse_option_spec
|
from kitty.cli import get_defaults_from_seq, parse_args, parse_option_spec
|
||||||
@ -160,27 +161,98 @@ class AsyncResponder:
|
|||||||
send_response_to_client(error=error, peer_id=self.peer_id, window_id=self.window_id, async_id=self.async_id)
|
send_response_to_client(error=error, peer_id=self.peer_id, window_id=self.window_id, async_id=self.async_id)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ArgsHandling:
|
||||||
|
|
||||||
|
json_field: str = ''
|
||||||
|
count: Optional[int] = None
|
||||||
|
spec: str = ''
|
||||||
|
completion: Optional[Dict[str, Tuple[str, Union[Callable[[], Iterable[str]], Tuple[str, ...]]]]] = None
|
||||||
|
value_if_unspecified: Tuple[str, ...] = ()
|
||||||
|
minimum_count: int = -1
|
||||||
|
first_rest: Optional[Tuple[str, str]] = None
|
||||||
|
special_parse: str = ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def args_count(self) -> Optional[int]:
|
||||||
|
if not self.spec:
|
||||||
|
return 0
|
||||||
|
return self.count
|
||||||
|
|
||||||
|
def as_go_code(self, cmd_name: str, field_types: Dict[str, str], handled_fields: Set[str]) -> Iterator[str]:
|
||||||
|
c = self.args_count
|
||||||
|
if c == 0:
|
||||||
|
yield f'if len(args) != 0 {{ return fmt.Errorf("%s", "Unknown extra argument(s) supplied to {cmd_name}") }}'
|
||||||
|
return
|
||||||
|
if c is not None:
|
||||||
|
yield f'if len(args) != {c} {{ return fmt.Errorf("%s", "Must specify exactly {c} argument(s) for {cmd_name}") }}'
|
||||||
|
if self.value_if_unspecified:
|
||||||
|
yield 'if len(args) == 0 {'
|
||||||
|
for x in self.value_if_unspecified:
|
||||||
|
yield f'args = append(args, "{x}")'
|
||||||
|
yield '}'
|
||||||
|
if self.minimum_count > -1:
|
||||||
|
yield f'if len(args) < {self.minimum_count} {{ return fmt.Errorf("%s", Must specify at least {self.minimum_count} arguments to {cmd_name}) }}'
|
||||||
|
if self.json_field:
|
||||||
|
jf = self.json_field
|
||||||
|
dest = f'payload.{jf.capitalize()}'
|
||||||
|
jt = field_types[jf]
|
||||||
|
if self.first_rest:
|
||||||
|
yield f'payload.{self.first_rest[0].capitalize()} = args[0]'
|
||||||
|
yield f'payload.{self.first_rest[1].capitalize()} = args[1:]'
|
||||||
|
handled_fields.add(self.first_rest[0])
|
||||||
|
handled_fields.add(self.first_rest[1])
|
||||||
|
return
|
||||||
|
handled_fields.add(self.json_field)
|
||||||
|
if self.special_parse:
|
||||||
|
if self.special_parse.startswith('!'):
|
||||||
|
yield f'io_data.multiple_payload_generator, err = {self.special_parse[1:]}'
|
||||||
|
else:
|
||||||
|
yield f'{dest}, err = {self.special_parse}'
|
||||||
|
yield 'if err != nil { return err }'
|
||||||
|
return
|
||||||
|
if jt == 'list.str':
|
||||||
|
yield f'{dest} = args'
|
||||||
|
return
|
||||||
|
if jt == 'str':
|
||||||
|
if c == 1:
|
||||||
|
yield f'{dest} = args[0]'
|
||||||
|
else:
|
||||||
|
yield f'{dest} = strings.Join(args, " ")'
|
||||||
|
return
|
||||||
|
if jt.startswith('choices.'):
|
||||||
|
yield f'if len(args) != 1 {{ return fmt.Errorf("%s", "Must specify exactly 1 argument for {cmd_name}") }}'
|
||||||
|
choices = ", ".join((f'"{x}"' for x in jt.split('.')[1:]))
|
||||||
|
yield 'switch(args[0]) {'
|
||||||
|
yield f'case {choices}:\n\t{dest} = args[0]'
|
||||||
|
yield f'default: return fmt.Errorf("%s is not a valid choice. Allowed values: %s", args[0], `{choices}`)'
|
||||||
|
yield '}'
|
||||||
|
return
|
||||||
|
if jt == 'dict.str':
|
||||||
|
yield f'{dest} = parse_key_val_args(args)'
|
||||||
|
raise TypeError(f'Unknown args handling for cmd: {cmd_name}')
|
||||||
|
|
||||||
|
|
||||||
class RemoteCommand:
|
class RemoteCommand:
|
||||||
|
Args = ArgsHandling
|
||||||
|
|
||||||
name: str = ''
|
name: str = ''
|
||||||
short_desc: str = ''
|
short_desc: str = ''
|
||||||
desc: str = ''
|
desc: str = ''
|
||||||
argspec: str = '...'
|
args: ArgsHandling = ArgsHandling()
|
||||||
options_spec: Optional[str] = None
|
options_spec: Optional[str] = None
|
||||||
no_response: bool = False
|
no_response: bool = False
|
||||||
response_timeout: float = 10. # seconds
|
response_timeout: float = 10. # seconds
|
||||||
string_return_is_error: bool = False
|
string_return_is_error: bool = False
|
||||||
args_count: Optional[int] = None
|
|
||||||
args_completion: Optional[Dict[str, Tuple[str, Union[Callable[[], Iterable[str]], Tuple[str, ...]]]]] = None
|
|
||||||
defaults: Optional[Dict[str, Any]] = None
|
defaults: Optional[Dict[str, Any]] = None
|
||||||
is_asynchronous: bool = False
|
is_asynchronous: bool = False
|
||||||
options_class: Type[RCOptions] = RCOptions
|
options_class: Type[RCOptions] = RCOptions
|
||||||
protocol_spec: str = ''
|
protocol_spec: str = ''
|
||||||
|
argspec = args_count = args_completion = ArgsHandling()
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.desc = self.desc or self.short_desc
|
self.desc = self.desc or self.short_desc
|
||||||
self.name = self.__class__.__module__.split('.')[-1].replace('_', '-')
|
self.name = self.__class__.__module__.split('.')[-1].replace('_', '-')
|
||||||
self.args_count = 0 if not self.argspec else self.args_count
|
|
||||||
|
|
||||||
def fatal(self, msg: str) -> NoReturn:
|
def fatal(self, msg: str) -> NoReturn:
|
||||||
if running_in_kitty():
|
if running_in_kitty():
|
||||||
@ -259,21 +331,21 @@ class RemoteCommand:
|
|||||||
|
|
||||||
|
|
||||||
def cli_params_for(command: RemoteCommand) -> Tuple[Callable[[], str], str, str, str]:
|
def cli_params_for(command: RemoteCommand) -> Tuple[Callable[[], str], str, str, str]:
|
||||||
return (command.options_spec or '\n').format, command.argspec, command.desc, f'{appname} @ {command.name}'
|
return (command.options_spec or '\n').format, command.args.spec, command.desc, f'{appname} @ {command.name}'
|
||||||
|
|
||||||
|
|
||||||
def parse_subcommand_cli(command: RemoteCommand, args: ArgsType) -> Tuple[Any, ArgsType]:
|
def parse_subcommand_cli(command: RemoteCommand, args: ArgsType) -> Tuple[Any, ArgsType]:
|
||||||
opts, items = parse_args(args[1:], *cli_params_for(command), result_class=command.options_class)
|
opts, items = parse_args(args[1:], *cli_params_for(command), result_class=command.options_class)
|
||||||
if command.args_count is not None and command.args_count != len(items):
|
if command.args.args_count is not None and command.args.args_count != len(items):
|
||||||
if command.args_count == 0:
|
if command.args.args_count == 0:
|
||||||
raise SystemExit(f'Unknown extra argument(s) supplied to {command.name}')
|
raise SystemExit(f'Unknown extra argument(s) supplied to {command.name}')
|
||||||
raise SystemExit(f'Must specify exactly {command.args_count} argument(s) for {command.name}')
|
raise SystemExit(f'Must specify exactly {command.args.args_count} argument(s) for {command.name}')
|
||||||
return opts, items
|
return opts, items
|
||||||
|
|
||||||
|
|
||||||
def display_subcommand_help(func: RemoteCommand) -> None:
|
def display_subcommand_help(func: RemoteCommand) -> None:
|
||||||
with suppress(SystemExit):
|
with suppress(SystemExit):
|
||||||
parse_args(['--help'], (func.options_spec or '\n').format, func.argspec, func.desc, func.name)
|
parse_args(['--help'], (func.options_spec or '\n').format, func.args.spec, func.desc, func.name)
|
||||||
|
|
||||||
|
|
||||||
def command_for_name(cmd_name: str) -> RemoteCommand:
|
def command_for_name(cmd_name: str) -> RemoteCommand:
|
||||||
|
|||||||
@ -46,7 +46,6 @@ Close the tab of the window this command is run in, rather than the active tab.
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Do not return an error if no tabs are matched to be closed.
|
Do not return an error if no tabs are matched to be closed.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'self': opts.self, 'ignore_no_match': opts.ignore_no_match}
|
return {'match': opts.match, 'self': opts.self, 'ignore_no_match': opts.ignore_no_match}
|
||||||
|
|||||||
@ -38,7 +38,6 @@ Close the window this command is run in, rather than the active window.
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Do not return an error if no windows are matched to be closed.
|
Do not return an error if no windows are matched to be closed.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'self': opts.self, 'ignore_no_match': opts.ignore_no_match}
|
return {'match': opts.match, 'self': opts.self, 'ignore_no_match': opts.ignore_no_match}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class CreateMarker(RemoteCommand):
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Apply marker to the window this command is run in, rather than the active window.
|
Apply marker to the window this command is run in, rather than the active window.
|
||||||
'''
|
'''
|
||||||
argspec = 'MARKER SPECIFICATION'
|
args = RemoteCommand.Args(spec='MARKER SPECIFICATION', json_field='marker_spec', minimum_count=2)
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
|
|||||||
@ -30,7 +30,6 @@ class DetachTab(RemoteCommand):
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Detach the tab this command is run in, rather than the active tab.
|
Detach the tab this command is run in, rather than the active tab.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'target_tab': opts.target_tab, 'self': opts.self}
|
return {'match': opts.match, 'target_tab': opts.target_tab, 'self': opts.self}
|
||||||
|
|||||||
@ -36,7 +36,6 @@ class DetachWindow(RemoteCommand):
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Detach the window this command is run in, rather than the active window.
|
Detach the window this command is run in, rather than the active window.
|
||||||
''')
|
''')
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'target_tab': opts.target_tab, 'self': opts.self}
|
return {'match': opts.match, 'target_tab': opts.target_tab, 'self': opts.self}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ By default, ligatures are only affected in the active window. This option will
|
|||||||
cause ligatures to be changed in all windows.
|
cause ligatures to be changed in all windows.
|
||||||
|
|
||||||
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
|
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
|
||||||
argspec = 'STRATEGY'
|
args = RemoteCommand.Args(spec='STRATEGY', count=1, json_field='strategy')
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
if not args:
|
if not args:
|
||||||
|
|||||||
@ -12,24 +12,27 @@ from .base import (
|
|||||||
class Env(RemoteCommand):
|
class Env(RemoteCommand):
|
||||||
|
|
||||||
protocol_spec = __doc__ = '''
|
protocol_spec = __doc__ = '''
|
||||||
env+/dict.str: Dictionary of environment variables to values. Empty values cause the variable to be removed.
|
env+/dict.str: Dictionary of environment variables to values. When a env var ends with = it is removed from the environment.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
short_desc = 'Change environment variables seen by future children'
|
short_desc = 'Change environment variables seen by future children'
|
||||||
desc = (
|
desc = (
|
||||||
'Change the environment variables that will be seen in newly launched windows.'
|
'Change the environment variables that will be seen in newly launched windows.'
|
||||||
' Similar to the :opt:`env` option in :file:`kitty.conf`, but affects running kitty instances.'
|
' Similar to the :opt:`env` option in :file:`kitty.conf`, but affects running kitty instances.'
|
||||||
' Empty values cause the environment variable to be removed.'
|
' If no = is present, the variable is removed from the environment.'
|
||||||
)
|
)
|
||||||
argspec = 'env_var1=val env_var2=val ...'
|
args = RemoteCommand.Args(spec='env_var1=val env_var2=val ...', minimum_count=1, json_field='env')
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType:
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
self.fatal('Must specify at least one env var to set')
|
self.fatal('Must specify at least one env var to set')
|
||||||
env = {}
|
env = {}
|
||||||
for x in args:
|
for x in args:
|
||||||
|
if '=' in x:
|
||||||
key, val = x.split('=', 1)
|
key, val = x.split('=', 1)
|
||||||
env[key] = val
|
env[key] = val
|
||||||
|
else:
|
||||||
|
env[x + '='] = ''
|
||||||
return {'env': env}
|
return {'env': env}
|
||||||
|
|
||||||
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
|
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
|
||||||
@ -38,10 +41,10 @@ class Env(RemoteCommand):
|
|||||||
new_env = payload_get('env') or {}
|
new_env = payload_get('env') or {}
|
||||||
env = default_env().copy()
|
env = default_env().copy()
|
||||||
for k, v in new_env.items():
|
for k, v in new_env.items():
|
||||||
if v:
|
if k.endswith('='):
|
||||||
env[k] = expandvars(v, env)
|
|
||||||
else:
|
|
||||||
env.pop(k, None)
|
env.pop(k, None)
|
||||||
|
else:
|
||||||
|
env[k] = expandvars(v or '', env)
|
||||||
set_default_env(env)
|
set_default_env(env)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,6 @@ default=false
|
|||||||
Don't wait for a response indicating the success of the action. Note that
|
Don't wait for a response indicating the success of the action. Note that
|
||||||
using this option means that you will not be notified of failures.
|
using this option means that you will not be notified of failures.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'no_response': opts.no_response}
|
return {'match': opts.match, 'no_response': opts.no_response}
|
||||||
|
|||||||
@ -23,7 +23,6 @@ class FocusWindow(RemoteCommand):
|
|||||||
|
|
||||||
short_desc = 'Focus the specified window'
|
short_desc = 'Focus the specified window'
|
||||||
desc = 'Focus the specified window, if no window is specified, focus the window this command is run inside.'
|
desc = 'Focus the specified window, if no window is specified, focus the window this command is run inside.'
|
||||||
argspec = ''
|
|
||||||
options_spec = MATCH_WINDOW_OPTION + '''\n\n
|
options_spec = MATCH_WINDOW_OPTION + '''\n\n
|
||||||
--no-response
|
--no-response
|
||||||
type=bool-set
|
type=bool-set
|
||||||
@ -33,7 +32,7 @@ the command will exit with a success code.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'no_response': opts.no_response}
|
return {'match': opts.match}
|
||||||
|
|
||||||
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
|
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
|
||||||
for window in self.windows_for_match_payload(boss, window, payload_get):
|
for window in self.windows_for_match_payload(boss, window, payload_get):
|
||||||
|
|||||||
@ -68,7 +68,6 @@ Clear the selection in the matched window, if any.
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Get text from the window this command is run in, rather than the active window.
|
Get text from the window this command is run in, rather than the active window.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -30,9 +30,7 @@ class GotoLayout(RemoteCommand):
|
|||||||
' You can use special match value :code:`all` to set the layout in all tabs.'
|
' You can use special match value :code:`all` to set the layout in all tabs.'
|
||||||
)
|
)
|
||||||
options_spec = MATCH_TAB_OPTION
|
options_spec = MATCH_TAB_OPTION
|
||||||
argspec = 'LAYOUT_NAME'
|
args = RemoteCommand.Args(spec='LAYOUT_NAME', count=1, completion={'names': ('Layouts', layout_names)}, json_field='layout')
|
||||||
args_count = 1
|
|
||||||
args_completion = {'names': ('Layouts', layout_names)}
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class Kitten(RemoteCommand):
|
|||||||
' is printed out to stdout.'
|
' is printed out to stdout.'
|
||||||
)
|
)
|
||||||
options_spec = MATCH_WINDOW_OPTION
|
options_spec = MATCH_WINDOW_OPTION
|
||||||
argspec = 'kitten_name'
|
args = RemoteCommand.Args(spec='kitten_name', json_field='kitten', minimum_count=1, first_rest=('kitten', 'args'))
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
|
|||||||
@ -67,7 +67,7 @@ type=bool-set
|
|||||||
If specified the tab containing the window this command is run in is used
|
If specified the tab containing the window this command is run in is used
|
||||||
instead of the active tab
|
instead of the active tab
|
||||||
''' + '\n\n' + launch_options_spec().replace(':option:`launch', ':option:`kitty @ launch')
|
''' + '\n\n' + launch_options_spec().replace(':option:`launch', ':option:`kitty @ launch')
|
||||||
argspec = '[CMD ...]'
|
args = RemoteCommand.Args(spec='[CMD ...]', json_field='args')
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
ans = {'args': args or []}
|
ans = {'args': args or []}
|
||||||
|
|||||||
@ -36,8 +36,6 @@ type=bool-set
|
|||||||
Show all environment variables in output, not just differing ones.
|
Show all environment variables in output, not just differing ones.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'all_env_vars': opts.all_env_vars}
|
return {'all_env_vars': opts.all_env_vars}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,7 @@ Don't wait for a response giving the id of the newly opened window. Note that
|
|||||||
using this option means that you will not be notified of failures and that
|
using this option means that you will not be notified of failures and that
|
||||||
the id of the new window will not be printed out.
|
the id of the new window will not be printed out.
|
||||||
'''
|
'''
|
||||||
argspec = '[CMD ...]'
|
args = RemoteCommand.Args(spec='[CMD ...]', json_field='args')
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
ans = {'args': args or [], 'type': 'window'}
|
ans = {'args': args or [], 'type': 'window'}
|
||||||
|
|||||||
@ -26,7 +26,6 @@ class RemoveMarker(RemoteCommand):
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Apply marker to the window this command is run in, rather than the active window.
|
Apply marker to the window this command is run in, rather than the active window.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {'match': opts.match, 'self': opts.self}
|
return {'match': opts.match, 'self': opts.self}
|
||||||
|
|||||||
@ -71,7 +71,6 @@ default=false
|
|||||||
Don't wait for a response indicating the success of the action. Note that
|
Don't wait for a response indicating the success of the action. Note that
|
||||||
using this option means that you will not be notified of failures.
|
using this option means that you will not be notified of failures.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -46,7 +46,6 @@ The special value :code:`reset` will reset the layout to its default configurati
|
|||||||
type=bool-set
|
type=bool-set
|
||||||
Resize the window this command is run in, rather than the active window.
|
Resize the window this command is run in, rather than the active window.
|
||||||
'''
|
'''
|
||||||
argspec = ''
|
|
||||||
string_return_is_error = True
|
string_return_is_error = True
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
|
|||||||
@ -31,7 +31,6 @@ class ScrollWindow(RemoteCommand):
|
|||||||
' will scroll up 2 pages and :code:`0.5p`will scroll down half page. :code:`3u` will *unscroll* by 3 lines, which means that 3 lines will move from the'
|
' will scroll up 2 pages and :code:`0.5p`will scroll down half page. :code:`3u` will *unscroll* by 3 lines, which means that 3 lines will move from the'
|
||||||
' scrollback buffer onto the top of the screen.'
|
' scrollback buffer onto the top of the screen.'
|
||||||
)
|
)
|
||||||
argspec = 'SCROLL_AMOUNT'
|
|
||||||
options_spec = MATCH_WINDOW_OPTION + '''\n
|
options_spec = MATCH_WINDOW_OPTION + '''\n
|
||||||
--no-response
|
--no-response
|
||||||
type=bool-set
|
type=bool-set
|
||||||
@ -39,6 +38,7 @@ default=false
|
|||||||
Don't wait for a response indicating the success of the action. Note that
|
Don't wait for a response indicating the success of the action. Note that
|
||||||
using this option means that you will not be notified of failures.
|
using this option means that you will not be notified of failures.
|
||||||
'''
|
'''
|
||||||
|
args = RemoteCommand.Args(spec='SCROLL_AMOUNT', count=1, special_parse='parse_scroll_amount(args[0])', json_field='amount')
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
|
|||||||
@ -89,8 +89,7 @@ type=bool-set
|
|||||||
Restore all colors to the values they had at kitty startup. Note that if you specify
|
Restore all colors to the values they had at kitty startup. Note that if you specify
|
||||||
this option, any color arguments are ignored and :option:`kitty @ set-colors --configured` and :option:`kitty @ set-colors --all` are implied.
|
this option, any color arguments are ignored and :option:`kitty @ set-colors --configured` and :option:`kitty @ set-colors --all` are implied.
|
||||||
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
|
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
|
||||||
argspec = 'COLOR_OR_FILE ...'
|
args = RemoteCommand.Args(spec='COLOR_OR_FILE ...', completion={'files': ('CONF files', ('*.conf',))})
|
||||||
args_completion = {'files': ('CONF files', ('*.conf',))}
|
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
final_colors: Dict[str, Optional[int]] = {}
|
final_colors: Dict[str, Optional[int]] = {}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class SetWindowLogo(RemoteCommand):
|
class SetWindowLogo(RemoteCommand):
|
||||||
protocol_spec = __doc__ = '''
|
protocol_spec = __doc__ = '''
|
||||||
data+/str: Chunk of at most 512 bytes of PNG data, base64 encoded. Must send an empty chunk to indicate end of image. \
|
data+/str: Chunk of PNG data, base64 encoded no more than 2048 bytes. Must send an empty chunk to indicate end of image. \
|
||||||
Or the special value :code:`-` to indicate image must be removed.
|
Or the special value :code:`-` to indicate image must be removed.
|
||||||
position/str: The logo position as a string, empty string means default
|
position/str: The logo position as a string, empty string means default
|
||||||
alpha/float: The logo alpha between :code:`0` and :code:`1`. :code:`-1` means use default
|
alpha/float: The logo alpha between :code:`0` and :code:`1`. :code:`-1` means use default
|
||||||
@ -59,9 +59,8 @@ default=false
|
|||||||
Don't wait for a response from kitty. This means that even if setting the image
|
Don't wait for a response from kitty. This means that even if setting the image
|
||||||
failed, the command will exit with a success code.
|
failed, the command will exit with a success code.
|
||||||
'''
|
'''
|
||||||
argspec = 'PATH_TO_PNG_IMAGE'
|
args = RemoteCommand.Args(spec='PATH_TO_PNG_IMAGE', count=1, json_field='data', special_parse='!read_window_logo(args[0])', completion={
|
||||||
args_count = 1
|
'files': ('PNG Images', ('*.png',))})
|
||||||
args_completion = {'files': ('PNG Images', ('*.png',))}
|
|
||||||
images_in_flight: Dict[str, IO[bytes]] = {}
|
images_in_flight: Dict[str, IO[bytes]] = {}
|
||||||
is_asynchronous = True
|
is_asynchronous = True
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ type=bool-set
|
|||||||
By default, the title will be permanently changed and programs running in the window will not be able to change it
|
By default, the title will be permanently changed and programs running in the window will not be able to change it
|
||||||
again. If you want to allow other programs to change it afterwards, use this option.
|
again. If you want to allow other programs to change it afterwards, use this option.
|
||||||
''' + '\n\n' + MATCH_WINDOW_OPTION
|
''' + '\n\n' + MATCH_WINDOW_OPTION
|
||||||
argspec = '[TITLE ...]'
|
args = RemoteCommand.Args(json_field='title', spec='[TITLE ...]')
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
ans = {'match': opts.match, 'temporary': opts.temporary}
|
ans = {'match': opts.match, 'temporary': opts.temporary}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
|||||||
class SignalChild(RemoteCommand):
|
class SignalChild(RemoteCommand):
|
||||||
|
|
||||||
protocol_spec = __doc__ = '''
|
protocol_spec = __doc__ = '''
|
||||||
signals/list.str: The signals, a list of names, such as :code:`SIGTERM`, :code:`SIGKILL`, :code:`SIGUSR1`, etc.
|
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
|
match/str: Which windows to send the signals to
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ default=false
|
|||||||
Don't wait for a response indicating the success of the action. Note that
|
Don't wait for a response indicating the success of the action. Note that
|
||||||
using this option means that you will not be notified of failures.
|
using this option means that you will not be notified of failures.
|
||||||
''' + '\n\n' + MATCH_WINDOW_OPTION
|
''' + '\n\n' + MATCH_WINDOW_OPTION
|
||||||
argspec = '[SIGNAL_NAME ...]'
|
args = RemoteCommand.Args(json_field='signals', spec='[SIGNAL_NAME ...]', value_if_unspecified=('SIGINT',))
|
||||||
|
|
||||||
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
# defaults to signal the window this command is run in
|
# defaults to signal the window this command is run in
|
||||||
|
|||||||
20
tools/cmd/at/env.go
Normal file
20
tools/cmd/at/env.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package at
|
||||||
|
|
||||||
|
import (
|
||||||
|
"kitty/tools/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parse_key_val_args(args []string) map[string]string {
|
||||||
|
ans := make(map[string]string, len(args))
|
||||||
|
for _, arg := range args {
|
||||||
|
key, value, found := utils.Cut(arg, "=")
|
||||||
|
if found {
|
||||||
|
ans[key] = value
|
||||||
|
} else {
|
||||||
|
ans[key+"="] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -75,18 +76,35 @@ type serializer_func func(rc *utils.RemoteControlCmd) ([]byte, error)
|
|||||||
type wrapped_serializer struct {
|
type wrapped_serializer struct {
|
||||||
state int
|
state int
|
||||||
serializer serializer_func
|
serializer serializer_func
|
||||||
|
all_payloads_done bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *wrapped_serializer) next(rc *utils.RemoteControlCmd) ([]byte, error) {
|
func (self *wrapped_serializer) next(io_data *rc_io_data) ([]byte, error) {
|
||||||
const prefix = "\x1bP@kitty-cmd"
|
const prefix = "\x1bP@kitty-cmd"
|
||||||
const suffix = "\x1b\\"
|
const suffix = "\x1b\\"
|
||||||
defer func() { self.state++ }()
|
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case 0:
|
case 0:
|
||||||
|
self.state++
|
||||||
return []byte(prefix), nil
|
return []byte(prefix), nil
|
||||||
case 1:
|
case 1:
|
||||||
return self.serializer(rc)
|
if io_data.multiple_payload_generator != nil {
|
||||||
|
is_last, err := io_data.multiple_payload_generator(io_data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if is_last {
|
||||||
|
self.all_payloads_done = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.all_payloads_done = true
|
||||||
|
}
|
||||||
|
return self.serializer(io_data.rc)
|
||||||
case 2:
|
case 2:
|
||||||
|
if self.all_payloads_done {
|
||||||
|
self.state++
|
||||||
|
} else {
|
||||||
|
self.state = 0
|
||||||
|
}
|
||||||
return []byte(suffix), nil
|
return []byte(suffix), nil
|
||||||
default:
|
default:
|
||||||
return make([]byte, 0), nil
|
return make([]byte, 0), nil
|
||||||
@ -150,6 +168,7 @@ type rc_io_data struct {
|
|||||||
send_keypresses bool
|
send_keypresses bool
|
||||||
string_response_is_err bool
|
string_response_is_err bool
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
multiple_payload_generator func(io_data *rc_io_data) (bool, error)
|
||||||
|
|
||||||
pending_chunks [][]byte
|
pending_chunks [][]byte
|
||||||
}
|
}
|
||||||
@ -161,7 +180,7 @@ func (self *rc_io_data) next_chunk(limit_size bool) (chunk []byte, err error) {
|
|||||||
self.pending_chunks = self.pending_chunks[:len(self.pending_chunks)-1]
|
self.pending_chunks = self.pending_chunks[:len(self.pending_chunks)-1]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
block, err := self.serializer.next(self.rc)
|
block, err := self.serializer.next(self)
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
if err != nil && !errors.Is(err, io.EOF) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
40
tools/cmd/at/scroll_window.go
Normal file
40
tools/cmd/at/scroll_window.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package at
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parse_scroll_amount(amt string) ([2]interface{}, error) {
|
||||||
|
var ans [2]interface{}
|
||||||
|
if amt == "start" || amt == "end" {
|
||||||
|
ans[0] = amt
|
||||||
|
ans[1] = nil
|
||||||
|
} else {
|
||||||
|
pages := strings.Contains(amt, "p")
|
||||||
|
unscroll := strings.Contains(amt, "u")
|
||||||
|
var mult float64 = 1
|
||||||
|
if strings.HasSuffix(amt, "-") && !unscroll {
|
||||||
|
mult = -1
|
||||||
|
q, err := strconv.ParseFloat(strings.TrimRight(amt, "+-plu"), 64)
|
||||||
|
if err != nil {
|
||||||
|
return ans, err
|
||||||
|
}
|
||||||
|
if !pages && q != float64(int(q)) {
|
||||||
|
return ans, fmt.Errorf("The number must be an integer")
|
||||||
|
}
|
||||||
|
ans[0] = q * mult
|
||||||
|
if pages {
|
||||||
|
ans[1] = "p"
|
||||||
|
} else if unscroll {
|
||||||
|
ans[1] = "u"
|
||||||
|
} else {
|
||||||
|
ans[1] = "l"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans, nil
|
||||||
|
}
|
||||||
54
tools/cmd/at/set_window_logo.go
Normal file
54
tools/cmd/at/set_window_logo.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package at
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func read_window_logo(path string) (func(io_data *rc_io_data) (bool, error), error) {
|
||||||
|
if strings.ToLower(path) == "none" {
|
||||||
|
return func(io_data *rc_io_data) (bool, error) {
|
||||||
|
io_data.rc.Payload = "-"
|
||||||
|
return true, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf := make([]byte, 2048)
|
||||||
|
n, err := f.Read(buf)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
f.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf = buf[:n]
|
||||||
|
|
||||||
|
if http.DetectContentType(buf) != "image/png" {
|
||||||
|
f.Close()
|
||||||
|
return nil, fmt.Errorf("%s is not a PNG image", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(io_data *rc_io_data) (bool, error) {
|
||||||
|
var payload set_window_logo_json_type = io_data.rc.Payload.(set_window_logo_json_type)
|
||||||
|
if len(buf) == 0 {
|
||||||
|
payload.Data = ""
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
payload.Data = base64.StdEncoding.EncodeToString(buf)
|
||||||
|
buf = buf[:cap(buf)]
|
||||||
|
n, err := f.Read(buf)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
buf = buf[:n]
|
||||||
|
return n == 0, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@ -7,6 +7,8 @@
|
|||||||
package at
|
package at
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -16,6 +18,9 @@ import (
|
|||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
var _ = strings.Join
|
||||||
|
|
||||||
type options_CMD_NAME_type struct {
|
type options_CMD_NAME_type struct {
|
||||||
OPTIONS_DECLARATION_CODE
|
OPTIONS_DECLARATION_CODE
|
||||||
}
|
}
|
||||||
@ -88,7 +93,7 @@ func aliasNormalizeFunc_CMD_NAME(f *pflag.FlagSet, name string) pflag.Normalized
|
|||||||
|
|
||||||
func setup_CMD_NAME(root *cobra.Command) *cobra.Command {
|
func setup_CMD_NAME(root *cobra.Command) *cobra.Command {
|
||||||
ans := cli.CreateCommand(&cobra.Command{
|
ans := cli.CreateCommand(&cobra.Command{
|
||||||
Use: "CLI_NAME [options]",
|
Use: "CLI_NAME [options]" + "ARGSPEC",
|
||||||
Short: "SHORT_DESC",
|
Short: "SHORT_DESC",
|
||||||
Long: "LONG_DESC",
|
Long: "LONG_DESC",
|
||||||
RunE: run_CMD_NAME,
|
RunE: run_CMD_NAME,
|
||||||
|
|||||||
@ -44,7 +44,7 @@ func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
lp.OnInitialize = func() (string, error) {
|
lp.OnInitialize = func() (string, error) {
|
||||||
chunk, err := io_data.next_chunk(true)
|
chunk, err := io_data.next_chunk(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error)
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
chunk, err := io_data.next_chunk(true)
|
chunk, err := io_data.next_chunk(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user