Add function to get path to integration script for the current shell

Makes setting up manual shell integration much easier. Also clean up
integration docs.
This commit is contained in:
Kovid Goyal
2021-11-08 11:11:16 +05:30
parent fadc1b539b
commit 8218df82f2
3 changed files with 48 additions and 67 deletions

View File

@@ -69,15 +69,24 @@ How it works
-----------------
At startup kitty detects if the shell you have configured (either system wide
or in kitty.conf) is a supported shell. If so, kitty adds a couple of lines to
the bottom of the shell's rc files (in an atomic manner) to load the shell
integration code.
or in kitty.conf) is a supported shell. If so, kitty injects some shell specific
code into the shell, to enable shell integration. How it does so varies for
different shells.
For fish, to make it automatically load the configuration file provided by
kitty, the integration script directory path is prepended to the
:code:`XDG_DATA_DIRS` environment variable. This is only applied to the fish
process and will be cleaned up by the integration script after startup. No files
are added or modified.
.. tab:: bash/zsh
For these shells, kitty adds a couple of lines to
the bottom of the shell's rc files (in an atomic manner) to load the shell
integration code.
.. tab:: fish
For fish, to make it automatically load the integration code provided by
kitty, the integration script directory path is prepended to the
:code:`XDG_DATA_DIRS` environment variable. This is only applied to the fish
process and will be cleaned up by the integration script after startup. No files
are added or modified.
Then, when launching the shell, kitty sets the environment variable
:envvar:`KITTY_SHELL_INTEGRATION` to the value of the :opt:`shell_integration`
@@ -131,22 +140,21 @@ want to setup shell integration for a remote system over SSH, in
Then in your shell's rc file, add the lines:
.. code-block:: sh
.. tab:: bash/zsh
export KITTY_SHELL_INTEGRATION="enabled"
source /path/to/integration/script
.. code-block:: sh
For fish, add the lines:
export KITTY_SHELL_INTEGRATION="enabled"
source $(kitty +runpy "from kitty.shell_integration import script_path; print(script_path())")
.. code-block:: fish
.. tab:: fish
set --global KITTY_SHELL_INTEGRATION enabled
source /path/to/integration/script
.. code-block:: fish
set --global KITTY_SHELL_INTEGRATION enabled
source (kitty +runpy "from kitty.shell_integration import script_path; print(script_path('fish'))")
set --prepend fish_complete_path (kitty +runpy "from kitty.shell_integration import fish_completions_dir; print(fish_completions_dir)")
Or create symbolic links for each of the two files in the fish integration
script directory and place them in :code:`~/.config/fish/completions/` and
:code:`~/.config/fish/conf.d/` respectively. You still need to configure
:envvar:`KITTY_SHELL_INTEGRATION` and set it to :code:`enabled` explicitly.
You can get the path to the directory containing the various shell integration
scripts by looking at the directory displayed by:
@@ -160,53 +168,6 @@ The value of :envvar:`KITTY_SHELL_INTEGRATION` is the same as that for
completely, in which case simply do not set the
:envvar:`KITTY_SHELL_INTEGRATION` variable at all.
If you use the fish shell automatic integration, the script directory will be
removed from the :code:`XDG_DATA_DIRS` environment variable after startup. This
is to ensure that when this environment variable is empty, the software that
relies on it will correctly use the system default fallback path, such as
:code:`/usr/local/share:/usr/share` defined in the specification. Otherwise,
software may not work properly, for example, :code:`xdg-open` will not be able
to open your files.
If you want to run fish in fish and enable automatic shell integration (e.g.
run :code:`fish --private`), you need to configure it manually and make sure
that :code:`XDG_DATA_DIRS` contains all the system data directory paths.
In your :file:`kitty.conf` set:
.. code-block:: conf
shell_integration enabled
For systems that already have the correct :code:`XDG_DATA_DIRS`, add the
following lines:
.. code-block:: fish
set --global KITTY_SHELL_INTEGRATION enabled
if set -q KITTY_FISH_XDG_DATA_DIR
set --erase KITTY_FISH_XDG_DATA_DIR
end
For cases where :code:`XDG_DATA_DIRS` is not set or empty (e.g. not set by
default on macOS), you can set it in :file:`kitty.conf` via :opt:`env`.
Otherwise, you need to add all the data directory paths defined by your system
and package manager in your fish configuration. For example:
.. code-block:: fish
set --global KITTY_SHELL_INTEGRATION enabled
if set -q KITTY_FISH_XDG_DATA_DIR
set --global --export XDG_DATA_DIRS $KITTY_FISH_XDG_DATA_DIR:/opt/path/to/data/dirs:/usr/local/share:/usr/share
set --erase KITTY_FISH_XDG_DATA_DIR
end
The benefit of using fish shell automatic integration is that the integration
script included with the current version of kitty will always be loaded
correctly. The installation path for kitty can be anywhere, not a hard-coded
location in your fish configuration. Your fish configuration files (a.k.a.
dotfiles) can also be shared between different system environments.
Notes for shell developers
-----------------------------

View File

@@ -23,7 +23,7 @@ except ImportError:
if is_macos:
from kitty.fast_data_types import (
cmdline_of_process, cwd_of_process as _cwd,
cmdline_of_process as cmdline_, cwd_of_process as _cwd,
environ_of_process as _environ_of_process,
process_group_map as _process_group_map
)
@@ -37,6 +37,8 @@ if is_macos:
ans[pgid].append(pid)
return ans
def cmdline_of_process(pid: int) -> List[str]:
return cmdline_(pid)
else:
def cmdline_of_process(pid: int) -> List[str]:

View File

@@ -16,6 +16,7 @@ posix_template = '''
if test -e {path}; then source {path}; fi
# END_KITTY_SHELL_INTEGRATION
'''
fish_completions_dir = os.path.join(shell_integration_dir, 'fish', 'vendor_completions.d')
def atomic_write(path: str, data: Union[str, bytes]) -> None:
@@ -86,6 +87,7 @@ ENV_MODIFIERS = {
def get_supported_shell_name(path: str) -> Optional[str]:
name = os.path.basename(path).split('.')[0].lower()
name = name.replace('-', '')
if name in SUPPORTED_SHELLS:
return name
return None
@@ -131,3 +133,19 @@ def modify_shell_environ(argv0: str, opts: Options, env: Dict[str, str]) -> None
traceback.print_exc()
log_error(f'Failed to setup shell integration for: {shell}')
return
def script_path(shell: str = '') -> str:
if not shell:
from .child import cmdline_of_process
cmd = cmdline_of_process(os.getppid())
if not cmd:
return ''
shell = get_supported_shell_name(cmd[0]) or ''
if not shell:
return ''
if shell == 'fish':
f = 'fish/vendor_conf.d/kitty-shell-integration.fish'
else:
f = f'kitty.{shell}'
return os.path.join(shell_integration_dir, f)