From 75942fb47e7b2c9b9a77bbac6b37384b5f23d668 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 28 May 2022 11:12:11 +0530 Subject: [PATCH] Implement edit-in-kitty for fish --- .../kitty-shell-integration.fish | 90 ++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish b/shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish index 79cfebd8a..15f4ca04b 100644 --- a/shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish +++ b/shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish @@ -155,7 +155,7 @@ function __ksi_schedule --on-event fish_prompt -d "Setup kitty integration after end end -function _ksi_transmit_data -d "Transmit data to kitty using chunked DCS escapes" +function __ksi_transmit_data -d "Transmit data to kitty using chunked DCS escapes" set --local data_len (string length -- "$argv[1]") set --local pos 1 set --local chunk_num 0 @@ -188,5 +188,91 @@ function clone-in-kitty -d "Clone the current fish session into a new kitty wind set --local b64_cwd (printf "%s" "$PWD" | base64) set --prepend data "shell=fish" "pid=$fish_pid" "cwd=$b64_cwd" "env=$b64_envs" set data (string join "," -- $data | tr -d "\t\n\r ") - _ksi_transmit_data "$data" "clone" + __ksi_transmit_data "$data" "clone" +end + +function edit-in-kitty -d "Edit the specified file in a new kitty overlay using your preferred editor, even over SSH" + set --local data + set --local ed_filename "" + set --local usage "Usage: edit-in-kitty [OPTIONS] FILE" + for a in $argv + if contains -- "$a" -h --help + echo "$usage" + echo + echo "Edit the specified file in a kitty overlay window. Works over SSH as well." + echo + echo "For usage instructions see: https://sw.kovidgoyal.net/kitty/shell-integration/#edit-file" + return + end + set --local ea (printf "%s" "$a" | base64) + set --append data "a=$ea" + set ed_filename "$a" + end + if test -z "$ed_filename" + echo "$usage" > /dev/stderr + return 1 + end + if test ! \( -r "$ed_filename" -a -w "$ed_filename" \) + echo "$ed_filename is not readable and writable" > /dev/stderr + return 1 + end + if test ! -f "$ed_filename" + builtin echo "$ed_filename is not a file" > /dev/stderr + return 1 + end + set --local stat_result (command stat -L --format '%d:%i:%s' "$ed_filename" 2> /dev/null) + if test "$status" -ne "0" + set stat_result (command stat -L -f '%d:%i:%z' "$ed_filename" 2> /dev/null) + end + if test -z "$stat_result" + echo "Failed to stat the file: $ed_filename" > /dev/stderr + return 1 + end + set --append data "file_inode=$stat_result" + set --local file_size (string match -rg '\d+:\d+:(\d+)' "$stat_result") + test "$file_size" -gt (math "8 * 1024 * 1024") && begin; echo "File is too large for performant editing"; return 1; end; + set --local file_data (command base64 < "$ed_filename") + set --append data "file_data=$file_data" + __ksi_transmit_data (string join "," -- $data | tr -d "\t\n\r ") "edit" + echo "Waiting for editing to be completed..." + set --global __ksi_waiting_for_edit "y" + set --erase data + function __ksi_react_to_interrupt -s SIGINT + if test "$__ksi_waiting_for_edit" = "y" + set --erase __ksi_waiting_for_edit + __ksi_transmit_data "abort_signaled=interrupt" "edit" + end + end + while true + set --local started "n" + while true + command stty "-echo"; set --local line (command head -n1 < /dev/tty); + test -z "$line" && break + if test "$started" = "y" + test "$line" = "UPDATE" && break; + if test "$line" = "DONE" + set started "done"; break; + end + printf "%s\n" "$line" > /dev/stderr; + return 1; + else + test "$line" = "KITTY_DATA_START" && set started "y" + end + end + test "$started" = "n" && continue; + set --local data "" + while true + command stty "-echo"; set --local line (command head -n1 < /dev/tty); + test -z "$line" && break + test "$line" = "KITTY_DATA_END" && break; + set data "$data$line" + end + if test -n "$data" -a "$started" != "done" + echo "Updating $ed_filename..." + printf "%s" "$data" | command base64 -d > "$ed_filename" + end + test "$started" = "done" && break; + end + set --erase __ksi_waiting_for_edit + functions --erase __ksi_react_to_interrupt end