Store match group properties on the match group object
This commit is contained in:
parent
c2d3a0c8b4
commit
71cd92da29
@ -168,7 +168,7 @@ def complete_choices(ans: Completions, prefix: str, title: str, key: str, comma_
|
||||
q = line.strip()
|
||||
if q.startswith(prefix):
|
||||
choices[q] = ''
|
||||
ans.match_groups[title] = choices
|
||||
ans.add_match_group(title, choices)
|
||||
|
||||
|
||||
def complete_arg(ans: Completions, option_flag: str, prefix: str = '') -> None:
|
||||
@ -185,17 +185,17 @@ def complete_arg(ans: Completions, option_flag: str, prefix: str = '') -> None:
|
||||
|
||||
|
||||
def complete_destination(ans: Completions, prefix: str = '') -> None:
|
||||
result = {k: '' for k in known_hosts() if k.startswith(prefix)}
|
||||
ans.match_groups['remote host name'] = result
|
||||
result = (k for k in known_hosts() if k.startswith(prefix))
|
||||
ans.add_match_group('remote host name', result)
|
||||
|
||||
|
||||
def complete_option(ans: Completions, prefix: str = '-') -> None:
|
||||
hm = option_help_map()
|
||||
if len(prefix) <= 1:
|
||||
result = {k: v for k, v in hm.items() if k.startswith(prefix)}
|
||||
ans.match_groups['option'] = result
|
||||
ans.add_match_group('option', result)
|
||||
else:
|
||||
ans.match_groups['option'] = {prefix: ''}
|
||||
ans.add_match_group('option', {prefix: ''})
|
||||
|
||||
|
||||
def complete(ans: Completions, words: Sequence[str], new_word: bool) -> None:
|
||||
|
||||
@ -6,8 +6,8 @@ import os
|
||||
import shlex
|
||||
import sys
|
||||
from typing import (
|
||||
Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Set,
|
||||
Tuple
|
||||
Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Tuple,
|
||||
Union
|
||||
)
|
||||
|
||||
from kittens.runner import (
|
||||
@ -45,7 +45,23 @@ them into something your shell will understand.
|
||||
|
||||
parsers: Dict[str, Callable] = {}
|
||||
serializers: Dict[str, Callable] = {}
|
||||
MatchGroup = Dict[str, str]
|
||||
|
||||
|
||||
class MatchGroup:
|
||||
|
||||
def __init__(self, x: Union[Dict[str, str], Iterable[str]], trailing_space: bool = True, is_files: bool = False):
|
||||
self.mdict = x if isinstance(x, dict) else dict.fromkeys(x, '')
|
||||
self.trailing_space = trailing_space
|
||||
self.is_files = is_files
|
||||
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
return iter(self.mdict)
|
||||
|
||||
def items(self) -> Iterator[Tuple[str, str]]:
|
||||
return iter(self.mdict.items())
|
||||
|
||||
def values(self) -> Iterator[str]:
|
||||
return iter(self.mdict.values())
|
||||
|
||||
|
||||
def debug(*a: Any, **kw: Any) -> None:
|
||||
@ -76,10 +92,12 @@ class Completions:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.match_groups: Dict[str, MatchGroup] = {}
|
||||
self.no_space_groups: Set[str] = set()
|
||||
self.files_groups: Set[str] = set()
|
||||
self.delegate: Delegate = Delegate()
|
||||
|
||||
def add_match_group(self, name: str, x: Union[Dict[str, str], Iterable[str]], trailing_space: bool = True, is_files: bool = False) -> MatchGroup:
|
||||
self.match_groups[name] = m = MatchGroup(x, trailing_space, is_files)
|
||||
return m
|
||||
|
||||
|
||||
@run_once
|
||||
def remote_control_command_names() -> Tuple[str, ...]:
|
||||
@ -191,14 +209,14 @@ def zsh_output_serializer(ans: Completions) -> str:
|
||||
|
||||
for description, matches in ans.match_groups.items():
|
||||
cmd = ['compadd', '-U', '-J', shlex.quote(description), '-X', shlex.quote('%B' + description + '%b')]
|
||||
if description in ans.no_space_groups:
|
||||
if not matches.trailing_space:
|
||||
cmd += ['-S', '""']
|
||||
if description in ans.files_groups:
|
||||
if matches.is_files:
|
||||
cmd.append('-f')
|
||||
common_prefix = os.path.commonprefix(tuple(matches))
|
||||
if common_prefix:
|
||||
cmd.extend(('-p', shlex.quote(common_prefix)))
|
||||
matches = {k[len(common_prefix):]: v for k, v in matches.items()}
|
||||
matches = MatchGroup({k[len(common_prefix):]: v for k, v in matches.items()})
|
||||
has_descriptions = any(matches.values())
|
||||
if has_descriptions:
|
||||
lines.append('compdescriptions=(')
|
||||
@ -231,9 +249,8 @@ def zsh_output_serializer(ans: Completions) -> str:
|
||||
def bash_output_serializer(ans: Completions) -> str:
|
||||
lines = []
|
||||
for description, matches in ans.match_groups.items():
|
||||
needs_space = description not in ans.no_space_groups
|
||||
for word in matches:
|
||||
if needs_space:
|
||||
if matches.trailing_space:
|
||||
word += ' '
|
||||
lines.append('COMPREPLY+=({})'.format(shlex.quote(word)))
|
||||
# debug('\n'.join(lines))
|
||||
@ -253,11 +270,11 @@ def fish_output_serializer(ans: Completions) -> str:
|
||||
|
||||
def completions_for_first_word(ans: Completions, prefix: str, entry_points: Iterable[str], namespaced_entry_points: Iterable[str]) -> None:
|
||||
cmds = ['@' + c for c in remote_control_command_names()]
|
||||
ans.match_groups['Entry points'] = {
|
||||
ans.add_match_group('Entry points', {
|
||||
k: '' for k in
|
||||
list(entry_points) + cmds + ['+' + k for k in namespaced_entry_points]
|
||||
if not prefix or k.startswith(prefix)
|
||||
}
|
||||
})
|
||||
if prefix:
|
||||
ans.delegate = Delegate([prefix], 0)
|
||||
|
||||
@ -270,7 +287,7 @@ def kitty_cli_opts(ans: Completions, prefix: Optional[str] = None) -> None:
|
||||
aliases = frozenset(x for x in opt['aliases'] if x.startswith(prefix)) if prefix else opt['aliases']
|
||||
for alias in aliases:
|
||||
matches[alias] = opt['help'].strip()
|
||||
ans.match_groups['Options'] = matches
|
||||
ans.add_match_group('Options', matches)
|
||||
|
||||
|
||||
def complete_kitty_cli_arg(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||
@ -283,8 +300,7 @@ def complete_kitty_cli_arg(ans: Completions, opt: Optional[OptionDict], prefix:
|
||||
if dest == 'override':
|
||||
from kitty.config import option_names_for_completion
|
||||
k = 'Config directives'
|
||||
ans.match_groups[k] = {k+'=': '' for k in option_names_for_completion() if k.startswith(prefix)}
|
||||
ans.no_space_groups.add(k)
|
||||
ans.add_match_group(k, {k+'=': '' for k in option_names_for_completion() if k.startswith(prefix)}, trailing_space=False)
|
||||
elif dest == 'config':
|
||||
|
||||
def is_conf_file(x: str) -> bool:
|
||||
@ -301,13 +317,11 @@ def complete_kitty_cli_arg(ans: Completions, opt: Optional[OptionDict], prefix:
|
||||
complete_files_and_dirs(ans, prefix, files_group_name='Directories', predicate=os.path.isdir)
|
||||
elif dest == 'start_as':
|
||||
k = 'Start as'
|
||||
ans.match_groups[k] = {x: x for x in 'normal,fullscreen,maximized,minimized'.split(',') if x.startswith(prefix)}
|
||||
ans.no_space_groups.add(k)
|
||||
ans.add_match_group(k, {x: x for x in 'normal,fullscreen,maximized,minimized'.split(',') if x.startswith(prefix)}, trailing_space=False)
|
||||
elif dest == 'listen_on':
|
||||
if ':' not in prefix:
|
||||
k = 'Address type'
|
||||
ans.match_groups[k] = {x: x for x in ('unix:', 'tcp:') if x.startswith(prefix)}
|
||||
ans.no_space_groups.add(k)
|
||||
ans.add_match_group(k, {x: x for x in ('unix:', 'tcp:') if x.startswith(prefix)}, trailing_space=False)
|
||||
elif prefix.startswith('unix:') and not prefix.startswith('@'):
|
||||
complete_files_and_dirs(ans, prefix[len('unix:'):], files_group_name='UNIX sockets', add_prefix='unix:')
|
||||
|
||||
@ -336,7 +350,7 @@ def complete_alias_map(
|
||||
opt = option_map.get(w)
|
||||
if w is last_word and not new_word:
|
||||
if w.startswith('-'):
|
||||
ans.match_groups['Options'] = {k: opt['help'] for k, opt in option_map.items() if k.startswith(last_word)}
|
||||
ans.add_match_group('Options', {k: opt['help'] for k, opt in option_map.items() if k.startswith(last_word)})
|
||||
else:
|
||||
if complete_args is not None:
|
||||
complete_args(ans, None, last_word, Delegate(words, i))
|
||||
@ -353,7 +367,7 @@ def complete_alias_map(
|
||||
prefix = '' if new_word else last_word
|
||||
if complete_args is not None:
|
||||
complete_args(ans, None, prefix, Delegate())
|
||||
ans.match_groups['Options'] = {k: opt['help'] for k, opt in option_map.items() if k.startswith(prefix)}
|
||||
ans.add_match_group('Options', {k: opt['help'] for k, opt in option_map.items() if k.startswith(prefix)})
|
||||
|
||||
|
||||
def complete_cli(
|
||||
@ -432,12 +446,9 @@ def complete_files_and_dirs(
|
||||
files = (add_prefix + x for x in files)
|
||||
|
||||
if dirs:
|
||||
ans.match_groups['Directories'] = dict.fromkeys(dirs)
|
||||
ans.files_groups.add('Directories')
|
||||
ans.no_space_groups.add('Directories')
|
||||
ans.add_match_group('Directories', dirs, trailing_space=False, is_files=True)
|
||||
if files:
|
||||
ans.match_groups[files_group_name] = dict.fromkeys(files)
|
||||
ans.files_groups.add(files_group_name)
|
||||
ans.add_match_group(files_group_name, files, is_files=True)
|
||||
|
||||
|
||||
def complete_icat_args(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||
@ -474,7 +485,7 @@ def remote_args_completer(title: str, words: Iterable[str]) -> CompleteArgsFunc:
|
||||
|
||||
def complete_names_for_arg(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||
if opt is None:
|
||||
ans.match_groups[title] = {c: '' for c in items if c.startswith(prefix)}
|
||||
ans.add_match_group(title, {c: '' for c in items if c.startswith(prefix)})
|
||||
|
||||
return complete_names_for_arg
|
||||
|
||||
@ -530,24 +541,24 @@ def find_completions(words: Sequence[str], new_word: bool, entry_points: Iterabl
|
||||
if words[0] == '@':
|
||||
if len(words) == 1 or (len(words) == 2 and not new_word):
|
||||
prefix = words[1] if len(words) > 1 else ''
|
||||
ans.match_groups['Remote control commands'] = {c: '' for c in remote_control_command_names() if c.startswith(prefix)}
|
||||
ans.add_match_group('Remote control commands', {c: '' for c in remote_control_command_names() if c.startswith(prefix)})
|
||||
else:
|
||||
complete_remote_command(ans, words[1], words[2:], new_word)
|
||||
return ans
|
||||
if words[0].startswith('@'):
|
||||
if len(words) == 1 and not new_word:
|
||||
prefix = words[0]
|
||||
ans.match_groups['Remote control commands'] = {'@' + c: '' for c in remote_control_command_names() if c.startswith(prefix)}
|
||||
ans.add_match_group('Remote control commands', {'@' + c: '' for c in remote_control_command_names() if c.startswith(prefix)})
|
||||
else:
|
||||
complete_remote_command(ans, words[0][1:], words[1:], new_word)
|
||||
if words[0] == '+':
|
||||
if len(words) == 1 or (len(words) == 2 and not new_word):
|
||||
prefix = words[1] if len(words) > 1 else ''
|
||||
ans.match_groups['Entry points'] = {c: '' for c in namespaced_entry_points if c.startswith(prefix)}
|
||||
ans.add_match_group('Entry points', {c: '' for c in namespaced_entry_points if c.startswith(prefix)})
|
||||
else:
|
||||
if words[1] == 'kitten':
|
||||
if len(words) == 2 or (len(words) == 3 and not new_word):
|
||||
ans.match_groups['Kittens'] = dict.fromkeys(k for k in all_kitten_names() if k.startswith('' if len(words) == 2 else words[2]))
|
||||
ans.add_match_group('Kittens', (k for k in all_kitten_names() if k.startswith('' if len(words) == 2 else words[2])))
|
||||
else:
|
||||
complete_kitten(ans, words[2], words[3:], new_word)
|
||||
return ans
|
||||
@ -555,13 +566,13 @@ def find_completions(words: Sequence[str], new_word: bool, entry_points: Iterabl
|
||||
if len(words) == 1:
|
||||
if new_word:
|
||||
if words[0] == '+kitten':
|
||||
ans.match_groups['Kittens'] = dict.fromkeys(all_kitten_names())
|
||||
ans.add_match_group('Kittens', all_kitten_names())
|
||||
else:
|
||||
prefix = words[0]
|
||||
ans.match_groups['Entry points'] = {c: '' for c in namespaced_entry_points if c.startswith(prefix)}
|
||||
ans.add_match_group('Entry points', (c for c in namespaced_entry_points if c.startswith(prefix)))
|
||||
else:
|
||||
if len(words) == 2 and not new_word:
|
||||
ans.match_groups['Kittens'] = dict.fromkeys(k for k in all_kitten_names() if k.startswith(words[1]))
|
||||
ans.add_match_group('Kittens', (k for k in all_kitten_names() if k.startswith(words[1])))
|
||||
else:
|
||||
if words[0] == '+kitten':
|
||||
complete_kitten(ans, words[1], words[2:], new_word)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user