I was trying to experiment on auto-load files which vim load at the time of start.
I kept the example.vim file in:
~/.vim/autoload/
directory and written a very simple function as:
echom "Autoloading..."
function! cpp#running#CompileAndRunFile(commands)
silent !clear
execute "!" . a:commands . " " . bufname("%")
endfunction
function! cpp#running#DebuggersOptions()
" Get the bytecode.
let bytecode = system(a:command . " -E -o " . bufname("%"))
" Open a new split and set it up.
vsplit __Bytecode__
normal! ggdG
setlocal filetype=potionbytecode
setlocal buftype=nofile
" Insert the bytecode.
call append(0, split(bytecode, '\v\n'))
endfunction
But I want to programatically force a reload of an autoload example.vim file which Vim has already loaded, without bothering the user. The reason being that I want that programmer at run-time can change behavior of the function and load latest modified function.
How can I do that ?
Thanks.
auto-load files which vim load at the time of start.
No. The autoload feature is exactly the opposite: an autoloaded script is sourced at runtime, when a function it contains is called.
But I want to programatically force a reload of an autoload example.vim file which Vim has already loaded, without bothering the user.
:source it again?
Related
So, I've added this function to my gvimrc, trying to get MacVim to re-open the same windows / same files, when rebooting.
" http://stackoverflow.com/questions/7955232/making-macvim-reopen-with-files-open-when-closed
" save and close all files and save global session
nnoremap <leader>q :mksession! ~/.vim/gvim-session.vim<CR>:wqa<CR>
" close all files without saving and save global session
nnoremap <leader>www :mksession! ~/.vim/gvim-session.vim<CR>:qa!<CR>
function! RestoreSession()
if argc() == 0 " vim called without arguments
let sessionFile='source ~/.vim/gvim-session.vim'
execute sessionFile
:call delete(sessionFile)
end
endfunction
autocmd VimEnter * call RestoreSession()
However, now, when I open MacVim, I get a completely blank window (that is, not even the ~~~s denoting blank lines, nor a status-bar or sign column or anything else) until I hit the return key:
I'm not sure what I'm doing wrong in my function to cause that. Any help?
You can and should drop the initial : in
:call delete(sessionFile)
delete() deletes a file but sessionFile doesn't point to a file:
let sessionFile='source ~/.vim/gvim-session.vim'
It should look like that:
let sessionFile='~/.vim/gvim-session.vim'
Why did you put source in the file path anyway? You could simply do the following:
execute "source " . sessionFile
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!
When I create a .tex file using vim I get a nice template from having
autocmd BufNewFile *.tex 0r $HOME/.vim/templates/skeleton.tex
in my .vimrc. I also have a makefile-template in my home directory, but this one I have to manually copy to where the .tex file is. In a Linux environment, how can I auto-copy or auto-generate the makefile at the same time as I create a .tex file?
The portable answer would not use cp (which may overwrite a preexisting makefile) but the vim functions readfile() and writefile().
To trigger it, the best thing would be to define and execute a function that loads the first skeleton, and creates the Makefile on the fly:
" untested code
"
function! s:NewTeXPlusMakefile()
let where = expand('%:p:h')
" see mu-template's fork for a more advanced way to find template-files
let skeletons_path = globpath(&rtp, 'templates')
" the current .tex file
let lines = readfile(skeletons_path.'/skeleton.tex')
call setline(1, lines)
" the Makefile, that MUST not be overwritten when it already exists!
let makefile = where.'/Makefile'
if ! filereadable(makefile)
let lines = readfile(skeletons_path.'/skeleton.makefile')
call writefile(lines, makefile )
endif
endfunction
augroup LaTeXTemplates
au!
au BufNewFile *.tex call s:NewTeXPlusMakefile()
augroup END
The normal ex command to do this would be
:!cp $HOME/.vim/templates/skeleton.makefile %:p:h
So you just need to add another autocmd (which will execute after the first)
autocmd BufNewFile *.tex silent !cp $HOME/.vim/templates/skeleton.makefile %:p:h
(the silent simply prevents the copy command from being printed on execution).
I use vim C++ tag file for navigation using Ctrl-]. The problem is whenever some file gets modified, the links are no longer valid and I have to re-run ctags and update the tag file. Our code base is huge and it takes quite a while for generating tag file.
Is there any tool which periodically updates the tag file in background? Can I configure VIM to do the same?
I use gvim under Windows.
Further to Blixtor's answer, you'll need to think a little carefully about the design of the script. I'd recommend segregating the design such that the autocommand uses the Windows "start" command or similar to run an external script in the background: thereby preventing Vim from being unresponsive while the tag file is generated.
That script could then generate the tag file using a different file name (i.e. not "tags": ctags -R -o newtags .) and, when ctags is complete, delete tags and rename newtags to tags. This will prevent the tag file from being unavailable in Vim while the generation is done.
I wrote the vim-easytags plug-in to do exactly this. I initialize my tags file once by scanning a whole project (using the command :UpdateTags **/*.[hc] for example) and afterwards the plug-in will automatically update the tags file as I edit and :update my source code files in Vim. While it updates the tags file it will block Vim, but because it only scans the current file it doesn't take long.
Update (2014-07-30): Still working on the vim-easytags plug-in :-). Nowadays it supports an asynchronous mode to avoid blocking Vim. At the time I write this the asynchronous mode is not the default mode yet, but after some more feedback I'll probably switch the default mode.
I already wrote a plugin to do all the hard job with ctags: Indexer.
It provides painless automatic tags generation for the whole project(s) and keeps tags up-to-date. Tags is generated in background, so, you do not have to wait while ctags generates tags. You can use it independently or as an add-on for another plugin project.tar.gz.
In the first way, you can declare your projects in ~/.indexer_files like this:
[CoolProject]
/home/user/cool_project
[AnotherProject]
option:ctags_params = "--languages=c++"
/home/user/another_project/src
/home/user/another_project/lib
And then, when you open any file from /home/user/cool_project , all this project will be indexed by ctags. When you open tags from another project, tags is generated for it too. Tags from different projects is never mixed. When you save file from project, tags is silently updated. You do not have to care about it, it just works.
For detailed information, see the article: Vim: convenient code navigation for your projects, which explains the usage of Indexer + Vimprj thoroughly.
It is successfully tested on Vim 7.3, on the following systems:
Archlinux
Ubuntu 10.4
Windows XP
Mac OS X Lion
An idea:
Use Vim autocommands (:help autocommand) to trigger running of a script every time a buffer is saved using the BufWritePost event.
This script starts the ctags generation and contains some additional small logic to not run while it's already running (or to run at most every 10 minutes, etc.).
Edit:
Something similar was asked here beforehand, see Vim auto-generate ctags
From its repository: vim-gutentags is a plugin that takes care of the much needed management of tags files in Vim. It will (re)generate tag files as you work while staying completely out of your way. It will even do its best to keep those tag files out of your way too. It has no dependencies and just works.
You can give it a try at https://github.com/ludovicchabant/vim-gutentags.
This logic works for most cases: When opening a new file in vim, change to the directory of that file and generate a tags file there if it does not already exist. When saving a changed buffer, generate a tags file in the directory of the file being saved:
function! GenerateTagsFile()
if (!filereadable("tags"))
exec ":!start /min ctags -R --c++-kinds=+p --fields=+iaS --extra=+q --sort=foldcase ."
endif
endfunction
" Always change to directory of the buffer currently in focus.
autocmd! bufenter *.* :cd %:p:h
autocmd! bufread *.* :cd %:p:h
" Generate tags on opening an existing file.
autocmd! bufreadpost *.cpp :call GenerateTagsFile()
autocmd! bufreadpost *.c :call GenerateTagsFile()
autocmd! bufreadpost *.h :call GenerateTagsFile()
" Generate tags on save. Note that this regenerates tags for all files in current folder.
autocmd! bufwritepost *.cpp :call GenerateTagsFile()
autocmd! bufwritepost *.c :call GenerateTagsFile()
autocmd! bufwritepost *.h :call GenerateTagsFile()
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file
function! DelTagOfFile(file)
let fullpath = a:file
let cwd = getcwd()
let tagfilename = cwd . "/tags"
let f = substitute(fullpath, cwd . "/", "", "")
let f = escape(f, './')
let cmd = 'sed -i "/' . f . '/d" "' . tagfilename . '"'
let resp = system(cmd)
endfunction
function! UpdateTags()
let f = expand("%:p")
let cwd = getcwd()
let tagfilename = cwd . "/tags"
let cmd = 'ctags -a -f ' . tagfilename . ' --c++-kinds=+p --fields=+iaS --extra=+q ' . '"' . f . '"'
call DelTagOfFile(f)
let resp = system(cmd)
endfunction
autocmd BufWritePost *.cpp,*.h,*.c call UpdateTags()
I found this really simple and useful:
cd into the code directory.
ctags -R
Right now I have the following in my .vimrc:
au BufWritePost *.c,*.cpp,*.h !ctags -R
There are a few problems with this:
It's slow -- regenerates tags for files that haven't changed since the last tag generation.
I have to push the enter button again after writing the file because of an inevitable "press Enter or type command to continue".
When you combine these two issues I end up pushing the additional enter too soon (before ctags -R has finished), then see the annoying error message, and have to push enter again.
I know it doesn't sound like a big deal, but with the amount of file writes I do on a given day it tends to get really annoying. There's gotta be a better way to do it!
au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
The downside is that you won't have a useful tags file until it completes. As long as you're on a *nix system it should be ok to do multiple writes before the previous ctags has completed, but you should test that. On a Windows system it won't put it in the background and it'll complain that the file is locked until the first ctags finishes (which shouldn't cause problems in vim, but you'll end up with a slightly outdated tags file).
Note, you could use the --append option as tonylo suggests, but then you'll have to disable tagbsearch which could mean that tag searches take a lot longer, depending on the size of your tag file.
Edit: A solution very much along the lines of the following has been posted as the AutoTag vim script. Note that the script needs a vim with Python support, however.
My solution shells out to awk instead, so it should work on many more systems.
au FileType {c,cpp} au BufWritePost <buffer> silent ! [ -e tags ] &&
\ ( awk -F'\t' '$2\!="%:gs/'/'\''/"{print}' tags ; ctags -f- '%:gs/'/'\''/' )
\ | sort -t$'\t' -k1,1 -o tags.new && mv tags.new tags
Note that you can only write it this way in a script, otherwise it has to go on a single line.
There’s lot going on in there:
This auto-command triggers when a file has been detected to be C or C++, and adds in turn a buffer-local auto-command that is triggered by the BufWritePost event.
It uses the % placeholder which is replaced by the buffer’s filename at execution time, together with the :gs modifier used to shell-quote the filename (by turning any embedded single-quotes into quote-escape-quote-quote).
That way it runs a shell command that checks if a tags file exists, in which case its content is printed except for the lines that refer to the just-saved file, meanwhile ctags is invoked on just the just-saved file, and the result is then sorted and put back into place.
Caveat implementor: this assumes everything is in the same directory and that that is also the buffer-local current directory. I have not given any thought to path mangling.
I wrote easytags.vim to do just this: automatically update and highlight tags. The plug-in can be configured to update just the file being edited or all files in the directory of the file being edited (recursively). It can use a global tags file, file type specific tags files and project specific tags files.
I've noticed this is an old thread, however...
Use incron in *nix like environments supporting inotify. It will always launch commands whenever files in a directory change. i.e.,
/home/me/Code/c/that_program IN_DELETE,IN_CLOSE_WRITE ctags --sort=yes *.c
That's it.
Perhaps use the append argument to ctags as demonstrated by:
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file
I can't really vouch for this as I generally use source insight for code browsing, but use vim as an editor... go figure.
How about having ctags scheduled to run via crontab? If your project tree is fairly stable in it's structure, that should be doable?
To suppress the "press enter" prompt, use :silent.
On OSX this command will not work out of the box, at least not for me.
au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
I found a post, which explains how to get the standard ctags version that contains the -R option. This alone did not work for me. I had to add /usr/local/bin to the PATH variable in .bash_profile in order to pick up the bin where Homebrew installs programs.
In my opninion, plugin Indexer is better.
http://www.vim.org/scripts/script.php?script_id=3221
It can be:
1) an add-on for project.tar.gz
2) an independent plugin
background tags generation (you have not wait while ctags works)
multiple projects supported
There is a vim plugin called AutoTag for this that works really well.
If you have taglist installed it will also update that for you.
The --append option is indeed the way to go. Used with a grep -v, we can update only one tagged file. For instance, here is a excerpt of an unpolished plugin that addresses this issue. (NB: It will require an "external" library plugin)
" Options {{{1
let g:tags_options_cpp = '--c++-kinds=+p --fields=+imaS --extra=+q'
function! s:CtagsExecutable()
let tags_executable = lh#option#Get('tags_executable', s:tags_executable, 'bg')
return tags_executable
endfunction
function! s:CtagsOptions()
let ctags_options = lh#option#Get('tags_options_'.&ft, '')
let ctags_options .= ' '.lh#option#Get('tags_options', '', 'wbg')
return ctags_options
endfunction
function! s:CtagsDirname()
let ctags_dirname = lh#option#Get('tags_dirname', '', 'b').'/'
return ctags_dirname
endfunction
function! s:CtagsFilename()
let ctags_filename = lh#option#Get('tags_filename', 'tags', 'bg')
return ctags_filename
endfunction
function! s:CtagsCmdLine(ctags_pathname)
let cmd_line = s:CtagsExecutable().' '.s:CtagsOptions().' -f '.a:ctags_pathname
return cmd_line
endfunction
" ######################################################################
" Tag generating functions {{{1
" ======================================================================
" Interface {{{2
" ======================================================================
" Mappings {{{3
" inoremap <expr> ; <sid>Run('UpdateTags_for_ModifiedFile',';')
nnoremap <silent> <Plug>CTagsUpdateCurrent :call <sid>UpdateCurrent()<cr>
if !hasmapto('<Plug>CTagsUpdateCurrent', 'n')
nmap <silent> <c-x>tc <Plug>CTagsUpdateCurrent
endif
nnoremap <silent> <Plug>CTagsUpdateAll :call <sid>UpdateAll()<cr>
if !hasmapto('<Plug>CTagsUpdateAll', 'n')
nmap <silent> <c-x>ta <Plug>CTagsUpdateAll
endif
" ======================================================================
" Auto command for automatically tagging a file when saved {{{3
augroup LH_TAGS
au!
autocmd BufWritePost,FileWritePost * if ! lh#option#Get('LHT_no_auto', 0) | call s:Run('UpdateTags_for_SavedFile') | endif
aug END
" ======================================================================
" Internal functions {{{2
" ======================================================================
" generate tags on-the-fly {{{3
function! UpdateTags_for_ModifiedFile(ctags_pathname)
let source_name = expand('%')
let temp_name = tempname()
let temp_tags = tempname()
" 1- purge old references to the source name
if filereadable(a:ctags_pathname)
" it exists => must be changed
call system('grep -v " '.source_name.' " '.a:ctags_pathname.' > '.temp_tags.
\ ' && mv -f '.temp_tags.' '.a:ctags_pathname)
endif
" 2- save the unsaved contents of the current file
call writefile(getline(1, '$'), temp_name, 'b')
" 3- call ctags, and replace references to the temporary source file to the
" real source file
let cmd_line = s:CtagsCmdLine(a:ctags_pathname).' '.source_name.' --append'
let cmd_line .= ' && sed "s#\t'.temp_name.'\t#\t'.source_name.'\t#" > '.temp_tags
let cmd_line .= ' && mv -f '.temp_tags.' '.a:ctags_pathname
call system(cmd_line)
call delete(temp_name)
return ';'
endfunction
" ======================================================================
" generate tags for all files {{{3
function! s:UpdateTags_for_All(ctags_pathname)
call delete(a:ctags_pathname)
let cmd_line = 'cd '.s:CtagsDirname()
" todo => use project directory
"
let cmd_line .= ' && '.s:CtagsCmdLine(a:ctags_pathname).' -R'
echo cmd_line
call system(cmd_line)
endfunction
" ======================================================================
" generate tags for the current saved file {{{3
function! s:UpdateTags_for_SavedFile(ctags_pathname)
let source_name = expand('%')
let temp_tags = tempname()
if filereadable(a:ctags_pathname)
" it exists => must be changed
call system('grep -v " '.source_name.' " '.a:ctags_pathname.' > '.temp_tags.' && mv -f '.temp_tags.' '.a:ctags_pathname)
endif
let cmd_line = 'cd '.s:CtagsDirname()
let cmd_line .= ' && ' . s:CtagsCmdLine(a:ctags_pathname).' --append '.source_name
" echo cmd_line
call system(cmd_line)
endfunction
" ======================================================================
" (public) Run a tag generating function {{{3
function! LHTagsRun(tag_function)
call s:Run(a:tag_function)
endfunction
" ======================================================================
" (private) Run a tag generating function {{{3
" See this function as a /template method/.
function! s:Run(tag_function)
try
let ctags_dirname = s:CtagsDirname()
if strlen(ctags_dirname)==1
throw "tags-error: empty dirname"
endif
let ctags_filename = s:CtagsFilename()
let ctags_pathname = ctags_dirname.ctags_filename
if !filewritable(ctags_dirname) && !filewritable(ctags_pathname)
throw "tags-error: ".ctags_pathname." cannot be modified"
endif
let Fn = function("s:".a:tag_function)
call Fn(ctags_pathname)
catch /tags-error:/
" call lh#common#ErrorMsg(v:exception)
return 0
finally
endtry
echo ctags_pathname . ' updated.'
return 1
endfunction
function! s:Irun(tag_function, res)
call s:Run(a:tag_function)
return a:res
endfunction
" ======================================================================
" Main function for updating all tags {{{3
function! s:UpdateAll()
let done = s:Run('UpdateTags_for_All')
endfunction
" Main function for updating the tags from one file {{{3
" #note the file may be saved or "modified".
function! s:UpdateCurrent()
if &modified
let done = s:Run('UpdateTags_for_ModifiedFile')
else
let done = s:Run('UpdateTags_for_SavedFile')
endif
endfunction
This code defines:
^Xta to force the update of the tags base for all the files in the current project ;
^Xtc to force the update of the tags base for the current (unsaved) file ;
an autocommand that updates the tags base every time a file is saved ;
and it supports and many options to disable the automatic update where we don't want it, to tune ctags calls depending on filetypes, ...
It is not just a tip, but a small excerpt of a plugin.
HTH,
Auto Tag is a vim plugin that updates existing tag files on save.
I've been using it for years without problems, with the exception that it enforces a maximum size on the tags files. Unless you have a really large set of code all indexed in the same tags file, you shouldn't hit that limit, though.
Note that Auto Tag requires Python support in vim.