diff --git a/kitty/complete.py b/kitty/complete.py index d4ef20fe4..d088fd7d3 100644 --- a/kitty/complete.py +++ b/kitty/complete.py @@ -161,6 +161,14 @@ end complete -f -c kitty -a "(__kitty_completions)" ''', + 'fish2': ''' +if functions -q _ksi_completions + complete -f -c kitty -a "(_ksi_completions)" +else + complete -f -c kitty -a "(commandline -cop | kitty +complete fish)" +end +''', + } ParseResult = Tuple[List[str], bool] @@ -199,6 +207,11 @@ def fish_input_parser(data: str) -> ParseResult: return data.rstrip().splitlines(), True +@input_parser +def fish2_input_parser(data: str) -> ParseResult: + return bash_input_parser(data) + + @output_serializer def zsh_output_serializer(ans: Completions) -> str: lines = [] @@ -288,6 +301,17 @@ def fish_output_serializer(ans: Completions) -> str: lines.append(word.replace('\n', ' ')) # debug('\n'.join(lines)) return '\n'.join(lines) + + +@output_serializer +def fish2_output_serializer(ans: Completions) -> str: + lines = [] + for description, matches in ans.match_groups.items(): + for word in matches: + lines.append(word.replace('\n', ' ')) + # debug('\n'.join(lines)) + return '\n'.join(lines) + # }}} diff --git a/kitty/shell_integration.py b/kitty/shell_integration.py index 3a939a4c4..a26e52169 100644 --- a/kitty/shell_integration.py +++ b/kitty/shell_integration.py @@ -6,6 +6,7 @@ import os import shutil import time +from contextlib import suppress from tempfile import mkstemp from typing import Optional, Union @@ -27,7 +28,8 @@ def atomic_write(path: str, data: Union[str, bytes]) -> None: os.makedirs(base, exist_ok=True) fd, tpath = mkstemp(dir=base, text=isinstance(data, str)) with open(fd, mode) as f: - shutil.copystat(path, tpath) + with suppress(FileNotFoundError): + shutil.copystat(path, tpath) f.write(data) try: os.rename(tpath, path) @@ -36,16 +38,17 @@ def atomic_write(path: str, data: Union[str, bytes]) -> None: raise +def safe_read(path: str) -> str: + with suppress(FileNotFoundError): + with open(path) as f: + return f.read() + return '' + + def setup_integration(shell_name: str, rc_path: str, template: str = posix_template) -> None: import re rc_path = os.path.realpath(rc_path) - try: - with open(rc_path) as f: - rc = f.read() - except FileNotFoundError: - rc = '' - except Exception: - raise + rc = safe_read(rc_path) home = os.path.expanduser('~') + '/' path = os.path.join(shell_integration_dir, f'kitty.{shell_name}') if path.startswith(home): @@ -83,9 +86,14 @@ def atomic_symlink(destination: str, in_directory: str) -> str: def setup_fish_integration() -> None: base = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) - base = os.path.join(base, 'fish', 'conf.d') + base = os.path.join(base, 'fish') path = os.path.join(shell_integration_dir, 'kitty.fish') - atomic_symlink(path, base) + atomic_symlink(path, os.path.join(base, 'conf.d')) + from .complete import completion_scripts + path = os.path.join(base, 'completions', 'kitty.fish') + rc = safe_read(path) + if rc != completion_scripts['fish2']: + atomic_write(path, completion_scripts['fish2']) SUPPORTED_SHELLS = { diff --git a/shell-integration/kitty.fish b/shell-integration/kitty.fish index 91cb5ddac..821c8e968 100644 --- a/shell-integration/kitty.fish +++ b/shell-integration/kitty.fish @@ -9,6 +9,14 @@ function _ksi_main printf "\e]%s\a" "$argv[1]" end + if not contains "no-complete" $_ksi + function _ksi_completions + set --local ct (commandline --current-token) + set --local tokens (commandline --tokenize --cut-at-cursor --current-process) + printf "%s\n" $tokens $ct | kitty +complete fish2 + end + end + if not contains "no-cursor" $_ksi function _ksi_bar_cursor --on-event fish_prompt printf "\e[5 q"