From 46b9aca16e1afcefc0519da4a25bf483ec90a46d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 12 Jul 2021 13:09:25 +0530 Subject: [PATCH] Start work on shell integration --- kitty/parser.c | 4 ++ kitty/screen.c | 5 ++ kitty/screen.h | 1 + shell-integration/kitty.zsh | 125 ++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 shell-integration/kitty.zsh diff --git a/kitty/parser.c b/kitty/parser.c index f14d703e3..b1258a13d 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -441,6 +441,10 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { DISPATCH_OSC_WITH_CODE(clipboard_control); if (code == -52) continue_osc_52(screen); END_DISPATCH + case 133: + START_DISPATCH + DISPATCH_OSC(shell_prompt_marking); + END_DISPATCH case 30001: REPORT_COMMAND(screen_push_dynamic_colors); screen_push_colors(screen, 0); diff --git a/kitty/screen.c b/kitty/screen.c index ff014d1b8..17e29d92a 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1710,6 +1710,11 @@ clipboard_control(Screen *self, int code, PyObject *data) { CALLBACK("clipboard_control", "OO", data, code == -52 ? Py_True: Py_False); } +void +shell_prompt_marking(Screen *self, PyObject *data) { + printf("prompt_marking: x=%d y=%d ", self->cursor->x, self->cursor->y); PyObject_Print(data, stdout, 0); printf("\n"); +} + void set_color_table_color(Screen *self, unsigned int code, PyObject *color) { if (color == NULL) { CALLBACK("set_color_table_color", "Is", code, ""); } diff --git a/kitty/screen.h b/kitty/screen.h index f39130a88..74e810539 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -198,6 +198,7 @@ void desktop_notify(Screen *self, unsigned int, PyObject*); void set_icon(Screen *self, PyObject*); void set_dynamic_color(Screen *self, unsigned int code, PyObject*); void clipboard_control(Screen *self, int code, PyObject*); +void shell_prompt_marking(Screen *self, PyObject*); void set_color_table_color(Screen *self, unsigned int code, PyObject*); void process_cwd_notification(Screen *self, unsigned int code, PyObject*); uint32_t* translation_table(uint32_t which); diff --git a/shell-integration/kitty.zsh b/shell-integration/kitty.zsh new file mode 100644 index 000000000..9e9bfd4f6 --- /dev/null +++ b/shell-integration/kitty.zsh @@ -0,0 +1,125 @@ +local args +typeset -a args +args=($@) +() { + if [[ ! -o interactive ]]; then return; fi + + typeset -g kitty_prompt_state="first-run" + typeset -g kitty_prompt_cursor="y" + typeset -g kitty_prompt_title="y" + + (( ${args[(I)no-cursor]} )) && kitty_prompt_cursor="n" + (( ${args[(I)no-title]} )) && kitty_prompt_title="n" + + function debug() { + # print a line to STDOUT of parent kitty process + local b=$(printf "%s\n" "$1" | base64) + printf "\eP@kitty-print|%s\e\\" "$b" + } + + function change-cursor-shape () { + # change cursor shape depending on mode + if [[ "$kitty_prompt_cursor" == "y" ]]; then + if [[ "$KEYMAP" == vicmd ]]; then + # the command mode for vi + printf "\e[2 q" # blinking block cursor + else + # the insert mode for vi + printf "\e[5 q" # blinking bar cursor + fi + fi + } + + function kitty_zle_keymap_select() { + change-cursor-shape + } + function kitty_zle_keymap_select_with_original() { zle kitty-zle-keymap-select-original; kitty_zle_keymap_select } + zle -A zle-keymap-select kitty-zle-keymap-select-original 2>/dev/null + if [[ $? == 0 ]]; then + zle -N zle-keymap-select kitty_zle_keymap_select_with_original + else + zle -N zle-keymap-select kitty_zle_keymap_select + fi + + function mark() { + # tell kitty to mark the current cursor position using OSC 133 + printf "\e]133;%s\e\\" "$1" + } + + function set_title_precmd () { + # Set kitty window title to the cwd + if [[ "$kitty_prompt_title" == "y" ]]; then + printf "\e]2;%s\007" "${PWD/$HOME/~}" + fi + } + function set_title_preexec() { + # Set kitty window title to the currently executing command + if [[ "$kitty_prompt_title" == "y" ]]; then + printf "\e]2;%s\a" "$1" + fi + } + + function kitty_precmd() { + local cmd_status=$? + if [[ "$kitty_prompt_state" == "first-run" ]]; then + # compdef is only defined if compinit has been called + if whence compdef > /dev/null; then + compdef _kitty kitty + fi + fi + set_title_precmd + if [[ "$kitty_prompt_state" == "preexec" ]]; then + mark "D;$cmd_status" + else + if [[ "$kitty_prompt_state" != "first-run" ]]; then mark "D"; fi + fi + kitty_prompt_state="precmd" + mark "A" + } + + function kitty_zle_line_init() { + mark "B" + change-cursor-shape; + kitty_prompt_state="line-init" + } + function kitty_zle_line_init_with_orginal() { zle kitty-zle-line-init-original; kitty_zle_line_init } + zle -A zle-line-init kitty-zle-line-init-original 2>/dev/null + if [[ $? == 0 ]]; then + zle -N zle-line-init kitty_zle_line_init_with_orginal + else + zle -N zle-line-init kitty_zle_line_init + fi + + function kitty_zle_line_finish() { + change-cursor-shape; + kitty_prompt_state="line-init" + } + function kitty_zle_line_finish_with_orginal() { zle kitty-zle-line-finish-original; kitty_zle_line_finish } + zle -A zle-line-finish kitty-zle-line-finish-original 2>/dev/null + if [[ $? == 0 ]]; then + zle -N zle-line-finish kitty_zle_line_finish_with_orginal + else + zle -N zle-line-finish kitty_zle_line_finish + fi + + function kitty_preexec() { + mark "C" + set_title_preexec "$1" + kitty_prompt_state="preexec" + } + + typeset -a -g precmd_functions + precmd_functions=($precmd_functions kitty_precmd) + typeset -a -g preexec_functions + preexec_functions=($preexec_functions kitty_preexec) + + # Completion for kitty + _kitty() { + local src + # Send all words up to the word the cursor is currently on + src=$(printf "%s\n" "${(@)words[1,$CURRENT]}" | kitty +complete zsh) + if [[ $? == 0 ]]; then + eval ${src} + fi + } +}