mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-11-13 03:12:37 +03:00
More completion work
This commit is contained in:
parent
946d44c43f
commit
0ff2446a1a
@ -61,6 +61,7 @@ def generate_completions_for_kitty() -> None:
|
|||||||
print('k := root.add_command("kitty", "")')
|
print('k := root.add_command("kitty", "")')
|
||||||
print('k.First_arg_may_not_be_subcommand = true')
|
print('k.First_arg_may_not_be_subcommand = true')
|
||||||
print('k.Completion_for_arg = complete_kitty')
|
print('k.Completion_for_arg = complete_kitty')
|
||||||
|
print('k.Subcommand_must_be_first = true')
|
||||||
for opt in go_options_for_seq(parse_option_spec()[0]):
|
for opt in go_options_for_seq(parse_option_spec()[0]):
|
||||||
print(opt.as_completion_option('k'))
|
print(opt.as_completion_option('k'))
|
||||||
print('at := k.add_command("@", "Remote control")')
|
print('at := k.add_command("@", "Remote control")')
|
||||||
|
15
kitty/cli.py
15
kitty/cli.py
@ -8,6 +8,7 @@ import socket
|
|||||||
import sys
|
import sys
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, FrozenSet, Iterator, List, Match, Optional, Sequence,
|
Any, Callable, Dict, FrozenSet, Iterator, List, Match, Optional, Sequence,
|
||||||
Tuple, Type, TypeVar, Union, cast
|
Tuple, Type, TypeVar, Union, cast
|
||||||
@ -37,6 +38,7 @@ class CompletionRelativeTo(Enum):
|
|||||||
config_dir = auto()
|
config_dir = auto()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class CompletionSpec:
|
class CompletionSpec:
|
||||||
|
|
||||||
type: CompletionType = CompletionType.none
|
type: CompletionType = CompletionType.none
|
||||||
@ -70,7 +72,7 @@ class CompletionSpec:
|
|||||||
raise KeyError(f'Unknown completion property: {ck}')
|
raise KeyError(f'Unknown completion property: {ck}')
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def as_go_code(self, go_name: str) -> Iterator[str]:
|
def as_go_code(self, go_name: str, sep: str = ' = ') -> Iterator[str]:
|
||||||
completers = []
|
completers = []
|
||||||
if self.kwds:
|
if self.kwds:
|
||||||
kwds = (f'"{serialize_as_go_string(x)}"' for x in self.kwds)
|
kwds = (f'"{serialize_as_go_string(x)}"' for x in self.kwds)
|
||||||
@ -84,10 +86,15 @@ class CompletionSpec:
|
|||||||
completers.append(f'fnmatch_completer("{g}", {relative_to}, ' + ', '.join(pats) + ')')
|
completers.append(f'fnmatch_completer("{g}", {relative_to}, ' + ', '.join(pats) + ')')
|
||||||
if self.mime_patterns:
|
if self.mime_patterns:
|
||||||
completers.append(f'mimepat_completer("{g}", {relative_to}, ' + ', '.join(f'"{p}"' for p in self.mime_patterns) + ')')
|
completers.append(f'mimepat_completer("{g}", {relative_to}, ' + ', '.join(f'"{p}"' for p in self.mime_patterns) + ')')
|
||||||
|
if self.type is CompletionType.directory:
|
||||||
|
g = serialize_as_go_string(self.group or 'Directories')
|
||||||
|
completers.append(f'directory_completer("{g}", {relative_to})')
|
||||||
|
if go_name:
|
||||||
|
go_name += '.'
|
||||||
if len(completers) > 1:
|
if len(completers) > 1:
|
||||||
yield f'{go_name}.Completion_for_arg = chain_completers(' + ', '.join(completers) + ')'
|
yield f'{go_name}Completion_for_arg{sep}chain_completers(' + ', '.join(completers) + ')'
|
||||||
elif completers:
|
elif completers:
|
||||||
yield f'{go_name}.Completion_for_arg = {completers[0]}'
|
yield f'{go_name}Completion_for_arg{sep}{completers[0]}'
|
||||||
|
|
||||||
|
|
||||||
class OptionDict(TypedDict):
|
class OptionDict(TypedDict):
|
||||||
@ -191,6 +198,8 @@ class GoOption:
|
|||||||
if self.type == 'choices':
|
if self.type == 'choices':
|
||||||
cx = ', '.join(f'"{serialize_as_go_string(x)}"' for x in self.sorted_choices)
|
cx = ', '.join(f'"{serialize_as_go_string(x)}"' for x in self.sorted_choices)
|
||||||
ans += f'Completion_for_arg: names_completer("Choices for {self.long}", {cx}),'
|
ans += f'Completion_for_arg: names_completer("Choices for {self.long}", {cx}),'
|
||||||
|
elif self.obj_dict['completion'].type is not CompletionType.none:
|
||||||
|
ans += ''.join(self.obj_dict['completion'].as_go_code('', ': ')) + ','
|
||||||
return ans + '})'
|
return ans + '})'
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,6 +118,9 @@ def completion(self: TestCompletion, tdir: str):
|
|||||||
add('kitty --s', has_words('--session', '--start-as'))
|
add('kitty --s', has_words('--session', '--start-as'))
|
||||||
add('kitty --start-as', all_words('--start-as'))
|
add('kitty --start-as', all_words('--start-as'))
|
||||||
add('kitty --start-as ', all_words('minimized', 'maximized', 'fullscreen', 'normal'))
|
add('kitty --start-as ', all_words('minimized', 'maximized', 'fullscreen', 'normal'))
|
||||||
|
add('kitty -1 ', does_not_have_words('@ls', '@'))
|
||||||
|
add('kitty --directory ', all_words('bin/', 'sub/'))
|
||||||
|
add('kitty -1d ', all_words('bin/', 'sub/'))
|
||||||
|
|
||||||
for cmd, tests, result in zip(all_cmds, all_tests, run_tool()):
|
for cmd, tests, result in zip(all_cmds, all_tests, run_tool()):
|
||||||
self.current_cmd = cmd
|
self.current_cmd = cmd
|
||||||
|
@ -250,3 +250,20 @@ func fnmatch_completer(title string, relative_to relative_to, patterns ...string
|
|||||||
func mimepat_completer(title string, relative_to relative_to, patterns ...string) completion_func {
|
func mimepat_completer(title string, relative_to relative_to, patterns ...string) completion_func {
|
||||||
return make_completer(title, relative_to, patterns, complete_by_mimepat)
|
return make_completer(title, relative_to, patterns, complete_by_mimepat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func directory_completer(title string, relative_to relative_to) completion_func {
|
||||||
|
if title == "" {
|
||||||
|
title = "Directories"
|
||||||
|
}
|
||||||
|
cwd := get_cwd_for_completion(relative_to)
|
||||||
|
|
||||||
|
return func(completions *Completions, word string, arg_num int) {
|
||||||
|
mg := completions.add_match_group(title)
|
||||||
|
mg.IsFiles = true
|
||||||
|
complete_files(word, func(entry *FileEntry) {
|
||||||
|
if entry.mode.IsDir() {
|
||||||
|
mg.add_match(entry.completion_candidate)
|
||||||
|
}
|
||||||
|
}, cwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,6 +14,9 @@ import (
|
|||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
|
|
||||||
func complete_kitty(completions *Completions, word string, arg_num int) {
|
func complete_kitty(completions *Completions, word string, arg_num int) {
|
||||||
|
if arg_num > 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
exes := complete_executables_in_path(word)
|
exes := complete_executables_in_path(word)
|
||||||
if len(exes) > 0 {
|
if len(exes) > 0 {
|
||||||
mg := completions.add_match_group("Executables in PATH")
|
mg := completions.add_match_group("Executables in PATH")
|
||||||
|
@ -100,7 +100,7 @@ func complete_word(word string, completions *Completions, only_args_allowed bool
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if arg_num == 1 && cmd.has_subcommands() {
|
if cmd.has_subcommands() && cmd.sub_command_allowed_at(completions, arg_num) {
|
||||||
for _, cg := range cmd.Groups {
|
for _, cg := range cmd.Groups {
|
||||||
group := completions.add_match_group(cg.Title)
|
group := completions.add_match_group(cg.Title)
|
||||||
if group.Title == "" {
|
if group.Title == "" {
|
||||||
@ -163,7 +163,7 @@ func (cmd *Command) parse_args(words []string, completions *Completions) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cmd.has_subcommands() && arg_num == 1 {
|
if cmd.has_subcommands() && cmd.sub_command_allowed_at(completions, arg_num) {
|
||||||
sc := cmd.find_subcommand_with_name(word)
|
sc := cmd.find_subcommand_with_name(word)
|
||||||
if sc == nil {
|
if sc == nil {
|
||||||
only_args_allowed = true
|
only_args_allowed = true
|
||||||
|
@ -68,6 +68,7 @@ type Command struct {
|
|||||||
Completion_for_arg completion_func
|
Completion_for_arg completion_func
|
||||||
Stop_processing_at_arg int
|
Stop_processing_at_arg int
|
||||||
First_arg_may_not_be_subcommand bool
|
First_arg_may_not_be_subcommand bool
|
||||||
|
Subcommand_must_be_first bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Command) add_group(name string) *CommandGroup {
|
func (self *Command) add_group(name string) *CommandGroup {
|
||||||
@ -122,6 +123,13 @@ func (self *Command) has_subcommands() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Command) add_option(opt *Option) {
|
func (self *Command) add_option(opt *Option) {
|
||||||
self.Options = append(self.Options, opt)
|
self.Options = append(self.Options, opt)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user