VIM: Change working directory only for the current buffer - vim

How can I change a current working directory for a specific buffer and change it to a previous value for other buffers?
More precisely what I want to do is to have auto-commands for specific file types which will change a current working directory when a buffer containing the file type is active. And change it back when working with other buffers.
I had something like that in my vimrc:
autocmd BufEnter *.py :lcd%:p:h
autocmd BufLeave *.py :lcd-
The idea here is that I wanted to switch to file's directory when working on python files and switch to a previous directory when working on something else, e.g. text, vimL etc. Obviously, it didn't work. I also try using BufWinLeave, but it didn't change anything.
Can you point out what's wrong here? Or maybe there's an easier solution for that?

I think you could accomplish something similar with the following:
augroup CDRooter
autocmd!
autocmd BufWinEnter * if &filetype == 'python' | lcd %:p:h | else | lcd! | endif
augroup END
Note: I am not sure :lcd - will work well. Instead I use :lcd! to simply revert the window to using the global current working directory.
The basic idea is whenever you enter a window sniff the filetype and execute :lcd accordingly.
For more help see:
:h 'filetype'
:h BufWinEnter
:h :lcd
:h :augroup
:h :autocmd
:h :if

Related

Autoload netrw when starting vim

I want netrw to autoload when I launch vim using the terminal. Completely new to linux/ubuntu. Is there any way of doing that?
Adding the following to your .vimrc (Vim's configuration file, located in the root of your home directory) will cause Vim to automatically load Netrw after starting up.
" Open Netrw after Vim starts up
augroup InitNetrw
autocmd!
autocmd VimEnter * :silent! Explore
augroup END
A problem with the preceding approach, as implemented, is that Netrw will also load when you use Vim with an argument to open a specific file. A workaround is to use the following modification, based on the suggested approach in Netrw's documentation (:help netrw-activate).
" Checks if there is a file open after Vim starts up,
" and if not, open the current working directory in Netrw.
augroup InitNetrw
autocmd!
autocmd VimEnter * if expand("%") == "" | edit . | endif
augroup END
The following pages have more details on autocommands and the .vimrc configuration file.
https://learnvimscriptthehardway.stevelosh.com/chapters/12.html
https://learnvimscriptthehardway.stevelosh.com/chapters/14.html
https://learnvimscriptthehardway.stevelosh.com/chapters/07.html
And the following code block in your vimrc:
set autochdir
let g:netrw_browse_split=4
augroup InitNetrw
autocmd!
autocmd VimEnter * if argc() == 0 | Lexplore! | endif
augroupend
Kind of does what #dannyadam suggested. But opens the netrw pane as a side bar on the right. If you want to be on the right use Lexplore without the bang(!).

Vim colorscheme not loading when using autocommand BufNewFile

When trying to automatically open the corresponding .cpp or .h file using autocommand I encounter no colorscheme on the corresponding file that is opened.
I'm not too familiar with vimscript but I believe Vim is opening the file thinking it is of file type ".txt" and therefore using a default colorscheme.
Two autocommand lines in ~/.vimrc:
au BufRead,BufNewFile *.cpp exe "bel vsplit" fnameescape(expand("%:r").".h")
au BufRead,BufNewFile *.h exe "vsplit" fnameescape(expand("%:r").".cpp")
Any help would be appreciated.
Your answer is a workaround (though you should use :setlocal instead of :set to avoid that the syntax leaks out to new buffers that are opened from that one), but it doesn't attack the root cause, which you'll find explained at :help autocmd-nested:
By default, autocommands do not nest. If you use ":e" or ":w" in an autocommand, Vim does not execute the BufRead and BufWrite autocommands for those commands. If you do want this, use the "nested" flag for those commands in which you want nesting.
Syntax highlighting (you say colorscheme in your title, but that's actually just the color and font attributes that are then used by syntax highlighting) is based on :autocmd events (same goes for filetype plugins, so any C++-related settings you also wouldn't find in the split file, assuming you have :filetype plugin on in your ~/.vimrc). Without the nested attribute, the split file will be opened, but none of the usual actions will be run on them. Though nesting in general can be problematic, this is one of those cases where it is needed.
au BufRead,BufNewFile *.cpp nested exe "bel vsplit" fnameescape(expand("%:r").".h")
au BufRead,BufNewFile *.h nested exe "vsplit" fnameescape(expand("%:r").".cpp")
Unfortunately, this introduces another problem: The one autocmd will trigger the other one, and vice versa (up to a limit). You need to guard the actions so that a split is only done if the file isn't open yet. (This also improves on the usability in a general way, when you open a file with the other already open.) :help bufwinnr() checks whether the target buffer is already visible in a window:
au BufRead,BufNewFile *.cpp nested if bufwinnr("^" . expand("%:r").".h$") == -1 | exe "bel vsplit" fnameescape(expand("%:r").".h") | endif
au BufRead,BufNewFile *.h nested if bufwinnr("^" . expand("%:r").".cpp$") == -1 | exe "vsplit" fnameescape(expand("%:r").".cpp") | endif
If anyone cares to look at this in the future the solution was that Vim was loading the second file as syntax=none. So adding | set syntax=cpp at the end of each auto command fixed it.

Vim plugin : Rainbow parentheses using tab

I'm using vim 7.3 and Rainbow Parentheses plugin. When opening multiple tabs with vim -p file1 file2 or with vim -S session.vim, or even with tabnew file or any other method, my parenthesis are colored in only one file.
I just put this into my .vimrc : au VimEnter * RainbowParenthesesToggle
as said here. I tried to use :RainbowParenthesesToggle on the other tabs once opened but it only toggles in the parenthesis-activated tab.
What should I do to make things work in all tabs ?
I made it work by adding the same instructions as here in my .vimrc, thanks to FDinoff. I replaced the last instruction to make it work using tab, as I intended first.
function! Config_Rainbow()
call rainbow_parentheses#load(0)
call rainbow_parentheses#load(1)
call rainbow_parentheses#load(2)
endfunction
function! Load_Rainbow()
call rainbow_parentheses#activate()
endfunction
augroup TastetheRainbow
autocmd!
autocmd Syntax * call Config_Rainbow()
autocmd VimEnter,BufRead,BufWinEnter,BufNewFile * call Load_Rainbow()
augroup END
The VimEnter flag on the autocommand tells vim to perform the command specified (in this case RainbowParenthesesToggle only when starting the editor, which is in your case when you open the first file.
If you want to extend the functionality to everytime you load a buffer you should do something like:
autocmd BufRead,BufNewFile * RainbowParenthesesToggle

Vim: Saving on FocusLost and executing auto command

I've setup my vim editor (I use MacVim) to save files automatically when the focus is lost:
autocmd FocusLost * silent! wall
I also automatically strip trailing whitespace from python files using this auto command:
autocmd BufWritePre *.py :%s/\s\+$//e
This auto command works perfectly when I save the file manually (either by typing :w or by pressing ⌘s) but it is not executed (i.e. the whitespace is not stripped) when I switch to another application and the buffer is automatically written.
How can I modify these auto commands to make them work together?
You need to change your FocusLost autocommand to:
autocmd FocusLost * nested silent! wall
See :h autocmd-nested for details.
I can't test this in a graphic Vim, but you can try some options:
Join some events in the same autocommand autocmd BufWritePre,FocusLost *.py ...
Execute an autocommand from an event, something like:
autocmd BufWritePre *.py :execute "%s/\s\+$//e" | doautocmd FocusLost %

how to use pythontidy in vim

what I am using now is ,
autocmd BufWritePost *.py !python PythonTidy.py % %
It really call the tidy programe and change the file, but the vim does not reload the new file.
And I do not want to install another plugin for it.
=======================
note: I found it's dangerous about this feature, PythonTidy will will output a empty file if the command faild, it means if you have syntax error, you will lose your file unless press "u" to get it,but you can't save before you fix syntax error.
I call :!PythonTidy % % manually after pylint complete now.
Use BufWritePre instead of BufWritePost and combine Vim range filtering with PythonTidy’s stdin/stdout mode.
autocmd FileType python autocmd BufWritePre <buffer> let s:saveview = winsaveview() | exe '%!python PythonTidy.py' | call winrestview(s:saveview) | unlet s:saveview
(The use of autocmd FileType python autocmd BufWritePre <buffer> makes this a bit more accurate than matching on a glob pattern: it means “any time a Python file is detected, install this autocmd for that buffer” – so it works independently of file name.)
Unfortunately this cannot preserve your cursor position if you undo the filtering. (You are filtering a whole-file range; when undoing a filter operation, the cursor jumps to the first line in the range; so you end up at the top of the file.) I was hoping to find a way to create a no-op undo state, before, so you could hit u twice and get back to the right place, but I can’t make that work as yet. Maybe someone else knows how.
hi the following fixed the cursor postion problem
function! PythonTidySaver()
let oldpos=getpos('.')
%!PythonTidy
call setpos('.',oldpos)
endfunction
autocmd! bufwritepost *.py call PythonTidySaver()
Based on :help :e:
*:e* *:edit*
:e[dit] [++opt] [+cmd] Edit the current file. This is useful to re-edit the
current file, when it has been changed outside of Vim.
This fails when changes have been made to the current
buffer and 'autowriteall' isn't set or the file can't
be written.
Also see |++opt| and |+cmd|.
{Vi: no ++opt}
So you'd need to use :e after updating the file externally. However, :! doesn't let you use | normally (see :help :!), so you need to wrap it:
autocmd BufWritePost *.py execute "!python PythonTidy.py % %" | e
(:autocmd doesn't interpret | normally either, which is why you don't need to escape it yet again.)

Resources