- Create a special function in your vimrc that's callable from terminal, its name must start with
Tapi_
.
" arglist : [ cwd ]
" change window local working directory
function! Tapi_lcd(bufnum, arglist)
let winid = bufwinid(a:bufnum)
let cwd = get(a:arglist, 0, '')
if winid == -1 || empty(cwd)
return
endif
call win_execute(winid, 'lcd ' . cwd)
endfunction
- create a function in your zshrc to call
Tapi_lcd
in terminal:
cdv()
{
printf '\033]51;["call", "Tapi_lcd", ["%s"]]\007' "$(pwd)"
}
The leading \033]51;
and the trailing \007
are special escape sequence recognized by vim.
check :h terminal-api for more detail.
You can now use cdv
in terminal to change window local directory now (personally I would stop here, it's good enough for me).
- hook
cd
and cdv
autoload -Uz add-zsh-hook
add-zsh-hook -Uz chpwd cdv
Now they are hooked
, cdv
is called every time you cd
.
There are some side effect you should know, as some subshell environment (such as $()
) is a duplicate of the current shell environment, the hook works in such subshell too. For example:
( cd / )
Above command will trigger cdv
, it change your working directory to /
, if you want to avoid that, you need to filter out subshell cd
:
cdv()
{
if [[ $ZSH_SUBSHELL -eq 0 ]] ; then
printf '\033]51;["call", "Tapi_lcd", ["%s"]]\007' "$(pwd)"
fi
}
I'm not a shell veteran, the hook make me nervous, I wouldn't use it,.
update for nvim
" in init.vim/vimrc
fu Tapi_lcd(buf, cwd) abort
if has('nvim')
exe 'lcd '..a:cwd
return ''
endif
let winid = bufwinid(a:buf)
if winid == -1 || empty(a:cwd)
return
endif
call win_execute(winid, 'lcd '..a:cwd)
endfu
# in zshrc
autoload -Uz add-zsh-hook
if [[ -n "$VIM_TERMINAL" ]]; then
add-zsh-hook -Uz chpwd cdv
cdv() {
printf -- '\033]51;["call", "Tapi_lcd", "%q"]\007' "$(pwd)"
}
elif [[ -n "$NVIM_LISTEN_ADDRESS" ]]; then
add-zsh-hook -Uz chpwd cdv
cdv() {
nvr --servername "$VIM_SERVERNAME" --remote-expr "$(printf -- 'Tapi_lcd(0, "%q")' "$(pwd)")"
}
fi
It requires the nvr
command; you can get it from here, or by running this shell command:
python3 -m pip install --user --upgrade neovim-remote
update for bash
There is no hook
in bash, but we can use an alias and a function to hook cd and cdv. After step 2, put this in your bashrc
:
cdv()
{
printf '\033]51;["call", "Tapi_lcd", ["%s"]]\007' "$(pwd)"
}
cd_and_cdv()
{
'cd' "$@" && cdv
}
hookvim()
{
alias cd=cd_and_cdv
}
execute hookvim
after entering terminal
, done. This solution works for zsh
too.
update: set up hook automatically
:h terminal-unix add a bunch of environment variable to terminal inside vim, we can use it to setup hook.
Put this to you zshrc/bashrc :
if [[ ! -z "$VIM_TERMINAL" ]]; then
hookvim
fi