Start moving clipboard kitten to kitty-tool
This commit is contained in:
parent
fbce5e7524
commit
4d3f3b5e91
@ -8,7 +8,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
from contextlib import contextmanager, suppress
|
from contextlib import contextmanager, suppress
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Dict, Iterator, List, Set, Tuple, Union, Sequence
|
from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Union
|
||||||
|
|
||||||
import kitty.constants as kc
|
import kitty.constants as kc
|
||||||
from kittens.tui.operations import Mode
|
from kittens.tui.operations import Mode
|
||||||
@ -50,10 +50,24 @@ def replace(template: str, **kw: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
# Completions {{{
|
# Completions {{{
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def kitten_cli_docs(kitten: str) -> Any:
|
||||||
|
from kittens.runner import get_kitten_cli_docs
|
||||||
|
return get_kitten_cli_docs(kitten)
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def go_options_for_kitten(kitten: str) -> Tuple[Sequence[GoOption], Optional[CompletionSpec]]:
|
||||||
|
kcd = kitten_cli_docs(kitten)
|
||||||
|
if kcd:
|
||||||
|
ospec = kcd['options']
|
||||||
|
return (tuple(go_options_for_seq(parse_option_spec(ospec())[0])), kcd.get('args_completion'))
|
||||||
|
return (), None
|
||||||
|
|
||||||
|
|
||||||
def generate_kittens_completion() -> None:
|
def generate_kittens_completion() -> None:
|
||||||
from kittens.runner import (
|
from kittens.runner import all_kitten_names, get_kitten_wrapper_of
|
||||||
all_kitten_names, get_kitten_cli_docs, get_kitten_wrapper_of,
|
|
||||||
)
|
|
||||||
for kitten in sorted(all_kitten_names()):
|
for kitten in sorted(all_kitten_names()):
|
||||||
kn = 'kitten_' + kitten
|
kn = 'kitten_' + kitten
|
||||||
print(f'{kn} := plus_kitten.AddSubCommand(&cli.Command{{Name:"{kitten}", Group: "Kittens"}})')
|
print(f'{kn} := plus_kitten.AddSubCommand(&cli.Command{{Name:"{kitten}", Group: "Kittens"}})')
|
||||||
@ -62,12 +76,10 @@ def generate_kittens_completion() -> None:
|
|||||||
print(f'{kn}.ArgCompleter = cli.CompletionForWrapper("{serialize_as_go_string(wof)}")')
|
print(f'{kn}.ArgCompleter = cli.CompletionForWrapper("{serialize_as_go_string(wof)}")')
|
||||||
print(f'{kn}.OnlyArgsAllowed = true')
|
print(f'{kn}.OnlyArgsAllowed = true')
|
||||||
continue
|
continue
|
||||||
kcd = get_kitten_cli_docs(kitten)
|
gopts, ac = go_options_for_kitten(kitten)
|
||||||
if kcd:
|
if gopts or ac:
|
||||||
ospec = kcd['options']
|
for opt in gopts:
|
||||||
for opt in go_options_for_seq(parse_option_spec(ospec())[0]):
|
|
||||||
print(opt.as_option(kn))
|
print(opt.as_option(kn))
|
||||||
ac = kcd.get('args_completion')
|
|
||||||
if ac is not None:
|
if ac is not None:
|
||||||
print(''.join(ac.as_go_code(kn + '.ArgCompleter', ' = ')))
|
print(''.join(ac.as_go_code(kn + '.ArgCompleter', ' = ')))
|
||||||
else:
|
else:
|
||||||
@ -265,6 +277,48 @@ def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) ->
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
# kittens {{{
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def wrapped_kittens() -> Sequence[str]:
|
||||||
|
with open('shell-integration/ssh/kitty') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(' wrapped_kittens="'):
|
||||||
|
val = line.strip().partition('"')[2][:-1]
|
||||||
|
return tuple(sorted(filter(None, val.split())))
|
||||||
|
raise Exception('Failed to read wrapped kittens from kitty wrapper script')
|
||||||
|
|
||||||
|
|
||||||
|
def kitten_clis() -> None:
|
||||||
|
for kitten in wrapped_kittens():
|
||||||
|
with replace_if_needed(f'tools/cmd/{kitten}/cli_generated.go'):
|
||||||
|
kcd = kitten_cli_docs(kitten)
|
||||||
|
has_underscore = '_' in kitten
|
||||||
|
print(f'package {kitten}')
|
||||||
|
print('import "kitty/tools/cli"')
|
||||||
|
print('func create_cmd(root *cli.Command, run_func cli.RunFunc) {')
|
||||||
|
print('ans := root.AddSubCommand(&cli.Command{')
|
||||||
|
print(f'Name: "{kitten}",')
|
||||||
|
print(f'ShortDescription: "{serialize_as_go_string(kcd["short_desc"])}",')
|
||||||
|
print(f'Usage: "{serialize_as_go_string(kcd["usage"])}",')
|
||||||
|
print(f'HelpText: "{serialize_as_go_string(kcd["help_text"])}",')
|
||||||
|
print('Run: run_func,')
|
||||||
|
if has_underscore:
|
||||||
|
print('Hidden: true,')
|
||||||
|
print('})')
|
||||||
|
gopts, ac = go_options_for_kitten(kitten)
|
||||||
|
for opt in gopts:
|
||||||
|
print(opt.as_option('ans'))
|
||||||
|
if ac is not None:
|
||||||
|
print(''.join(ac.as_go_code('ans.ArgCompleter', ' = ')))
|
||||||
|
if has_underscore:
|
||||||
|
print("clone := root.AddClone(ans.Group, ans)")
|
||||||
|
print('clone.Hidden = false')
|
||||||
|
print(f'clone.Name = "{serialize_as_go_string(kitten.replace("_", "-"))}"')
|
||||||
|
print('}')
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
# Constants {{{
|
# Constants {{{
|
||||||
|
|
||||||
def generate_spinners() -> str:
|
def generate_spinners() -> str:
|
||||||
@ -335,7 +389,12 @@ var DocTitleMap = map[string]string{serialize_go_dict(ref_map['doc'])}
|
|||||||
@contextmanager
|
@contextmanager
|
||||||
def replace_if_needed(path: str, show_diff: bool = False) -> Iterator[io.StringIO]:
|
def replace_if_needed(path: str, show_diff: bool = False) -> Iterator[io.StringIO]:
|
||||||
buf = io.StringIO()
|
buf = io.StringIO()
|
||||||
|
origb = sys.stdout
|
||||||
|
sys.stdout = buf
|
||||||
|
try:
|
||||||
yield buf
|
yield buf
|
||||||
|
finally:
|
||||||
|
sys.stdout = origb
|
||||||
orig = ''
|
orig = ''
|
||||||
with suppress(FileNotFoundError), open(path, 'r') as f:
|
with suppress(FileNotFoundError), open(path, 'r') as f:
|
||||||
orig = f.read()
|
orig = f.read()
|
||||||
@ -391,21 +450,15 @@ func add_rc_global_opts(cmd *cli.Command) {{
|
|||||||
|
|
||||||
|
|
||||||
def update_completion() -> None:
|
def update_completion() -> None:
|
||||||
orig = sys.stdout
|
with replace_if_needed('tools/cmd/completion/kitty_generated.go'):
|
||||||
try:
|
|
||||||
with replace_if_needed('tools/cmd/completion/kitty_generated.go') as f:
|
|
||||||
sys.stdout = f
|
|
||||||
generate_completions_for_kitty()
|
generate_completions_for_kitty()
|
||||||
with replace_if_needed('tools/cmd/edit_in_kitty/launch_generated.go') as f:
|
with replace_if_needed('tools/cmd/edit_in_kitty/launch_generated.go'):
|
||||||
sys.stdout = f
|
|
||||||
print('package edit_in_kitty')
|
print('package edit_in_kitty')
|
||||||
print('import "kitty/tools/cli"')
|
print('import "kitty/tools/cli"')
|
||||||
print('func AddCloneSafeOpts(cmd *cli.Command) {')
|
print('func AddCloneSafeOpts(cmd *cli.Command) {')
|
||||||
completion_for_launch_wrappers('cmd')
|
completion_for_launch_wrappers('cmd')
|
||||||
print(''.join(CompletionSpec.from_string('type:file mime:text/* group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
|
print(''.join(CompletionSpec.from_string('type:file mime:text/* group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
|
||||||
print('}')
|
print('}')
|
||||||
finally:
|
|
||||||
sys.stdout = orig
|
|
||||||
|
|
||||||
|
|
||||||
def define_enum(package_name: str, type_name: str, items: str, underlying_type: str = 'uint') -> str:
|
def define_enum(package_name: str, type_name: str, items: str, underlying_type: str = 'uint') -> str:
|
||||||
@ -496,6 +549,7 @@ def main() -> None:
|
|||||||
f.write(generate_spinners())
|
f.write(generate_spinners())
|
||||||
update_completion()
|
update_completion()
|
||||||
update_at_commands()
|
update_at_commands()
|
||||||
|
kitten_clis()
|
||||||
print(json.dumps(changed, indent=2))
|
print(json.dumps(changed, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -147,3 +147,4 @@ elif __name__ == '__doc__':
|
|||||||
cd['usage'] = usage
|
cd['usage'] = usage
|
||||||
cd['options'] = OPTIONS
|
cd['options'] = OPTIONS
|
||||||
cd['help_text'] = help_text
|
cd['help_text'] = help_text
|
||||||
|
cd['short_desc'] = 'Copy/paste with the system clipboard, even over SSH'
|
||||||
|
|||||||
@ -216,6 +216,23 @@ get_docs_ref_map(PyObject *self UNUSED, PyObject *args UNUSED) {
|
|||||||
return PyBytes_FromStringAndSize(docs_ref_map, sizeof(docs_ref_map));
|
return PyBytes_FromStringAndSize(docs_ref_map, sizeof(docs_ref_map));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "wrapped_kitten_names_generated.h"
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
wrapped_kittens(PyObject *self UNUSED, PyObject *args UNUSED) {
|
||||||
|
PyObject *ans = PyFrozenSet_New(NULL);
|
||||||
|
if (ans != NULL) {
|
||||||
|
for (int i = 0; wrapped_kitten_names[i] != NULL; i++) {
|
||||||
|
PyObject *n = PyUnicode_FromString(wrapped_kitten_names[i]);
|
||||||
|
if (n == NULL) break;
|
||||||
|
if (PySet_Add(ans, n) != 0) { Py_DECREF(n); break; }
|
||||||
|
Py_DECREF(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PyErr_Occurred()) { Py_CLEAR(ans); }
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
|
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
|
||||||
{"get_docs_ref_map", (PyCFunction)get_docs_ref_map, METH_NOARGS, ""},
|
{"get_docs_ref_map", (PyCFunction)get_docs_ref_map, METH_NOARGS, ""},
|
||||||
@ -234,6 +251,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
{"locale_is_valid", (PyCFunction)locale_is_valid, METH_VARARGS, ""},
|
{"locale_is_valid", (PyCFunction)locale_is_valid, METH_VARARGS, ""},
|
||||||
{"shm_open", (PyCFunction)py_shm_open, METH_VARARGS, ""},
|
{"shm_open", (PyCFunction)py_shm_open, METH_VARARGS, ""},
|
||||||
{"shm_unlink", (PyCFunction)py_shm_unlink, METH_VARARGS, ""},
|
{"shm_unlink", (PyCFunction)py_shm_unlink, METH_VARARGS, ""},
|
||||||
|
{"wrapped_kitten_names", (PyCFunction)wrapped_kittens, METH_NOARGS, ""},
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
METHODB(user_cache_dir, METH_NOARGS),
|
METHODB(user_cache_dir, METH_NOARGS),
|
||||||
METHODB(process_group_map, METH_NOARGS),
|
METHODB(process_group_map, METH_NOARGS),
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import termios
|
import termios
|
||||||
from ctypes import Array, c_ubyte
|
from ctypes import Array, c_ubyte
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, List, NewType, Optional, Tuple, TypedDict,
|
Any, Callable, Dict, FrozenSet, Iterator, List, NewType, Optional, Tuple, TypedDict,
|
||||||
Union, Iterator
|
Union,
|
||||||
)
|
)
|
||||||
|
|
||||||
from kitty.boss import Boss
|
from kitty.boss import Boss
|
||||||
@ -1493,3 +1493,4 @@ def get_clipboard_mime(ct: int, mime: Optional[str], callback: Callable[[bytes],
|
|||||||
def run_with_activation_token(func: Callable[[str], None]) -> None: ...
|
def run_with_activation_token(func: Callable[[str], None]) -> None: ...
|
||||||
def make_x11_window_a_dock_window(x11_window_id: int, strut: Tuple[int, int, int, int, int, int, int, int, int, int, int, int]) -> None: ...
|
def make_x11_window_a_dock_window(x11_window_id: int, strut: Tuple[int, int, int, int, int, int, int, int, int, int, int, int]) -> None: ...
|
||||||
def unicode_database_version() -> Tuple[int, int, int]: ...
|
def unicode_database_version() -> Tuple[int, int, int]: ...
|
||||||
|
def wrapped_kittens() -> FrozenSet[str]: ...
|
||||||
|
|||||||
26
setup.py
26
setup.py
@ -860,11 +860,37 @@ def build_ref_map() -> str:
|
|||||||
return dest
|
return dest
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def wrapped_kittens() -> Sequence[str]:
|
||||||
|
with open('shell-integration/ssh/kitty') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(' wrapped_kittens="'):
|
||||||
|
val = line.strip().partition('"')[2][:-1]
|
||||||
|
return tuple(sorted(filter(None, val.split())))
|
||||||
|
raise Exception('Failed to read wrapped kittens from kitty wrapper script')
|
||||||
|
|
||||||
|
|
||||||
|
def build_wrapped_kittens() -> str:
|
||||||
|
h = 'static const char* wrapped_kitten_names[] = {\n'
|
||||||
|
h += ', '.join(f'"{x}"' for x in wrapped_kittens())
|
||||||
|
h += ', NULL'
|
||||||
|
h += '\n};\n'
|
||||||
|
dest = 'kitty/wrapped_kitten_names_generated.h'
|
||||||
|
q = ''
|
||||||
|
with suppress(FileNotFoundError), open(dest) as f:
|
||||||
|
q = f.read()
|
||||||
|
if q != h:
|
||||||
|
with open(dest, 'w') as f:
|
||||||
|
f.write(h)
|
||||||
|
return dest
|
||||||
|
|
||||||
|
|
||||||
def build(args: Options, native_optimizations: bool = True, call_init: bool = True) -> None:
|
def build(args: Options, native_optimizations: bool = True, call_init: bool = True) -> None:
|
||||||
if call_init:
|
if call_init:
|
||||||
init_env_from_args(args, native_optimizations)
|
init_env_from_args(args, native_optimizations)
|
||||||
sources, headers = find_c_files()
|
sources, headers = find_c_files()
|
||||||
headers.append(build_ref_map())
|
headers.append(build_ref_map())
|
||||||
|
headers.append(build_wrapped_kittens())
|
||||||
compile_c_extension(
|
compile_c_extension(
|
||||||
kitty_env(), 'kitty/fast_data_types', args.compilation_database, sources, headers
|
kitty_env(), 'kitty/fast_data_types', args.compilation_database, sources, headers
|
||||||
)
|
)
|
||||||
|
|||||||
@ -22,6 +22,21 @@ exec_kitty() {
|
|||||||
die "Failed to execute kitty"
|
die "Failed to execute kitty"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
is_wrapped_kitten() {
|
||||||
|
wrapped_kittens="clipboard"
|
||||||
|
[ -n "$1" ] && {
|
||||||
|
case " $wrapped_kittens " in
|
||||||
|
*" $1 "*) printf "%s" "$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "(" "$1" = "+kitten" -a -n "$(is_wrapped_kitten "$2")" ")" -o "(" "$1" = "+" -a "$2" = "kitten" -a "$(is_wrapped_kitten "$3")" ")" && {
|
||||||
|
if [ "$1" = "+kitten" ]; then shift "1"; else shift "2"; fi
|
||||||
|
exec kitty-tool "$@"
|
||||||
|
}
|
||||||
|
|
||||||
lock_dir=""
|
lock_dir=""
|
||||||
script_path="$(command readlink -f "$0" 2> /dev/null)"
|
script_path="$(command readlink -f "$0" 2> /dev/null)"
|
||||||
[ $? = 0 ] || script_path="$0"
|
[ $? = 0 ] || script_path="$0"
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import (
|
|||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
type RunFunc = func(cmd *Command, args []string) (int, error)
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Name, Group string
|
Name, Group string
|
||||||
Usage, ShortDescription, HelpText string
|
Usage, ShortDescription, HelpText string
|
||||||
@ -26,7 +28,7 @@ type Command struct {
|
|||||||
// If true subcommands are ignored unless they are the first non-option argument
|
// If true subcommands are ignored unless they are the first non-option argument
|
||||||
SubCommandMustBeFirst bool
|
SubCommandMustBeFirst bool
|
||||||
// The entry point for this command
|
// The entry point for this command
|
||||||
Run func(cmd *Command, args []string) (int, error)
|
Run RunFunc
|
||||||
// The completer for args
|
// The completer for args
|
||||||
ArgCompleter CompletionFunc
|
ArgCompleter CompletionFunc
|
||||||
// Stop completion processing at this arg num
|
// Stop completion processing at this arg num
|
||||||
|
|||||||
18
tools/cmd/clipboard/main.go
Normal file
18
tools/cmd/clipboard/main.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package clipboard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"kitty/tools/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
func clipboard_main(cmd *cli.Command, args []string) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EntryPoint(parent *cli.Command) {
|
||||||
|
create_cmd(parent, clipboard_main)
|
||||||
|
}
|
||||||
@ -4,8 +4,10 @@ package tool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"kitty/tools/cli"
|
"kitty/tools/cli"
|
||||||
"kitty/tools/cmd/at"
|
"kitty/tools/cmd/at"
|
||||||
|
"kitty/tools/cmd/clipboard"
|
||||||
"kitty/tools/cmd/edit_in_kitty"
|
"kitty/tools/cmd/edit_in_kitty"
|
||||||
"kitty/tools/cmd/update_self"
|
"kitty/tools/cmd/update_self"
|
||||||
)
|
)
|
||||||
@ -21,4 +23,6 @@ func KittyToolEntryPoints(root *cli.Command) {
|
|||||||
update_self.EntryPoint(root)
|
update_self.EntryPoint(root)
|
||||||
// edit-in-kitty
|
// edit-in-kitty
|
||||||
edit_in_kitty.EntryPoint(root)
|
edit_in_kitty.EntryPoint(root)
|
||||||
|
// clipboard
|
||||||
|
clipboard.EntryPoint(root)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user