diff --git a/kitty/shell_integration.py b/kitty/shell_integration.py index dc96f499d..27d86629f 100644 --- a/kitty/shell_integration.py +++ b/kitty/shell_integration.py @@ -13,7 +13,6 @@ from .fast_data_types import get_options from .types import run_once from .utils import log_error, resolved_shell -SUPPORTED_SHELLS = ('zsh',) posix_template = ''' # BEGIN_KITTY_SHELL_INTEGRATION [[ -a {path} ]] && source {path} @@ -61,6 +60,13 @@ def setup_zsh_integration() -> None: setup_integration('zsh', rc) +def setup_bash_integration() -> None: + setup_integration('bash', os.path.expanduser('~/.bashrc')) + + +SUPPORTED_SHELLS = {'zsh': setup_zsh_integration, 'bash': setup_bash_integration} + + def get_supported_shell_name(path: str) -> Optional[str]: name = os.path.basename(path).split('.')[0].lower() if name in SUPPORTED_SHELLS: @@ -76,7 +82,7 @@ def setup_shell_integration() -> None: shell = get_supported_shell_name(resolved_shell(opts)[0]) if shell is None: return - func = {'zsh': setup_zsh_integration}[shell] + func = SUPPORTED_SHELLS[shell] try: func() except Exception: diff --git a/shell-integration/kitty.bash b/shell-integration/kitty.bash new file mode 100644 index 000000000..ab3544b49 --- /dev/null +++ b/shell-integration/kitty.bash @@ -0,0 +1,59 @@ +_ksi_main() { + if [[ $- != *i* ]] ; then return; fi # check in interactive mode + if [[ -z "$KITTY_SHELL_INTEGRATION" ]]; then return; fi + declare -A _ksi_prompt=( [cursor]='y' [title]='y' [mark]='y' [complete]='y' ) + set -f + for i in ${KITTY_SHELL_INTEGRATION}; do + set +f + if [[ "$i" == "no-cursor" ]]; then _ksi_prompt[cursor]='n'; fi + if [[ "$i" == "no-title" ]]; then _ksi_prompt[title]='n'; fi + if [[ "$i" == "no-prompt-mark" ]]; then _ksi_prompt[mark]='n'; fi + if [[ "$i" == "no-complete" ]]; then _ksi_prompt[complete]='n'; fi + done + set +f + + unset KITTY_SHELL_INTEGRATION + + _ksi_debug_print() { + # print a line to STDOUT of parent kitty process + local b=$(printf "%s\n" "$1" | base64 | tr -d \\n) + printf "\eP@kitty-print|%s\e\\" "$b" + # " + } + + if [[ "${_ksi_prompt[cursor]}" == "y" ]]; then + PS1="\[\e[5 q\]$PS1" # blinking bar cursor + PS0="\[\e[1 q\]$PS0" # blinking block cursor + fi + + if [[ "${_ksi_prompt[title]}" == "y" ]]; then + # see https://www.gnu.org/software/bash/manual/html_node/Controlling-the-Prompt.html#Controlling-the-Prompt + PS1="\[\e]2;\w\a\]$PS1" + if [[ "$HISTCONTROL" == *"ignoreboth"* ]] || [[ "$HISTCONTROL" == *"ignorespace"* ]]; then + _ksi_debug_print "ignoreboth or ignorespace present in bash HISTCONTROL setting, showing running command in window title will not be robust" + fi + local orig_ps0="$PS0" + PS0='$(printf "\e]2;%s\a" "$(HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//")")' + PS0+="$orig_ps0" + fi + + if [[ "${_ksi_prompt[mark]}" == "y" ]]; then + PS1="\[\e]133;A\a\]$PS1" + PS0="\[\e]133;C\a\]$PS0" + fi + + if [[ "${_ksi_prompt[complete]}" == "y" ]]; then + _ksi_completions() { + local src + local limit + # Send all words up to the word the cursor is currently on + let limit=1+$COMP_CWORD + src=$(printf "%s\n" "${COMP_WORDS[@]: 0:$limit}" | kitty +complete bash) + if [[ $? == 0 ]]; then + eval ${src} + fi + } + complete -o nospace -F _ksi_completions kitty + fi +} +_ksi_main