2022-08-16 17:49:39 +03:00
|
|
|
#!./kitty/launcher/kitty +launch
|
|
|
|
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
|
2022-08-26 08:22:10 +03:00
|
|
|
import io
|
2022-08-29 08:13:33 +03:00
|
|
|
import json
|
2022-09-15 11:40:57 +03:00
|
|
|
import os
|
2022-10-04 06:20:19 +03:00
|
|
|
import subprocess
|
2022-09-07 08:25:07 +03:00
|
|
|
import sys
|
2022-08-26 08:32:24 +03:00
|
|
|
from contextlib import contextmanager, suppress
|
2022-09-15 11:40:57 +03:00
|
|
|
from functools import lru_cache
|
2022-08-30 13:19:26 +03:00
|
|
|
from typing import Dict, Iterator, List, Set, Tuple, Union
|
2022-08-16 17:49:39 +03:00
|
|
|
|
2022-08-17 07:04:03 +03:00
|
|
|
import kitty.constants as kc
|
2022-08-23 16:23:55 +03:00
|
|
|
from kittens.tui.operations import Mode
|
2022-11-16 10:18:13 +03:00
|
|
|
from kittens.tui.spinners import spinners
|
2022-08-29 08:13:33 +03:00
|
|
|
from kitty.cli import (
|
2022-09-17 10:02:02 +03:00
|
|
|
CompletionSpec, GoOption, go_options_for_seq, parse_option_spec,
|
2022-09-25 09:53:52 +03:00
|
|
|
serialize_as_go_string,
|
2022-08-29 08:13:33 +03:00
|
|
|
)
|
2022-08-24 06:00:21 +03:00
|
|
|
from kitty.key_encoding import config_mod_map
|
2022-09-25 09:53:52 +03:00
|
|
|
from kitty.key_names import character_key_name_aliases, functional_key_name_aliases
|
2022-08-29 08:13:33 +03:00
|
|
|
from kitty.options.types import Options
|
2022-08-24 12:41:08 +03:00
|
|
|
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
|
2022-09-25 09:53:52 +03:00
|
|
|
from kitty.remote_control import global_options_spec
|
2022-08-29 08:13:33 +03:00
|
|
|
from kitty.rgb import color_names
|
2022-08-16 17:49:39 +03:00
|
|
|
|
2022-08-26 08:22:10 +03:00
|
|
|
changed: List[str] = []
|
|
|
|
|
|
|
|
|
2022-08-26 08:32:24 +03:00
|
|
|
# Utils {{{
|
2022-08-16 17:49:39 +03:00
|
|
|
|
2022-08-26 08:32:24 +03:00
|
|
|
def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int], Dict[str, str]]) -> str:
|
|
|
|
ans = []
|
|
|
|
|
|
|
|
def s(x: Union[int, str]) -> str:
|
|
|
|
if isinstance(x, int):
|
|
|
|
return str(x)
|
|
|
|
return f'"{serialize_as_go_string(x)}"'
|
|
|
|
|
|
|
|
for k, v in x.items():
|
|
|
|
ans.append(f'{s(k)}: {s(v)}')
|
|
|
|
return '{' + ', '.join(ans) + '}'
|
|
|
|
|
|
|
|
|
2022-08-17 07:04:03 +03:00
|
|
|
def replace(template: str, **kw: str) -> str:
|
|
|
|
for k, v in kw.items():
|
|
|
|
template = template.replace(k, v)
|
|
|
|
return template
|
2022-08-26 08:32:24 +03:00
|
|
|
# }}}
|
2022-08-17 07:04:03 +03:00
|
|
|
|
|
|
|
|
2022-09-26 08:52:48 +03:00
|
|
|
# Completions {{{
|
2022-09-17 09:29:41 +03:00
|
|
|
def generate_kittens_completion() -> None:
|
2022-09-25 09:53:52 +03:00
|
|
|
from kittens.runner import (
|
|
|
|
all_kitten_names, get_kitten_cli_docs, get_kitten_wrapper_of,
|
|
|
|
)
|
2022-09-19 11:01:32 +03:00
|
|
|
for kitten in sorted(all_kitten_names()):
|
2022-09-17 09:29:41 +03:00
|
|
|
kn = 'kitten_' + kitten
|
2022-09-26 05:04:49 +03:00
|
|
|
print(f'{kn} := plus_kitten.AddSubCommand(&cli.Command{{Name:"{kitten}", Group: "Kittens"}})')
|
2022-09-19 11:01:32 +03:00
|
|
|
wof = get_kitten_wrapper_of(kitten)
|
|
|
|
if wof:
|
2022-09-26 05:04:49 +03:00
|
|
|
print(f'{kn}.ArgCompleter = cli.CompletionForWrapper("{serialize_as_go_string(wof)}")')
|
2022-09-26 09:24:57 +03:00
|
|
|
print(f'{kn}.OnlyArgsAllowed = true')
|
2022-09-19 11:01:32 +03:00
|
|
|
continue
|
2022-09-17 09:29:41 +03:00
|
|
|
kcd = get_kitten_cli_docs(kitten)
|
|
|
|
if kcd:
|
|
|
|
ospec = kcd['options']
|
|
|
|
for opt in go_options_for_seq(parse_option_spec(ospec())[0]):
|
2022-09-26 05:04:49 +03:00
|
|
|
print(opt.as_option(kn))
|
2022-09-17 09:29:41 +03:00
|
|
|
ac = kcd.get('args_completion')
|
|
|
|
if ac is not None:
|
2022-09-26 05:04:49 +03:00
|
|
|
print(''.join(ac.as_go_code(kn + '.ArgCompleter', ' = ')))
|
2022-09-17 09:29:41 +03:00
|
|
|
else:
|
2022-09-26 05:04:49 +03:00
|
|
|
print(f'{kn}.HelpText = ""')
|
2022-09-17 09:29:41 +03:00
|
|
|
|
|
|
|
|
2022-09-17 10:02:02 +03:00
|
|
|
def completion_for_launch_wrappers(*names: str) -> None:
|
|
|
|
from kitty.launch import clone_safe_opts, options_spec
|
|
|
|
opts = tuple(go_options_for_seq(parse_option_spec(options_spec())[0]))
|
|
|
|
allowed = clone_safe_opts()
|
|
|
|
for o in opts:
|
2022-09-25 09:53:52 +03:00
|
|
|
if o.obj_dict['name'] in allowed:
|
2022-09-17 10:02:02 +03:00
|
|
|
for name in names:
|
2022-09-26 05:04:49 +03:00
|
|
|
print(o.as_option(name))
|
2022-09-17 10:02:02 +03:00
|
|
|
|
|
|
|
|
2022-09-07 08:25:07 +03:00
|
|
|
def generate_completions_for_kitty() -> None:
|
2022-09-26 05:04:49 +03:00
|
|
|
from kitty.config import option_names_for_completion
|
2022-09-07 08:25:07 +03:00
|
|
|
print('package completion\n')
|
2022-09-26 05:04:49 +03:00
|
|
|
print('import "kitty/tools/cli"')
|
2022-09-30 11:30:01 +03:00
|
|
|
print('import "kitty/tools/cmd/tool"')
|
2022-09-26 05:04:49 +03:00
|
|
|
print('import "kitty/tools/cmd/at"')
|
|
|
|
conf_names = ', '.join((f'"{serialize_as_go_string(x)}"' for x in option_names_for_completion()))
|
|
|
|
print('var kitty_option_names_for_completion = []string{' + conf_names + '}')
|
|
|
|
|
|
|
|
print('func kitty(root *cli.Command) {')
|
2022-09-17 10:02:02 +03:00
|
|
|
|
|
|
|
# The kitty exe
|
2022-09-26 05:04:49 +03:00
|
|
|
print('k := root.AddSubCommand(&cli.Command{'
|
|
|
|
'Name:"kitty", SubCommandIsOptional: true, ArgCompleter: cli.CompleteExecutableFirstArg, SubCommandMustBeFirst: true })')
|
2022-09-30 08:53:58 +03:00
|
|
|
print('kt := root.AddSubCommand(&cli.Command{Name:"kitty-tool", SubCommandMustBeFirst: true })')
|
2022-09-30 11:30:01 +03:00
|
|
|
print('tool.KittyToolEntryPoints(kt)')
|
2022-09-16 11:38:22 +03:00
|
|
|
for opt in go_options_for_seq(parse_option_spec()[0]):
|
2022-09-26 05:04:49 +03:00
|
|
|
print(opt.as_option('k'))
|
2022-09-16 19:25:31 +03:00
|
|
|
|
2022-09-17 10:02:02 +03:00
|
|
|
# kitty +
|
2022-09-26 05:04:49 +03:00
|
|
|
print('plus := k.AddSubCommand(&cli.Command{Name:"+", Group:"Entry points", ShortDescription: "Various special purpose tools and kittens"})')
|
2022-09-16 19:02:10 +03:00
|
|
|
|
2022-09-26 05:04:49 +03:00
|
|
|
print('plus_launch := plus.AddSubCommand(&cli.Command{'
|
|
|
|
'Name:"launch", Group:"Entry points", ShortDescription: "Launch Python scripts", ArgCompleter: complete_plus_launch})')
|
|
|
|
print('k.AddClone("", plus_launch).Name = "+launch"')
|
2022-09-16 19:02:10 +03:00
|
|
|
|
2022-09-26 05:04:49 +03:00
|
|
|
print('plus_runpy := plus.AddSubCommand(&cli.Command{'
|
|
|
|
'Name: "runpy", Group:"Entry points", ArgCompleter: complete_plus_runpy, ShortDescription: "Run Python code"})')
|
|
|
|
print('k.AddClone("", plus_runpy).Name = "+runpy"')
|
2022-09-16 19:02:10 +03:00
|
|
|
|
2022-09-26 05:04:49 +03:00
|
|
|
print('plus_open := plus.AddSubCommand(&cli.Command{'
|
|
|
|
'Name:"open", Group:"Entry points", ArgCompleter: complete_plus_open, ShortDescription: "Open files and URLs"})')
|
2022-09-26 08:52:48 +03:00
|
|
|
print('for _, og := range k.OptionGroups { plus_open.OptionGroups = append(plus_open.OptionGroups, og.Clone(plus_open)) }')
|
2022-09-26 05:04:49 +03:00
|
|
|
print('k.AddClone("", plus_open).Name = "+open"')
|
2022-09-16 19:02:10 +03:00
|
|
|
|
2022-09-17 10:02:02 +03:00
|
|
|
# kitty +kitten
|
2022-09-26 05:04:49 +03:00
|
|
|
print('plus_kitten := plus.AddSubCommand(&cli.Command{Name:"kitten", Group:"Kittens", SubCommandMustBeFirst: true})')
|
2022-09-17 09:29:41 +03:00
|
|
|
generate_kittens_completion()
|
2022-09-26 05:04:49 +03:00
|
|
|
print('k.AddClone("", plus_kitten).Name = "+kitten"')
|
2022-09-17 09:29:41 +03:00
|
|
|
|
2022-09-26 05:04:49 +03:00
|
|
|
# @
|
|
|
|
print('at.EntryPoint(k)')
|
2022-09-17 10:02:02 +03:00
|
|
|
|
|
|
|
# clone-in-kitty, edit-in-kitty
|
2022-09-26 05:04:49 +03:00
|
|
|
print('cik := root.AddSubCommand(&cli.Command{Name:"clone-in-kitty"})')
|
|
|
|
print('eik := root.AddSubCommand(&cli.Command{Name:"edit-in-kitty"})')
|
2022-09-17 10:02:02 +03:00
|
|
|
completion_for_launch_wrappers('cik', 'eik')
|
2022-09-26 05:04:49 +03:00
|
|
|
print(''.join(CompletionSpec.from_string('type:file mime:text/* group:"Text files"').as_go_code('eik.ArgCompleter', ' = ')))
|
2022-09-17 10:02:02 +03:00
|
|
|
|
2022-09-07 08:25:07 +03:00
|
|
|
print('}')
|
|
|
|
print('func init() {')
|
2022-09-26 05:04:49 +03:00
|
|
|
print('cli.RegisterExeForCompletion(kitty)')
|
2022-09-07 08:25:07 +03:00
|
|
|
print('}')
|
2022-09-26 08:52:48 +03:00
|
|
|
# }}}
|
2022-09-07 08:25:07 +03:00
|
|
|
|
|
|
|
|
2022-09-06 16:21:23 +03:00
|
|
|
# rc command wrappers {{{
|
2022-08-17 19:27:02 +03:00
|
|
|
json_field_types: Dict[str, str] = {
|
|
|
|
'bool': 'bool', 'str': 'string', 'list.str': '[]string', 'dict.str': 'map[string]string', 'float': 'float64', 'int': 'int',
|
2022-09-21 05:41:46 +03:00
|
|
|
'scroll_amount': 'any', 'spacing': 'any', 'colors': 'any',
|
2022-08-17 19:27:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def go_field_type(json_field_type: str) -> str:
|
|
|
|
q = json_field_types.get(json_field_type)
|
|
|
|
if q:
|
|
|
|
return q
|
|
|
|
if json_field_type.startswith('choices.'):
|
|
|
|
return 'string'
|
|
|
|
if '.' in json_field_type:
|
|
|
|
p, r = json_field_type.split('.', 1)
|
|
|
|
p = {'list': '[]', 'dict': 'map[string]'}[p]
|
|
|
|
return p + go_field_type(r)
|
|
|
|
raise TypeError(f'Unknown JSON field type: {json_field_type}')
|
|
|
|
|
|
|
|
|
|
|
|
class JSONField:
|
|
|
|
|
|
|
|
def __init__(self, line: str) -> None:
|
|
|
|
field_def = line.split(':', 1)[0]
|
|
|
|
self.required = False
|
|
|
|
self.field, self.field_type = field_def.split('/', 1)
|
|
|
|
if self.field.endswith('+'):
|
|
|
|
self.required = True
|
|
|
|
self.field = self.field[:-1]
|
|
|
|
self.struct_field_name = self.field[0].upper() + self.field[1:]
|
|
|
|
|
|
|
|
def go_declaration(self) -> str:
|
|
|
|
return self.struct_field_name + ' ' + go_field_type(self.field_type) + f'`json:"{self.field},omitempty"`'
|
|
|
|
|
|
|
|
|
2022-09-09 12:40:38 +03:00
|
|
|
def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) -> str:
|
2022-08-16 21:41:28 +03:00
|
|
|
template = '\n' + template[len('//go:build exclude'):]
|
2022-08-31 17:33:51 +03:00
|
|
|
NO_RESPONSE_BASE = 'false'
|
2022-08-17 07:04:03 +03:00
|
|
|
af: List[str] = []
|
|
|
|
a = af.append
|
2022-09-26 05:04:49 +03:00
|
|
|
af.extend(cmd.args.as_go_completion_code('ans'))
|
2022-08-17 17:12:43 +03:00
|
|
|
od: List[str] = []
|
2022-08-29 09:40:23 +03:00
|
|
|
option_map: Dict[str, GoOption] = {}
|
2022-09-09 12:40:38 +03:00
|
|
|
for o in rc_command_options(name):
|
2022-09-25 09:53:52 +03:00
|
|
|
option_map[o.go_var_name] = o
|
|
|
|
a(o.as_option('ans'))
|
|
|
|
if o.go_var_name in ('NoResponse', 'ResponseTimeout'):
|
2022-08-17 11:03:24 +03:00
|
|
|
continue
|
2022-09-25 09:53:52 +03:00
|
|
|
od.append(o.struct_declaration())
|
2022-08-17 19:27:02 +03:00
|
|
|
jd: List[str] = []
|
2022-08-29 09:40:23 +03:00
|
|
|
json_fields = []
|
2022-08-29 21:51:59 +03:00
|
|
|
field_types: Dict[str, str] = {}
|
2022-08-17 19:27:02 +03:00
|
|
|
for line in cmd.protocol_spec.splitlines():
|
|
|
|
line = line.strip()
|
|
|
|
if ':' not in line:
|
|
|
|
continue
|
|
|
|
f = JSONField(line)
|
2022-08-29 09:40:23 +03:00
|
|
|
json_fields.append(f)
|
2022-08-29 21:51:59 +03:00
|
|
|
field_types[f.field] = f.field_type
|
2022-08-17 19:27:02 +03:00
|
|
|
jd.append(f.go_declaration())
|
2022-08-29 09:40:23 +03:00
|
|
|
jc: List[str] = []
|
2022-08-30 13:19:26 +03:00
|
|
|
handled_fields: Set[str] = set()
|
2022-08-30 18:00:25 +03:00
|
|
|
jc.extend(cmd.args.as_go_code(name, field_types, handled_fields))
|
2022-08-30 13:19:26 +03:00
|
|
|
|
2022-08-30 18:35:31 +03:00
|
|
|
unhandled = {}
|
|
|
|
used_options = set()
|
2022-08-29 09:40:23 +03:00
|
|
|
for field in json_fields:
|
2022-08-30 18:35:31 +03:00
|
|
|
oq = (cmd.field_to_option_map or {}).get(field.field, field.field)
|
2022-09-25 09:53:52 +03:00
|
|
|
oq = ''.join(x.capitalize() for x in oq.split('_'))
|
2022-08-30 18:35:31 +03:00
|
|
|
if oq in option_map:
|
|
|
|
o = option_map[oq]
|
|
|
|
used_options.add(oq)
|
2022-08-29 09:40:23 +03:00
|
|
|
jc.append(f'payload.{field.struct_field_name} = options_{name}.{o.go_var_name}')
|
2022-08-30 13:19:26 +03:00
|
|
|
elif field.field in handled_fields:
|
|
|
|
pass
|
2022-08-29 09:40:23 +03:00
|
|
|
else:
|
2022-08-30 18:35:31 +03:00
|
|
|
unhandled[field.field] = field
|
|
|
|
for x in tuple(unhandled):
|
2022-09-25 09:53:52 +03:00
|
|
|
if x == 'match_window' and 'Match' in option_map and 'Match' not in used_options:
|
|
|
|
used_options.add('Match')
|
|
|
|
o = option_map['Match']
|
2022-08-30 18:35:31 +03:00
|
|
|
field = unhandled[x]
|
|
|
|
jc.append(f'payload.{field.struct_field_name} = options_{name}.{o.go_var_name}')
|
|
|
|
del unhandled[x]
|
|
|
|
if unhandled:
|
|
|
|
raise SystemExit(f'Cant map fields: {", ".join(unhandled)} for cmd: {name}')
|
2022-08-31 07:39:55 +03:00
|
|
|
if name != 'send_text':
|
2022-09-25 09:53:52 +03:00
|
|
|
unused_options = set(option_map) - used_options - {'NoResponse', 'ResponseTimeout'}
|
2022-08-31 07:39:55 +03:00
|
|
|
if unused_options:
|
|
|
|
raise SystemExit(f'Unused options: {", ".join(unused_options)} for command: {name}')
|
2022-08-29 21:51:59 +03:00
|
|
|
|
|
|
|
argspec = cmd.args.spec
|
|
|
|
if argspec:
|
|
|
|
argspec = ' ' + argspec
|
2022-08-17 07:04:03 +03:00
|
|
|
ans = replace(
|
|
|
|
template,
|
|
|
|
CMD_NAME=name, __FILE__=__file__, CLI_NAME=name.replace('_', '-'),
|
|
|
|
SHORT_DESC=serialize_as_go_string(cmd.short_desc),
|
|
|
|
LONG_DESC=serialize_as_go_string(cmd.desc.strip()),
|
2022-08-25 15:46:03 +03:00
|
|
|
IS_ASYNC='true' if cmd.is_asynchronous else 'false',
|
2022-08-17 11:03:24 +03:00
|
|
|
NO_RESPONSE_BASE=NO_RESPONSE_BASE, ADD_FLAGS_CODE='\n'.join(af),
|
|
|
|
WAIT_TIMEOUT=str(cmd.response_timeout),
|
2022-08-17 17:12:43 +03:00
|
|
|
OPTIONS_DECLARATION_CODE='\n'.join(od),
|
2022-08-17 19:27:02 +03:00
|
|
|
JSON_DECLARATION_CODE='\n'.join(jd),
|
2022-08-29 21:51:59 +03:00
|
|
|
JSON_INIT_CODE='\n'.join(jc), ARGSPEC=argspec,
|
2022-08-22 12:41:00 +03:00
|
|
|
STRING_RESPONSE_IS_ERROR='true' if cmd.string_return_is_error else 'false',
|
2022-08-31 17:33:51 +03:00
|
|
|
STREAM_WANTED='true' if cmd.reads_streaming_data else 'false',
|
2022-08-17 11:03:24 +03:00
|
|
|
)
|
2022-08-16 17:49:39 +03:00
|
|
|
return ans
|
2022-09-06 16:21:23 +03:00
|
|
|
# }}}
|
2022-08-16 17:49:39 +03:00
|
|
|
|
|
|
|
|
2022-08-26 08:32:24 +03:00
|
|
|
# Constants {{{
|
2022-11-16 10:18:13 +03:00
|
|
|
|
|
|
|
def generate_spinners() -> str:
|
|
|
|
ans = ['package tui', 'import "time"', 'func NewSpinner(name string) *Spinner {', 'var ans *Spinner', 'switch name {']
|
|
|
|
a = ans.append
|
|
|
|
for name, spinner in spinners.items():
|
|
|
|
a(f'case "{serialize_as_go_string(name)}":')
|
|
|
|
a('ans = &Spinner{')
|
|
|
|
a(f'Name: "{serialize_as_go_string(name)}",')
|
|
|
|
a(f'interval: {spinner["interval"]},')
|
|
|
|
frames = ', '.join(f'"{serialize_as_go_string(x)}"' for x in spinner['frames'])
|
|
|
|
a(f'frames: []string{{{frames}}},')
|
|
|
|
a('}')
|
|
|
|
a('}')
|
|
|
|
a('if ans != nil {')
|
|
|
|
a('ans.interval *= time.Millisecond')
|
|
|
|
a('ans.current_frame = -1')
|
|
|
|
a('ans.last_change_at = time.Now().Add(-ans.interval)')
|
|
|
|
a('}')
|
|
|
|
a('return ans}')
|
|
|
|
return '\n'.join(ans)
|
|
|
|
|
|
|
|
|
2022-08-27 10:27:07 +03:00
|
|
|
def generate_color_names() -> str:
|
|
|
|
return 'package style\n\nvar ColorNames = map[string]RGBA{' + '\n'.join(
|
|
|
|
f'\t"{name}": RGBA{{ Red:{val.red}, Green:{val.green}, Blue:{val.blue} }},'
|
|
|
|
for name, val in color_names.items()
|
|
|
|
) + '\n}' + '\n\nvar ColorTable = [256]uint32{' + ', '.join(
|
|
|
|
f'{x}' for x in Options.color_table) + '}\n'
|
|
|
|
|
|
|
|
|
2022-08-24 12:41:08 +03:00
|
|
|
def load_ref_map() -> Dict[str, Dict[str, str]]:
|
|
|
|
with open('kitty/docs_ref_map_generated.h') as f:
|
|
|
|
raw = f.read()
|
|
|
|
raw = raw.split('{', 1)[1].split('}', 1)[0]
|
|
|
|
data = json.loads(bytes(bytearray(json.loads(f'[{raw}]'))))
|
|
|
|
return data # type: ignore
|
|
|
|
|
|
|
|
|
2022-08-26 08:22:10 +03:00
|
|
|
def generate_constants() -> str:
|
2022-08-24 12:41:08 +03:00
|
|
|
ref_map = load_ref_map()
|
2022-08-26 08:22:10 +03:00
|
|
|
dp = ", ".join(map(lambda x: f'"{serialize_as_go_string(x)}"', kc.default_pager_for_help))
|
|
|
|
return f'''\
|
2022-08-16 18:44:40 +03:00
|
|
|
package kitty
|
|
|
|
|
|
|
|
type VersionType struct {{
|
|
|
|
Major, Minor, Patch int
|
|
|
|
}}
|
2022-08-23 16:23:55 +03:00
|
|
|
const VersionString string = "{kc.str_version}"
|
|
|
|
const WebsiteBaseURL string = "{kc.website_base_url}"
|
|
|
|
const VCSRevision string = ""
|
|
|
|
const RC_ENCRYPTION_PROTOCOL_VERSION string = "{kc.RC_ENCRYPTION_PROTOCOL_VERSION}"
|
|
|
|
const IsFrozenBuild bool = false
|
2022-11-15 12:34:28 +03:00
|
|
|
const IsStandaloneBuild bool = false
|
2022-08-23 16:23:55 +03:00
|
|
|
const HandleTermiosSignals = {Mode.HANDLE_TERMIOS_SIGNALS.value[0]}
|
2022-08-16 18:44:40 +03:00
|
|
|
var Version VersionType = VersionType{{Major: {kc.version.major}, Minor: {kc.version.minor}, Patch: {kc.version.patch},}}
|
|
|
|
var DefaultPager []string = []string{{ {dp} }}
|
2022-08-24 06:00:21 +03:00
|
|
|
var FunctionalKeyNameAliases = map[string]string{serialize_go_dict(functional_key_name_aliases)}
|
|
|
|
var CharacterKeyNameAliases = map[string]string{serialize_go_dict(character_key_name_aliases)}
|
|
|
|
var ConfigModMap = map[string]uint16{serialize_go_dict(config_mod_map)}
|
2022-08-24 12:41:08 +03:00
|
|
|
var RefMap = map[string]string{serialize_go_dict(ref_map['ref'])}
|
|
|
|
var DocTitleMap = map[string]string{serialize_go_dict(ref_map['doc'])}
|
2022-08-26 08:32:24 +03:00
|
|
|
''' # }}}
|
|
|
|
|
2022-08-26 08:22:10 +03:00
|
|
|
|
2022-08-26 08:32:24 +03:00
|
|
|
# Boilerplate {{{
|
2022-08-26 08:22:10 +03:00
|
|
|
|
|
|
|
@contextmanager
|
2022-10-04 06:20:19 +03:00
|
|
|
def replace_if_needed(path: str, show_diff: bool = False) -> Iterator[io.StringIO]:
|
2022-08-26 08:22:10 +03:00
|
|
|
buf = io.StringIO()
|
|
|
|
yield buf
|
2022-08-26 08:32:24 +03:00
|
|
|
orig = ''
|
|
|
|
with suppress(FileNotFoundError), open(path, 'r') as f:
|
2022-08-26 08:22:10 +03:00
|
|
|
orig = f.read()
|
2022-08-26 08:32:24 +03:00
|
|
|
new = buf.getvalue()
|
2022-09-15 11:40:57 +03:00
|
|
|
new = f'// Code generated by {os.path.basename(__file__)}; DO NOT EDIT.\n\n' + new
|
2022-08-26 08:22:10 +03:00
|
|
|
if orig != new:
|
|
|
|
changed.append(path)
|
2022-10-04 06:20:19 +03:00
|
|
|
if show_diff:
|
|
|
|
with open(path + '.new', 'w') as f:
|
|
|
|
f.write(new)
|
|
|
|
subprocess.run(['diff', '-Naurp', path, f.name], stdout=open('/dev/tty', 'w'))
|
|
|
|
os.remove(f.name)
|
2022-08-26 08:22:10 +03:00
|
|
|
with open(path, 'w') as f:
|
|
|
|
f.write(new)
|
|
|
|
|
|
|
|
|
2022-09-09 12:40:38 +03:00
|
|
|
@lru_cache(maxsize=256)
|
|
|
|
def rc_command_options(name: str) -> Tuple[GoOption, ...]:
|
|
|
|
cmd = command_for_name(name)
|
|
|
|
return tuple(go_options_for_seq(parse_option_spec(cmd.options_spec or '\n\n')[0]))
|
|
|
|
|
|
|
|
|
2022-08-26 08:22:10 +03:00
|
|
|
def update_at_commands() -> None:
|
2022-08-16 17:49:39 +03:00
|
|
|
with open('tools/cmd/at/template.go') as f:
|
|
|
|
template = f.read()
|
|
|
|
for name in all_command_names():
|
|
|
|
cmd = command_for_name(name)
|
2022-09-09 12:40:38 +03:00
|
|
|
code = go_code_for_remote_command(name, cmd, template)
|
2022-08-25 05:33:23 +03:00
|
|
|
dest = f'tools/cmd/at/cmd_{name}_generated.go'
|
2022-09-06 16:21:23 +03:00
|
|
|
with replace_if_needed(dest) as f:
|
2022-08-16 17:49:39 +03:00
|
|
|
f.write(code)
|
2022-09-25 09:53:52 +03:00
|
|
|
struct_def = []
|
|
|
|
opt_def = []
|
|
|
|
for o in go_options_for_seq(parse_option_spec(global_options_spec())[0]):
|
|
|
|
struct_def.append(o.struct_declaration())
|
|
|
|
opt_def.append(o.as_option(depth=1, group="Global options"))
|
|
|
|
sdef = '\n'.join(struct_def)
|
|
|
|
odef = '\n'.join(opt_def)
|
|
|
|
code = f'''
|
|
|
|
package at
|
|
|
|
import "kitty/tools/cli"
|
|
|
|
type rc_global_options struct {{
|
|
|
|
{sdef}
|
|
|
|
}}
|
|
|
|
var rc_global_opts rc_global_options
|
|
|
|
|
|
|
|
func add_rc_global_opts(cmd *cli.Command) {{
|
|
|
|
{odef}
|
|
|
|
}}
|
|
|
|
'''
|
|
|
|
with replace_if_needed('tools/cmd/at/global_opts_generated.go') as f:
|
|
|
|
f.write(code)
|
2022-08-16 17:49:39 +03:00
|
|
|
|
|
|
|
|
2022-09-06 16:21:23 +03:00
|
|
|
def update_completion() -> None:
|
2022-09-07 08:25:07 +03:00
|
|
|
orig = sys.stdout
|
|
|
|
try:
|
2022-09-26 05:04:49 +03:00
|
|
|
with replace_if_needed('tools/cmd/completion/kitty_generated.go') as f:
|
2022-09-07 08:25:07 +03:00
|
|
|
sys.stdout = f
|
|
|
|
generate_completions_for_kitty()
|
|
|
|
finally:
|
|
|
|
sys.stdout = orig
|
2022-09-06 16:21:23 +03:00
|
|
|
|
|
|
|
|
2022-11-08 17:11:03 +03:00
|
|
|
def define_enum(package_name: str, type_name: str, items: str, underlying_type: str = 'uint') -> str:
|
2022-11-08 17:01:42 +03:00
|
|
|
actions = []
|
2022-11-08 17:11:03 +03:00
|
|
|
for x in items.splitlines():
|
|
|
|
x = x.strip()
|
|
|
|
if x:
|
|
|
|
actions.append(x)
|
|
|
|
ans = [f'package {package_name}', 'import "strconv"', f'type {type_name} {underlying_type}', 'const (']
|
|
|
|
stringer = [f'func (ac {type_name}) String() string ''{', 'switch(ac) {']
|
|
|
|
for i, ac in enumerate(actions):
|
|
|
|
stringer.append(f'case {ac}: return "{ac}"')
|
|
|
|
if i == 0:
|
|
|
|
ac = ac + f' {type_name} = iota'
|
|
|
|
ans.append(ac)
|
|
|
|
ans.append(')')
|
|
|
|
stringer.append('}\nreturn strconv.Itoa(int(ac)) }')
|
|
|
|
return '\n'.join(ans + stringer)
|
|
|
|
|
|
|
|
|
|
|
|
def generate_readline_actions() -> str:
|
|
|
|
return define_enum('readline', 'Action', '''\
|
2022-11-08 17:01:42 +03:00
|
|
|
ActionNil
|
|
|
|
|
|
|
|
ActionBackspace
|
|
|
|
ActionDelete
|
|
|
|
ActionMoveToStartOfLine
|
|
|
|
ActionMoveToEndOfLine
|
|
|
|
ActionMoveToStartOfDocument
|
|
|
|
ActionMoveToEndOfDocument
|
|
|
|
ActionMoveToEndOfWord
|
|
|
|
ActionMoveToStartOfWord
|
|
|
|
ActionCursorLeft
|
|
|
|
ActionCursorRight
|
|
|
|
ActionEndInput
|
|
|
|
ActionAcceptInput
|
|
|
|
ActionCursorUp
|
|
|
|
ActionHistoryPreviousOrCursorUp
|
|
|
|
ActionCursorDown
|
|
|
|
ActionHistoryNextOrCursorDown
|
|
|
|
ActionHistoryNext
|
|
|
|
ActionHistoryPrevious
|
|
|
|
ActionHistoryFirst
|
|
|
|
ActionHistoryLast
|
|
|
|
ActionHistoryIncrementalSearchBackwards
|
|
|
|
ActionHistoryIncrementalSearchForwards
|
|
|
|
ActionTerminateHistorySearchAndApply
|
|
|
|
ActionTerminateHistorySearchAndRestore
|
|
|
|
ActionClearScreen
|
|
|
|
ActionAddText
|
|
|
|
ActionAbortCurrentLine
|
|
|
|
|
|
|
|
ActionStartKillActions
|
|
|
|
ActionKillToEndOfLine
|
|
|
|
ActionKillToStartOfLine
|
|
|
|
ActionKillNextWord
|
|
|
|
ActionKillPreviousWord
|
|
|
|
ActionKillPreviousSpaceDelimitedWord
|
|
|
|
ActionEndKillActions
|
|
|
|
ActionYank
|
|
|
|
ActionPopYank
|
|
|
|
|
|
|
|
ActionNumericArgumentDigit0
|
|
|
|
ActionNumericArgumentDigit1
|
|
|
|
ActionNumericArgumentDigit2
|
|
|
|
ActionNumericArgumentDigit3
|
|
|
|
ActionNumericArgumentDigit4
|
|
|
|
ActionNumericArgumentDigit5
|
|
|
|
ActionNumericArgumentDigit6
|
|
|
|
ActionNumericArgumentDigit7
|
|
|
|
ActionNumericArgumentDigit8
|
|
|
|
ActionNumericArgumentDigit9
|
|
|
|
ActionNumericArgumentDigitMinus
|
2022-11-10 13:05:36 +03:00
|
|
|
|
|
|
|
ActionCompleteForward
|
|
|
|
ActionCompleteBackward
|
2022-11-08 17:11:03 +03:00
|
|
|
''')
|
2022-11-08 17:01:42 +03:00
|
|
|
|
|
|
|
|
2022-08-26 08:22:10 +03:00
|
|
|
def main() -> None:
|
|
|
|
with replace_if_needed('constants_generated.go') as f:
|
|
|
|
f.write(generate_constants())
|
2022-08-27 10:27:07 +03:00
|
|
|
with replace_if_needed('tools/utils/style/color-names_generated.go') as f:
|
|
|
|
f.write(generate_color_names())
|
2022-11-08 17:01:42 +03:00
|
|
|
with replace_if_needed('tools/tui/readline/actions_generated.go') as f:
|
|
|
|
f.write(generate_readline_actions())
|
2022-11-16 10:18:13 +03:00
|
|
|
with replace_if_needed('tools/tui/spinners_generated.go') as f:
|
|
|
|
f.write(generate_spinners())
|
2022-09-06 16:21:23 +03:00
|
|
|
update_completion()
|
2022-08-26 08:22:10 +03:00
|
|
|
update_at_commands()
|
|
|
|
print(json.dumps(changed, indent=2))
|
|
|
|
|
|
|
|
|
2022-08-16 17:49:39 +03:00
|
|
|
if __name__ == '__main__':
|
2022-08-26 08:32:24 +03:00
|
|
|
main() # }}}
|