Add completion for the kittens
This commit is contained in:
parent
25a7ec9a07
commit
7737369fc9
@ -57,6 +57,23 @@ def generate_completion_for_rc(name: str) -> None:
|
||||
print(opt.as_completion_option(name))
|
||||
|
||||
|
||||
def generate_kittens_completion() -> None:
|
||||
from kittens.runner import all_kitten_names, get_kitten_cli_docs
|
||||
for kitten in all_kitten_names():
|
||||
kn = 'kitten_' + kitten
|
||||
print(f'{kn} := plus_kitten.add_command("{kitten}", "Kittens")')
|
||||
kcd = get_kitten_cli_docs(kitten)
|
||||
if kcd:
|
||||
ospec = kcd['options']
|
||||
for opt in go_options_for_seq(parse_option_spec(ospec())[0]):
|
||||
print(opt.as_completion_option(kn))
|
||||
ac = kcd.get('args_completion')
|
||||
if ac is not None:
|
||||
print(''.join(ac.as_go_code(kn)))
|
||||
else:
|
||||
print(f'{kn}.Description = ""')
|
||||
|
||||
|
||||
def generate_completions_for_kitty() -> None:
|
||||
print('package completion\n')
|
||||
print('func kitty(root *Command) {')
|
||||
@ -71,22 +88,27 @@ def generate_completions_for_kitty() -> None:
|
||||
print(f'k.find_option("-o").Completion_for_arg = complete_kitty_override("Config directives", []string{{{conf_names}}})')
|
||||
print('k.find_option("--listen-on").Completion_for_arg = complete_kitty_listen_on')
|
||||
|
||||
print('plus := k.add_command("+", "Entry point")')
|
||||
print('plus := k.add_command("+", "Entry points")')
|
||||
print('plus.Description = "Various special purpose tools and kittens"')
|
||||
|
||||
print('plus_launch := plus.add_command("launch", "Launch Python script")')
|
||||
print('plus_launch := plus.add_command("launch", "Entry points")')
|
||||
print('plus_launch.Completion_for_arg = complete_plus_launch')
|
||||
print('k.add_clone("+launch", "Launch Python scripts", plus_launch)')
|
||||
|
||||
print('plus_runpy := plus.add_command("runpy", "Run python code")')
|
||||
print('plus_runpy := plus.add_command("runpy", "Entry points")')
|
||||
print('plus_runpy.Completion_for_arg = complete_plus_runpy')
|
||||
print('k.add_clone("+runpy", "Run Python code", plus_runpy)')
|
||||
|
||||
print('plus_open := plus.add_command("open", "Open files and URLs")')
|
||||
print('plus_open := plus.add_command("open", "Entry points")')
|
||||
print('plus_open.Completion_for_arg = complete_plus_open')
|
||||
print('plus_open.clone_options_from(k)')
|
||||
print('k.add_clone("+open", "Open files and URLs", plus_open)')
|
||||
|
||||
print('plus_kitten := plus.add_command("kitten", "Kittens")')
|
||||
print('plus_kitten.Subcommand_must_be_first = true')
|
||||
generate_kittens_completion()
|
||||
print('k.add_clone("+kitten", "Kittens", plus_kitten)')
|
||||
|
||||
print('at := k.add_command("@", "Remote control")')
|
||||
print('at.Description = "Control kitty using commands"')
|
||||
for go_name in all_command_names():
|
||||
|
||||
@ -17,7 +17,7 @@ from typing import (
|
||||
Any, DefaultDict, Dict, Iterable, Iterator, List, Optional, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.cli import CONFIG_HELP, parse_args
|
||||
from kitty.cli import CONFIG_HELP, parse_args, CompletionSpec
|
||||
from kitty.cli_stub import DiffCLIOptions
|
||||
from kitty.conf.utils import KeyAction
|
||||
from kitty.constants import appname
|
||||
@ -577,6 +577,7 @@ number set in :file:`diff.conf`.
|
||||
|
||||
--config
|
||||
type=list
|
||||
completion=type:file ext:conf group:"Config files" kwds:none,NONE
|
||||
{config_help}
|
||||
|
||||
|
||||
@ -687,6 +688,7 @@ elif __name__ == '__doc__':
|
||||
cd['usage'] = usage
|
||||
cd['options'] = OPTIONS
|
||||
cd['help_text'] = help_text
|
||||
cd['args_completion'] = CompletionSpec.from_string('type:file mime:text/* mime:image/* group:"Text and image files"')
|
||||
elif __name__ == '__conf__':
|
||||
from .options.definition import definition
|
||||
sys.options_definition = definition # type: ignore
|
||||
|
||||
@ -15,7 +15,7 @@ from typing import (
|
||||
Dict, Generator, List, NamedTuple, Optional, Pattern, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli import parse_args, CompletionSpec
|
||||
from kitty.cli_stub import IcatCLIOptions
|
||||
from kitty.constants import appname
|
||||
from kitty.guess_mime_type import guess_type
|
||||
@ -622,3 +622,4 @@ elif __name__ == '__doc__':
|
||||
cd['usage'] = usage
|
||||
cd['options'] = options_spec
|
||||
cd['help_text'] = help_text
|
||||
cd['args_completion'] = CompletionSpec.from_string('type:file mime:image/* group:Images')
|
||||
|
||||
@ -8,17 +8,20 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
from contextlib import suppress
|
||||
from typing import Any, Callable, Dict, Iterator, Match, Optional, Tuple, Union, Type
|
||||
from typing import (
|
||||
Any, Callable, Dict, Iterator, Match, Optional, Tuple, Type, Union
|
||||
)
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from kitty.config import atomic_save, parse_config
|
||||
from kitty.constants import cache_dir, config_dir
|
||||
from kitty.options.types import Options as KittyOptions
|
||||
from kitty.fast_data_types import Color
|
||||
from kitty.options.types import Options as KittyOptions
|
||||
from kitty.utils import reload_conf_in_all_kitties
|
||||
|
||||
from ..choose.match import match
|
||||
@ -647,3 +650,13 @@ def load_themes(cache_age: float = 1., ignore_no_cache: bool = False) -> Themes:
|
||||
ans.load_from_dir(os.path.join(config_dir, 'themes'))
|
||||
ans.index_map = tuple(ans.themes)
|
||||
return ans
|
||||
|
||||
|
||||
def print_theme_names() -> None:
|
||||
found = False
|
||||
for theme in load_themes(cache_age=-1, ignore_no_cache=True):
|
||||
print(theme.name)
|
||||
found = True
|
||||
if not found:
|
||||
print('Default')
|
||||
sys.stdout.flush()
|
||||
|
||||
@ -11,12 +11,12 @@ from typing import (
|
||||
Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.cli import create_default_opts, parse_args
|
||||
from kitty.cli import CompletionSpec, create_default_opts, parse_args
|
||||
from kitty.cli_stub import ThemesCLIOptions
|
||||
from kitty.config import cached_values_for
|
||||
from kitty.options.types import Options as KittyOptions
|
||||
from kitty.constants import config_dir
|
||||
from kitty.fast_data_types import truncate_point_for_length, wcswidth
|
||||
from kitty.options.types import Options as KittyOptions
|
||||
from kitty.rgb import color_as_sharp, color_from_int
|
||||
from kitty.typing import KeyEventType
|
||||
from kitty.utils import ScreenSize
|
||||
@ -616,3 +616,4 @@ elif __name__ == '__doc__':
|
||||
cd['usage'] = usage
|
||||
cd['options'] = OPTIONS
|
||||
cd['help_text'] = help_text
|
||||
cd['args_completion'] = CompletionSpec.from_string('type:special group:complete_themes')
|
||||
|
||||
@ -30,6 +30,7 @@ class CompletionType(Enum):
|
||||
file = auto()
|
||||
directory = auto()
|
||||
keyword = auto()
|
||||
special = auto()
|
||||
none = auto()
|
||||
|
||||
|
||||
@ -89,6 +90,8 @@ class CompletionSpec:
|
||||
if self.type is CompletionType.directory:
|
||||
g = serialize_as_go_string(self.group or 'Directories')
|
||||
completers.append(f'directory_completer("{g}", {relative_to})')
|
||||
if self.type is CompletionType.special:
|
||||
completers.append(self.group)
|
||||
if go_name:
|
||||
go_name += '.'
|
||||
if len(completers) > 1:
|
||||
@ -113,7 +116,9 @@ 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_type_map = {
|
||||
'bool-set': 'bool', 'bool-reset': 'bool', 'int': 'int', 'float': 'float64',
|
||||
'': 'string', 'list': '[]string', 'choices': 'string', 'str': 'string'}
|
||||
go_getter_map = {
|
||||
'bool-set': 'GetBool', 'bool-reset': 'GetBool', 'int': 'GetInt', 'float': 'GetFloat64', '': 'GetString',
|
||||
'list': 'GetStringArray', 'choices': 'GetString'
|
||||
@ -460,6 +465,8 @@ def parse_option_spec(spec: Optional[str] = None) -> Tuple[OptionSpecSeq, Option
|
||||
if k == 'default':
|
||||
current_cmd['default'] = v
|
||||
elif k == 'type':
|
||||
if v == 'choice':
|
||||
v = 'choices'
|
||||
current_cmd['type'] = v
|
||||
elif k == 'dest':
|
||||
current_cmd['dest'] = v
|
||||
|
||||
@ -136,6 +136,14 @@ def completion(self: TestCompletion, tdir: str):
|
||||
add('kitty @launch --logo ', all_words('exe-not3.png'))
|
||||
add('kitty @launch --logo ~', all_words('~/exe-not3.png'))
|
||||
|
||||
add('kitty + ', has_words('launch', 'kitten'))
|
||||
add('kitty + kitten ', has_words('icat', 'diff'))
|
||||
add('kitty +kitten icat ', has_words('sub/', 'exe-not2.jpeg'))
|
||||
add('kitty + kitten icat --pr', has_words('--print-window-size'))
|
||||
add('kitty + kitten diff ', has_words('exe-not2.jpeg'))
|
||||
add('kitty + kitten themes --', has_words('--cache-age'))
|
||||
add('kitty + kitten themes D', has_words('Default'))
|
||||
|
||||
for cmd, tests, result in zip(all_cmds, all_tests, run_tool()):
|
||||
self.current_cmd = cmd
|
||||
for test in tests:
|
||||
|
||||
@ -185,7 +185,17 @@ func complete_by_fnmatch(prefix, cwd string, patterns []string) []string {
|
||||
}
|
||||
|
||||
func complete_by_mimepat(prefix, cwd string, patterns []string) []string {
|
||||
all_allowed := false
|
||||
for _, p := range patterns {
|
||||
if p == "*" {
|
||||
all_allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return fname_based_completer(prefix, cwd, func(name string) bool {
|
||||
if all_allowed {
|
||||
return true
|
||||
}
|
||||
idx := strings.Index(name, ".")
|
||||
if idx < 1 {
|
||||
return false
|
||||
|
||||
@ -3,8 +3,12 @@
|
||||
package completion
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"kitty/tools/utils"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@ -97,3 +101,20 @@ func complete_plus_runpy(completions *Completions, word string, arg_num int) {
|
||||
func complete_plus_open(completions *Completions, word string, arg_num int) {
|
||||
fnmatch_completer("Files", CWD, "*")(completions, word, arg_num)
|
||||
}
|
||||
|
||||
func complete_themes(completions *Completions, word string, arg_num int) {
|
||||
kitty, err := utils.KittyExe()
|
||||
if err == nil {
|
||||
out, err := exec.Command(kitty, "+runpy", "from kittens.themes.collection import *; print_theme_names()").Output()
|
||||
if err == nil {
|
||||
mg := completions.add_match_group("Themes")
|
||||
scanner := bufio.NewScanner(bytes.NewReader(out))
|
||||
for scanner.Scan() {
|
||||
theme_name := strings.TrimSpace(scanner.Text())
|
||||
if theme_name != "" && strings.HasPrefix(theme_name, word) {
|
||||
mg.add_match(theme_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,6 +139,7 @@ func (cmd *Command) parse_args(words []string, completions *Completions) {
|
||||
for i, word := range words {
|
||||
cmd = completions.current_cmd
|
||||
completions.current_word_idx = i
|
||||
completions.current_word_idx_in_parent++
|
||||
is_last_word := i == len(words)-1
|
||||
if expecting_arg_for == nil && !strings.HasPrefix(word, "-") {
|
||||
arg_num++
|
||||
@ -172,6 +173,7 @@ func (cmd *Command) parse_args(words []string, completions *Completions) {
|
||||
completions.current_cmd = sc
|
||||
cmd = sc
|
||||
arg_num = 0
|
||||
completions.current_word_idx_in_parent = 0
|
||||
only_args_allowed = false
|
||||
} else if cmd.Stop_processing_at_arg > 0 && arg_num >= cmd.Stop_processing_at_arg {
|
||||
return
|
||||
|
||||
@ -34,6 +34,7 @@ type Completions struct {
|
||||
current_cmd *Command
|
||||
all_words []string // all words passed to parse_args()
|
||||
current_word_idx int // index of current word in all_words
|
||||
current_word_idx_in_parent int // index of current word in parents command line 1 for first word after parent
|
||||
}
|
||||
|
||||
func (self *Completions) add_prefix_to_all_matches(prefix string) {
|
||||
@ -141,7 +142,7 @@ func (self *Command) has_subcommands() bool {
|
||||
|
||||
func (self *Command) sub_command_allowed_at(completions *Completions, arg_num int) bool {
|
||||
if self.Subcommand_must_be_first {
|
||||
return arg_num == 1 && completions.current_word_idx == 0
|
||||
return arg_num == 1 && completions.current_word_idx_in_parent == 1
|
||||
}
|
||||
return arg_num == 1
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var Sep = string(os.PathSeparator)
|
||||
@ -56,6 +58,15 @@ func Abspath(path string) string {
|
||||
|
||||
var config_dir string
|
||||
|
||||
func KittyExe() (string, error) {
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ans := filepath.Join(filepath.Dir(exe), "kitty")
|
||||
return ans, unix.Access(ans, unix.X_OK)
|
||||
}
|
||||
|
||||
func ConfigDir() string {
|
||||
if config_dir != "" {
|
||||
return config_dir
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user