kitty-shell-integration.fish 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #!/bin/fish
  2. # To use fish's autoloading feature, kitty prepends the vendored integration script directory to XDG_DATA_DIRS.
  3. # The original paths needs to be restored here to not affect other programs.
  4. # In particular, if the original XDG_DATA_DIRS does not exist, it needs to be removed.
  5. if set -q KITTY_FISH_XDG_DATA_DIR
  6. if set -q XDG_DATA_DIRS
  7. set --global --export --path XDG_DATA_DIRS "$XDG_DATA_DIRS"
  8. if set --local index (contains --index "$KITTY_FISH_XDG_DATA_DIR" $XDG_DATA_DIRS)
  9. set --erase --global XDG_DATA_DIRS[$index]
  10. test -n "$XDG_DATA_DIRS" || set --erase --global XDG_DATA_DIRS
  11. end
  12. if set -q XDG_DATA_DIRS
  13. set --global --export --unpath XDG_DATA_DIRS "$XDG_DATA_DIRS"
  14. end
  15. end
  16. set --erase KITTY_FISH_XDG_DATA_DIR
  17. end
  18. status is-interactive || exit 0
  19. not functions -q __ksi_schedule || exit 0
  20. # Check fish version 3.3.0+ efficiently and fallback to check the minimum working version 3.2.0, exit on outdated versions.
  21. # "Warning: Update fish to version 3.3.0+ to enable kitty shell integration.\n"
  22. set -q fish_killring || set -q status_generation || string match -qnv "3.1.*" "$version"
  23. or echo -en \eP@kitty-print\|V2FybmluZzogVXBkYXRlIGZpc2ggdG8gdmVyc2lvbiAzLjMuMCsgdG8gZW5hYmxlIGtpdHR5IHNoZWxsIGludGVncmF0aW9uLgo=\e\\ && exit 0 || exit 0
  24. function __ksi_schedule --on-event fish_prompt -d "Setup kitty integration after other scripts have run, we hope"
  25. functions --erase __ksi_schedule
  26. test -n "$KITTY_SHELL_INTEGRATION" || return 0
  27. set --local _ksi (string split " " -- "$KITTY_SHELL_INTEGRATION")
  28. set --erase KITTY_SHELL_INTEGRATION
  29. # Enable cursor shape changes for default mode and vi mode
  30. if not contains "no-cursor" $_ksi
  31. function __ksi_set_cursor --on-variable fish_key_bindings -d "Set the cursor shape for different modes when switching key bindings"
  32. if test "$fish_key_bindings" = fish_default_key_bindings
  33. function __ksi_bar_cursor --on-event fish_prompt -d "Set cursor shape to blinking bar on prompt"
  34. echo -en "\e[5 q"
  35. end
  36. # Change the cursor shape on first run
  37. set -q argv[1]
  38. and __ksi_bar_cursor
  39. else
  40. functions --erase __ksi_bar_cursor
  41. contains "$fish_key_bindings" fish_vi_key_bindings fish_hybrid_key_bindings
  42. and __ksi_set_vi_cursor
  43. end
  44. end
  45. function __ksi_set_vi_cursor -d "Set the vi mode cursor shapes"
  46. # Set the vi mode cursor shapes only when none of them are configured
  47. set --local vi_modes fish_cursor_{default,insert,replace_one,visual}
  48. set -q $vi_modes
  49. test "$status" -eq 4 || return
  50. set --local vi_cursor_shapes block line underscore block
  51. for i in 1 2 3 4
  52. set --global $vi_modes[$i] $vi_cursor_shapes[$i] blink
  53. end
  54. # Change the cursor shape for current mode
  55. test "$fish_bind_mode" = "insert" && echo -en "\e[5 q" || echo -en "\e[1 q"
  56. end
  57. function __ksi_default_cursor --on-event fish_preexec -d "Set cursor shape to blinking default shape before executing command"
  58. echo -en "\e[0 q"
  59. end
  60. __ksi_set_cursor init
  61. end
  62. # Enable prompt marking with OSC 133
  63. if not contains "no-prompt-mark" $_ksi and not set -q __ksi_prompt_state
  64. set --local suffix ''
  65. if bind --function-names | string match -q forward-char-passive
  66. set suffix '-passive'
  67. end
  68. # fish 3.8 emits prompt markers, so we don't need to. It also is the
  69. # first version to define forward-char-passive so use that as a test to detect it
  70. if test "$suffix" = ""
  71. function __ksi_mark_prompt_start --on-event fish_prompt --on-event fish_cancel --on-event fish_posterror
  72. test "$__ksi_prompt_state" != prompt-start
  73. and echo -en "\e]133;D\a"
  74. set --global __ksi_prompt_state prompt-start
  75. echo -en "\e]133;A;special_key=1\a"
  76. end
  77. __ksi_mark_prompt_start
  78. function __ksi_mark_output_start --on-event fish_preexec
  79. set --global __ksi_prompt_state pre-exec
  80. printf '\e]133;C;cmdline_url=%s\a' (string escape --style=url -- "$argv")
  81. end
  82. function __ksi_mark_output_end --on-event fish_postexec
  83. set --global __ksi_prompt_state post-exec
  84. echo -en "\e]133;D;$status\a"
  85. end
  86. # With prompt marking, kitty clears the current prompt on resize,
  87. # so we need fish to redraw it.
  88. set --global fish_handle_reflow 1
  89. end
  90. # Binding for special key to move cursor on mouse click without triggering any
  91. # autocompletion or other effects
  92. for mode in (bind --list-modes | string match -v paste) # bind in all modes except paste
  93. bind --preset -M "$mode" \e\[1u "forward-char$suffix"
  94. bind --preset -M "$mode" \e\[1\;1u "backward-char$suffix"
  95. end
  96. end
  97. # Enable CWD reporting
  98. if not contains "no-cwd" $_ksi
  99. # This function name is from fish and will override the builtin one, which is enabled by default for kitty in fish 3.5.0+.
  100. # We provide this to ensure that fish 3.2.0 and above will work.
  101. # https://github.com/fish-shell/fish-shell/blob/3.2.0/share/functions/__fish_config_interactive.fish#L275
  102. # An executed program could change cwd and report the changed cwd, so also report cwd at each new prompt
  103. function __update_cwd_osc --on-variable PWD --on-event fish_prompt -d "Report PWD changes to kitty"
  104. status is-command-substitution
  105. or echo -en "\e]7;kitty-shell-cwd://$hostname$PWD\a"
  106. end
  107. __update_cwd_osc
  108. end
  109. # Note that neither alias nor function is recursive in fish so if the user defines an alias/function
  110. # for sudo it will be clobbered by us, so only install this if sudo is not already function
  111. if not contains "no-sudo" $_ksi
  112. and test -n "$TERMINFO" -a "file" = (type -t sudo 2> /dev/null || echo "x")
  113. and not test -r "/usr/share/terminfo/x/xterm-kitty" -o -r "/usr/share/terminfo/78/xterm-kitty"
  114. # Ensure terminfo is available in sudo
  115. function sudo
  116. set --local is_sudoedit "n"
  117. for arg in $argv
  118. if string match -q -- "-e" "$arg" or string match -q -- "--edit" "$arg"
  119. set is_sudoedit "y"
  120. break
  121. end
  122. if not string match -r -q -- "^-" "$arg" and not string match -r -q -- "=" "$arg"
  123. break # reached the command
  124. end
  125. end
  126. if string match -q -- "$is_sudoedit" "y"
  127. command sudo $argv
  128. else
  129. command sudo TERMINFO="$TERMINFO" $argv
  130. end
  131. end
  132. end
  133. # Handle clone launches
  134. if test -n "$KITTY_IS_CLONE_LAUNCH"
  135. set --local orig_conda_env "$CONDA_DEFAULT_ENV"
  136. eval "$KITTY_IS_CLONE_LAUNCH"
  137. set --local venv "$VIRTUAL_ENV/bin/activate.fish"
  138. set --global _ksi_sourced
  139. function _ksi_s_is_ok
  140. test -z "$_ksi_sourced"
  141. and string match -q -- "*,$argv[1],*" "$KITTY_CLONE_SOURCE_STRATEGIES"
  142. and return 0
  143. return 1
  144. end
  145. if _ksi_s_is_ok "venv"
  146. and test -n "$VIRTUAL_ENV" -a -r "$venv"
  147. set _ksi_sourced "y"
  148. set --erase VIRTUAL_ENV _OLD_FISH_PROMPT_OVERRIDE # activate.fish stupidly exports _OLD_FISH_PROMPT_OVERRIDE
  149. source "$venv"
  150. end
  151. if _ksi_s_is_ok "conda"
  152. and test -n "$CONDA_DEFAULT_ENV" -a "$CONDA_DEFAULT_ENV" != "$orig_conda_env"
  153. and functions -q conda
  154. set _ksi_sourced "y"
  155. conda activate "$CONDA_DEFAULT_ENV"
  156. end
  157. if _ksi_s_is_ok "env_var"
  158. and test -n "$KITTY_CLONE_SOURCE_CODE"
  159. set _ksi_sourced "y"
  160. eval "$KITTY_CLONE_SOURCE_CODE"
  161. end
  162. if _ksi_s_is_ok "path"
  163. and test -r "$KITTY_CLONE_SOURCE_PATH"
  164. set _ksi_sourced "y"
  165. source "$KITTY_CLONE_SOURCE_PATH"
  166. end
  167. set --erase KITTY_IS_CLONE_LAUNCH KITTY_CLONE_SOURCE_STRATEGIES _ksi_sourced
  168. functions --erase _ksi_s_is_ok
  169. # Ensure PATH has no duplicate entries
  170. set --local --path new_path
  171. for p in $PATH
  172. contains -- "$p" $new_path
  173. or set --append new_path "$p"
  174. end
  175. test (count $new_path) -eq (count $PATH)
  176. or set --global --export --path PATH $new_path
  177. end
  178. end
  179. function edit-in-kitty --wraps "kitten edit-in-kitty" -d "Edit the specified file in a kitty overlay window with your locally installed editor"
  180. kitten edit-in-kitty $argv
  181. end
  182. function __ksi_transmit_data -d "Transmit data to kitty using chunked DCS escapes"
  183. set --local data (string replace --regex --all -- "\s" "" "$argv[1]")
  184. set --local data_len (string length -- "$data")
  185. set --local pos 1
  186. set --local chunk_num 0
  187. while test "$pos" -le $data_len
  188. printf \eP@kitty-%s\|%s:%s\e\\ "$argv[2]" "$chunk_num" (string sub --start $pos --length 2048 -- "$data")
  189. set pos (math $pos + 2048)
  190. set chunk_num (math $chunk_num + 1)
  191. end
  192. printf \eP@kitty-%s\|\e\\ "$argv[2]"
  193. end
  194. function clone-in-kitty -d "Clone the current fish session into a new kitty window"
  195. set --local data
  196. for a in $argv
  197. if contains -- "$a" -h --help
  198. echo "Clone the current fish session into a new kitty window."
  199. echo
  200. echo "For usage instructions see: https://sw.kovidgoyal.net/kitty/shell-integration/#clone-shell"
  201. return
  202. end
  203. set --local ea (printf "%s" "$a" | base64)
  204. set --append data "a=$ea"
  205. end
  206. set --local envs
  207. for e in (set --export --names)
  208. set --append envs "$e=$$e"
  209. end
  210. set --local b64_envs (string join0 -- $envs | base64)
  211. set --local b64_cwd (printf "%s" "$PWD" | base64)
  212. set --prepend data "shell=fish" "pid=$fish_pid" "cwd=$b64_cwd" "env=$b64_envs"
  213. __ksi_transmit_data (string join "," -- $data) "clone"
  214. end