Numerous problems with zsh integration code
The current integration example code in /etc/emacs-vterm-zsh.sh contains several problems.
To start there is the related bug #574 where the code to add a chpwd hook is incorrect. To correct this, you would write something like this:
vterm_update_buffer_title (){
print -Pn "\e]2;${EMACS_VTERM_BUFFER_TITLE:-%m:%2~}\a"
}
add-zsh-hook -Uz chpwd vterm_update_buffer_title
The problem is that now you are printing information to stdout even from within shell scripts that use cd; that means you WILL be polluting output files with this.
A hook will also only set your buffer title after the first directory change; I like to see it immediately when vterm starts.
So a better solution would be to not use a hook at all and just add this to the prompt.
Another problem is that printing extra information in the prompt will cause any RPROMPT in the zsh to shift location. To prevent that, we have to put the escape codes in {%..%}.
My config now looks like this, which solves all those problems:
emacs_vterm_prompt () {
buffer_title_update=$(print -Pn "\e]2;%2~$\a")
pwd_update=$(print -Pn "\e]51;A$(whoami)@$(hostname):$(pwd)\e")
prompt_end=$(print "%{$buffer_title_update$pwd_update%}\\")
PROMPT="$PROMPT$prompt_end"
}
autoload -U add-zsh-hook
add-zsh-hook precmd emacs_vterm_prompt
Note that the prompt is now set in a precmd hook, which makes this code play nice with other code that changes the prompt like ohmyzsh themes.
By the way, if we move the double slashes \\ at the end of prompt_end inside the %}:
prompt_end=$(print "%{$buffer_title_update$pwd_update\\%}")
This crashes my emacs every single time.
See also this comment.
For me, this almost works. The only problem is because of the mentioned \\ at the end of prompt_end, tab-completion duplicates characters (because \\ has nonzero length, I think). Of course, moving it inside the %} crashes Emacs. Here's what worked for me:
vterm_printf() {
# update buffer title
print -Pn "\e]2;%2~\a"
if [ -n "$TMUX" ] && ([ "${TERM%%-*}" = "tmux" ] || [ "${TERM%%-*}" = "screen" ]); then
# Tell tmux to pass the escape sequences through
printf "\ePtmux;\e\e]%s\007\e\\" "$1"
elif [ "${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]%s\007\e\\" "$1"
else
printf "\e]%s\e\\" "$1"
fi
}
vterm_prompt_end() {
prompt_end=$(vterm_printf "51;A$USER@$HOST:$PWD")
PROMPT="$PROMPT%{$prompt_end%}"
}
autoload -U add-zsh-hook
add-zsh-hook precmd vterm_prompt_end