diff --git a/kittens/ssh/completion.py b/kittens/ssh/completion.py index 9d82b2e17..ba36deb90 100644 --- a/kittens/ssh/completion.py +++ b/kittens/ssh/completion.py @@ -164,11 +164,23 @@ def option_help_map() -> Dict[str, str]: def complete_choices(ans: Completions, prefix: str, title: str, key: str, comma_separated: bool) -> None: choices = {} + word_transforms = {} + effective_prefix = prefix + hidden_prefix = '' + if comma_separated: + effective_prefix = prefix.split(',')[-1] + hidden_prefix = ','.join(prefix.split(',')[:-1]) + if hidden_prefix: + hidden_prefix += ',' for line in lines_from_command('ssh', '-Q', key): q = line.strip() - if q.startswith(prefix): + if q.startswith(effective_prefix): + if comma_separated: + tq = q + q = hidden_prefix + q + ',' + word_transforms[q] = tq choices[q] = '' - ans.add_match_group(title, choices) + ans.add_match_group(title, choices, trailing_space=not comma_separated, word_transforms=word_transforms) def complete_arg(ans: Completions, option_flag: str, prefix: str = '') -> None: diff --git a/kitty/complete.py b/kitty/complete.py index 0a505c642..2bee3b797 100644 --- a/kitty/complete.py +++ b/kitty/complete.py @@ -49,14 +49,28 @@ class MatchGroup: - def __init__(self, x: Union[Dict[str, str], Iterable[str]], trailing_space: bool = True, is_files: bool = False): + def __init__( + self, x: Union[Dict[str, str], Iterable[str]], + trailing_space: bool = True, + is_files: bool = False, + word_transforms: Optional[Dict[str, str]] = None, + ): self.mdict = x if isinstance(x, dict) else dict.fromkeys(x, '') self.trailing_space = trailing_space self.is_files = is_files + self.word_transforms = word_transforms or {} def __iter__(self) -> Iterator[str]: return iter(self.mdict) + def transformed_words(self) -> Iterator[str]: + for w in self: + yield self.word_transforms.get(w, w) + + def transformed_items(self) -> Iterator[Tuple[str, str]]: + for w, desc in self.items(): + yield self.word_transforms.get(w, w), desc + def items(self) -> Iterator[Tuple[str, str]]: return iter(self.mdict.items()) @@ -94,8 +108,13 @@ def __init__(self) -> None: self.match_groups: Dict[str, MatchGroup] = {} 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) + def add_match_group( + self, name: str, x: Union[Dict[str, str], Iterable[str]], + trailing_space: bool = True, + is_files: bool = False, + word_transforms: Optional[Dict[str, str]] = None + ) -> MatchGroup: + self.match_groups[name] = m = MatchGroup(x, trailing_space, is_files, word_transforms) return m @@ -188,6 +207,9 @@ def zsh_output_serializer(ans: Completions) -> str: width = screen.cols def fmt_desc(word: str, desc: str, max_word_len: int) -> Iterator[str]: + if not desc: + yield word + return desc = prettify(desc.splitlines()[0]) multiline = False if wcswidth(word) > max_word_len: @@ -218,14 +240,15 @@ def fmt_desc(word: str, desc: str, max_word_len: int) -> Iterator[str]: cmd.extend(('-p', shlex.quote(common_prefix))) matches = MatchGroup({k[len(common_prefix):]: v for k, v in matches.items()}) has_descriptions = any(matches.values()) - if has_descriptions: + if has_descriptions or matches.word_transforms: lines.append('compdescriptions=(') - sz = max(map(wcswidth, matches)) + sz = max(map(wcswidth, matches.transformed_words())) limit = min(16, sz) - for word, desc in matches.items(): + for word, desc in matches.transformed_items(): lines.extend(map(shlex.quote, fmt_desc(word, desc, limit))) lines.append(')') - cmd.append('-l') + if has_descriptions: + cmd.append('-l') cmd.append('-d') cmd.append('compdescriptions') cmd.append('--')