How to always have the same current directory in VIm and in Terminal?

爱⌒轻易说出口 提交于 2019-12-05 10:57:51

What kind of command do you issue in your shell after you suspend Vim? Isn't Vim's :!command enough?

With set autochdir, Vim's current directory follows you as you jump from file to file. With this setting, a simple :!ctags -R . will always create a tags file in the directory of the current file.

Another useful setting is set tags=./tags,tags;$HOME which tells Vim to look for a tags file in the directory of the current file, then in the "current directory" and up and up until it reaches your ~/. You might modify the endpoint to suit your needs. This allows you to use a tags at the root of your project while editing any file belonging to the project.

So, basically, you can go a long way without leaving Vim at all.

If you really need to go back to the shell to issue your commands, :shell (or :sh) launchs a new shell with Vim's current directory. When you are done, you only have to $ exit to go back to Vim:

$ pwd
/home/romainl
$ vim
:cd Projects
:sh
$ pwd
/home/romainl/Projects
$ exit

In bash or zsh and on Unix you can do this: current working directory of the process is represented in /proc/{PID}/cwd as a symlink to a real directory. Speaking about zsh the following code will do the job:

function precmd()
{
    emulate -L zsh
    (( $#jobstates == 1 )) || return
    local -i PID=${${${(s.:.)${(v)jobstates[1]}}[3]}%\=*}
    cd $(readlink /proc/$PID/cwd)
}

. Note: with this code you won’t be able to pernamently switch directories in terminal anymore, only in vim or for duration of one command (using cd other-dir && some command).

Note 2: I have no idea how to express this in bash. The straightforward way is to get PIDs of all children of the shell (using ps --ppid $$ -o CMD), filter out the ps process (it will be shown as a child as well), check that there is only one other child and use its PID like in the last line above. But I am pretty sure there is a better way using some shell builtins like I did with zsh’s $jobstates associative array. I also don’t remember what is the analogue of precmd in bash.


Another idea would be making vim save its current directory into some file when you do <C-z> and make shell read this in precmd:

" In .vimrc:
function s:CtrlZ()
    call writefile([fnamemodify('.', ':p')], $CWDFILE, 'b')
    return "\<C-z>"
endfunction
nnoremap <expr> <C-z> <SID>CtrlZ()

# In .zshrc
function vim()
{
    local -x CWDFILE=~/.workdirs/$$
    test -d $CWDFILE:h || mkdir $CWDFILE:h
    vim $@
}
function precmd()
{
    local CWDFILE=~/.workdirs/$$
    test -e $CWDFILE && cd "$(cat $CWDFILE)"
}

. It should be easier to port above code to bash.

you can open a new terminal like this

:!xterm -e bash -c "cd %:p:h;bash" &

actually I write this in my .vimrc

nmap <F3> :!xterm -e bash -c "cd %:p:h;bash" &<CR> | :redraw!

For bash users coming by:

Vim: Save pwd at <c-z> (with map and getpwd()).
Bash: Before prompt command, goto directory indicated by vim with PROMPT_COMMAND.

.bashrc

PROMPT_COMMAND='read -r line 2>/dev/null </tmp/cd_vim'\
'&& > /tmp/cd_vim && cd ${line##\r};'$PROMPT_COMMAND

vimrc

function! s:CtrlZ() call writefile([getcwd(),''], '/tmp/cd_vim', 'b')
    return "\<C-z>"
endfunction
nnoremap <expr> <C-z> <SID>CtrlZ()

This is ZyX answer edited for bash https://stackoverflow.com/a/12241861/2544873

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!