how to use pythontidy in vim - 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.)

Related

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: Change working directory only for the current buffer

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

Golang Formatter and Vim - How to destroy history record?

Go (Golang) programming language comes with a tool called go fmt. Its a code formatter, which formats your code automagically (alignments, alphabetic sorting, tabbing, spacing, idioms...). Its really awesome.
So I've found this little autocommand which utilizes it in Vim, each time buffer is saved to file.
au FileType go au BufWritePre <buffer> Fmt
Fmt is a function that comes with Go vim plugin.
This is really great, but it has 1 problem. Each time formatter writes to buffer, it creates a jump in undo/redo history. Which becomes very painful when trying to undo/redo changes, since every 2nd change is formatter (making cursor jump to line 1).
So I am wondering, is there any way to discard latest change from undo/redo history after triggering Fmt?
EDIT:
Ok, so far I have:
au FileType go au BufWritePre <buffer> undojoin | Fmt
But its not all good yet. According to :h undojoin, undojoin is not allowed after undo. And sure enough, it fires an error when I try to :w after an undo.
So how do I achieve something like this pseudo-code:
if lastAction != undo then
au FileType go au BufWritePre <buffer> undojoin | Fmt
end
If I get this last bit figured out, I think I have a solution.
I think this is almost there, accomplishes what you ask, but I see it's deleting one undo point (I think this is expected from undojoin):
function! GoFmt()
try
exe "undojoin"
exe "Fmt"
catch
endtry
endfunction
au FileType go au BufWritePre <buffer> call GoFmt()
EDIT
Based on MattyW answer I recalled another alternative:
au FileType go au BufWritePre <buffer> %!gofmt
:%!<some command> executes a shell command over the buffer, so I do it before writing it to file. But also, it's gonna put the cursor at top of file...
Here is my go at this. It seems to be working well both with read/write autocmds and bound to a key. It puts the cursor back
and doesn't include the top-of-file event in the undos.
function! GoFormatBuffer()
if &modifiable == 1
let l:curw=winsaveview()
let l:tmpname=tempname()
call writefile(getline(1,'$'), l:tmpname)
call system("gofmt " . l:tmpname ." > /dev/null 2>&1")
if v:shell_error == 0
try | silent undojoin | catch | endtry
silent %!gofmt -tabwidth=4
endif
call delete(l:tmpname)
call winrestview(l:curw)
endif
endfunction
I check modifiable because I use vim as my pager.
I attempted to use #pepper_chino's answer but ran into issues where if fmt errors then vim would undo the last change prior to running GoFmt. I worked around this in a long and slightly convoluted way:
" Fmt calls 'go fmt' to convert the file to go's format standards. This being
" run often makes the undo buffer long and difficult to use. This function
" wraps the Fmt function causing it to join the format with the last action.
" This has to have a try/catch since you can't undojoin if the previous
" command was itself an undo.
function! GoFmt()
" Save cursor/view info.
let view = winsaveview()
" Check if Fmt will succeed or not. If it will fail run again to populate location window. If it succeeds then we call it with an undojoin.
" Copy the file to a temp file and attempt to run gofmt on it
let TempFile = tempname()
let SaveModified = &modified
exe 'w ' . TempFile
let &modified = SaveModified
silent exe '! ' . g:gofmt_command . ' ' . TempFile
call delete(TempFile)
if v:shell_error
" Execute Fmt to populate the location window
silent Fmt
else
" Now that we know Fmt will succeed we can now run Fmt with its undo
" joined to the previous edit in the current buffer
try
silent undojoin | silent Fmt
catch
endtry
endif
" Restore the saved cursor/view info.
call winrestview(view)
endfunction
command! GoFmt call GoFmt()
I just have this in my .vimrc:
au BufWritePost *.go !gofmt -w %
Automatically runs gofmt on the file when I save. It doesn't actually reformat it in the buffer so it doesn't interrupt what I'm looking at, but it's correctly formatted on disk so all check ins are properly formatted. If you want to see the correctly formatted code looks like you can just do :e .
Doesn't do anything to my undo/redo history either
You can install the vim plugins from the default repository. Alternatively, a pathogen friendly mirror is here:
https://github.com/jnwhiteh/vim-golang
Then you can use the :Fmt command to safely do a go fmt!

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 autocommand doesn't run when opening file

I'm using QuickCursor for entering text to forms.
My problem with that is I always have MacVim open, and with hidden enabled, so when I :wq from the temp file QuickCursor make, the buffer stays in MacVim, so I have to delete it to get QuickCursor paste back to the window.
I wanted to solve this with an autocommand in my vimrc:
autocmd BufRead "/private/var/folders/fg/gv_*/T/*" set bufhidden="delete" | startinsert!
but this never run. What could be the problem ? What is the right event to use ? I tried BufWinEnter, BufNewFile, neither of them works, or maybe something else is the problem.
Ok, after several hours of try, I finally found out.
I had added quotes to the bufhidden setting and the filename. It should be:
autocmd BufRead /private/var/folders/fg/gv_*/T/* set bufhidden=delete | startinsert!
With the extra quotes it doesn't work:
"delete" is an invalid option value (see :he bufhidden)
quotes around a filename prevent the wildcards (glob characters) from matching (see doc)
If anybody else using QuickCursor, you can fine-tune it:
autocmd BufWinEnter /private/var/folders/fg/gv_*/T/* set bufhidden=delete |
exe "normal G$" | startinsert!
So it changes to insert mode at the end of the text

Resources