diff --git a/kitty/complete.py b/kitty/complete.py index db3d9c634..a4cd2b908 100644 --- a/kitty/complete.py +++ b/kitty/complete.py @@ -17,6 +17,7 @@ from .cli import ( OptionDict, OptionSpecSeq, options_for_completion, parse_option_spec, prettify ) +from .constants import shell_integration_dir from .fast_data_types import truncate_point_for_length, wcswidth from .rc.base import all_command_names, command_for_name from .shell import options_for_cmd @@ -128,6 +129,11 @@ def remote_control_command_names() -> Tuple[str, ...]: # Shell specific code {{{ +def load_fish2_completion() -> str: + with open(os.path.join(shell_integration_dir, 'fish', 'vendor_completions.d', 'kitty.fish')) as f: + return f.read() + + completion_scripts = { 'zsh': '''#compdef kitty @@ -140,7 +146,7 @@ _kitty() { fi } compdef _kitty kitty -''', +'''.__str__, 'bash': ''' _kitty_completions() { local src @@ -154,7 +160,7 @@ _kitty_completions() { } complete -o nospace -F _kitty_completions kitty -''', +'''.__str__, 'fish': ''' function __kitty_completions # Send all words up to the one before the cursor @@ -162,15 +168,8 @@ function __kitty_completions 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 -''', - +'''.__str__, + 'fish2': load_fish2_completion, } ParseResult = Tuple[List[str], bool] @@ -670,7 +669,7 @@ def find_completions(words: Sequence[str], new_word: bool, entry_points: Iterabl def setup(cstyle: str) -> None: - print(completion_scripts[cstyle]) + print(completion_scripts[cstyle]()) def main(args: Sequence[str], entry_points: Iterable[str], namespaced_entry_points: Iterable[str]) -> None: diff --git a/kitty/main.py b/kitty/main.py index 978f1e802..c95710b3d 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -29,6 +29,7 @@ from .fonts.render import set_font_family from .options.types import Options from .os_window_size import initial_window_size_func from .session import get_os_window_sizing_data +from .shell_integration import setup_shell_integration from .types import SingleKey from .utils import ( detach, expandvars, log_error, single_instance, @@ -150,9 +151,6 @@ def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) if not is_wayland() and not is_macos: # no window icons on wayland set_x11_window_icon() load_shader_programs.use_selection_fg = opts.selection_foreground is not None - if opts.shell_integration != 'disabled': - from .shell_integration import setup_shell_integration - setup_shell_integration() with cached_values_for(run_app.cached_values_name) as cached_values: with startup_notification_handler(extra_callback=run_app.first_window_callback) as pre_show_callback: window_id = create_os_window( @@ -274,7 +272,9 @@ def setup_environment(opts: Options, cli_opts: CLIOptions) -> None: if cli_opts.listen_on and opts.allow_remote_control != 'n': cli_opts.listen_on = expand_listen_on(cli_opts.listen_on, from_config_file) os.environ['KITTY_LISTEN_ON'] = cli_opts.listen_on - set_default_env(opts.env.copy()) + env = opts.env.copy() + setup_shell_integration(opts, env) + set_default_env(env) def set_locale() -> None: diff --git a/kitty/shell_integration.py b/kitty/shell_integration.py index 5f271af24..387889f34 100644 --- a/kitty/shell_integration.py +++ b/kitty/shell_integration.py @@ -5,12 +5,11 @@ import os import time from contextlib import suppress -from typing import Optional, Union +from typing import Optional, Union, Dict +from .options.types import Options from .config import atomic_save from .constants import shell_integration_dir -from .fast_data_types import get_options -from .types import run_once from .utils import log_error, resolved_shell posix_template = ''' @@ -50,14 +49,14 @@ def setup_integration(shell_name: str, rc_path: str, template: str = posix_templ atomic_write(rc_path, newrc) -def setup_zsh_integration() -> None: +def setup_zsh_integration(env: Dict[str, str]) -> None: base = os.environ.get('ZDOTDIR', os.path.expanduser('~')) rc = os.path.join(base, '.zshrc') if os.path.exists(rc): # dont prevent zsh-newuser-install from running setup_integration('zsh', rc) -def setup_bash_integration() -> None: +def setup_bash_integration(env: Dict[str, str]) -> None: setup_integration('bash', os.path.expanduser('~/.bashrc')) @@ -73,17 +72,16 @@ def atomic_symlink(destination: str, in_directory: str) -> None: raise -def setup_fish_integration() -> None: - base = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) - base = os.path.join(base, 'fish') - os.makedirs(os.path.join(base, 'completions'), exist_ok=True) - path = os.path.join(shell_integration_dir, 'kitty.fish') - 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']) +def setup_fish_integration(env: Dict[str, str]) -> None: + if 'XDG_DATA_DIRS' in env: + val = env.get('XDG_DATA_DIRS', '') + dirs = list(filter(None, val.split(os.pathsep))) + else: + val = os.environ.get('XDG_DATA_DIRS', '') + dirs = list(filter(None, val.split(os.pathsep))) + if shell_integration_dir not in dirs: + dirs.insert(0, shell_integration_dir) + env['XDG_DATA_DIRS'] = os.pathsep.join(dirs) SUPPORTED_SHELLS = { @@ -100,19 +98,19 @@ def get_supported_shell_name(path: str) -> Optional[str]: return None -@run_once -def setup_shell_integration() -> None: - opts = get_options() - q = opts.shell_integration.split() - if opts.shell_integration == 'disabled' or 'no-rc' in q: - return +def setup_shell_integration(opts: Options, env: Dict[str, str]) -> bool: + q = set(opts.shell_integration.split()) + if q & {'disabled', 'no-rc'}: + return False shell = get_supported_shell_name(resolved_shell(opts)[0]) if shell is None: - return + return False func = SUPPORTED_SHELLS[shell] try: - func() + func(env) except Exception: import traceback traceback.print_exc() log_error(f'Failed to setup shell integration for: {shell}') + return False + return True diff --git a/shell-integration/fish/vendor_completions.d/kitty.fish b/shell-integration/fish/vendor_completions.d/kitty.fish new file mode 100644 index 000000000..804160a9c --- /dev/null +++ b/shell-integration/fish/vendor_completions.d/kitty.fish @@ -0,0 +1,5 @@ +if functions -q _ksi_completions + complete -f -c kitty -a "(_ksi_completions)" +else + complete -f -c kitty -a "(commandline -cop | kitty +complete fish)" +end diff --git a/shell-integration/kitty.fish b/shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish similarity index 100% rename from shell-integration/kitty.fish rename to shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish