compile c++ project using vim - vim

I a new vim user, so i am trying to modify vim in order to fit to my needs.
Let's say that i have the project/main.cpp and project/build. Where inside the project/build when i do "make -j5 install" my project is being build and installed correctly. But when i am trying to do that inside from the vim it doesn't work. Here is the code which i use....
map <F5> :call BuildGitRepo()<cr>
function! BuildGitRepo()
:cd %:p:h
let currentFileDir = :pw
:cd currentFileDir
:cd "build"
:!make -j5 install
endfunction

Vim script from a vimrc file functions a bit differently from the Vim window. Commands that begin with : become native in vim script, meaning that you don't need the colon. Also, using local variables is a bit different - you need to use exec.
Finally, you can't capture the output of : commands without buffer redirection, but you can use the getcwd() function to get the current working directory. But it looks like you're cding to the current file's directory twice, so I've made that a bit simpler.
Here's a version of your function that should work in a vimrc file:
map <F5> :call BuildGitRepo()<cr>
function! BuildGitRepo()
exec "cd " . expand("%:p:h") ."/build"
!make -j5 install
endfunction

Related

vim command to map keys to command that maps keys

Background: I'm using this mapping map ,r :! bundle exec ruby %<CR> all the time to easily run test file I'm currently editing. However I also do:
map ,t :! bundle exec ruby test/integration/some_integration_test.rb<CR>
so that I can run this particular integration test with two key strokes while working on some other file. It has hard-coded path, when I move to some other area of the application I type above command with another integration test file path.
How to make a command that creates such mapping automatically?
map ,T :map ,t :! bundle exec ruby %<CR> won't work because it doesn't expand % while creating the mapping, so ,t will always run current file (while I want it to run file I was editing at the time of creating the mapping).
[EDIT]:
Slightly adjusted solution from the answer:
nnoremap ,r :! bundle exec ruby %<CR>
nnoremap ,T :let g:testfile = expand('%:p')
nnoremap ,t :! bundle exec ruby <C-r><C-r>=g:testfile<CR><CR>
,r always runs file under cursor
,T saves current file path under in a variable for running later
,t runs file path stored previously
Just save the current file name (best with a full absolute path to be immune against changes to the current directory; the :p modifier does that) in a variable, and insert the variable instead of % via <C-r>:
:noremap ,r :let g:testfile = expand('%:p')<Bar>! bundle exec ruby %<CR>
:noremap ,t :! bundle exec ruby <C-r><C-r>=g:testfile<CR><CR>
PS: I used :noremap, because that is generally safer and should be the first choice unless you really need remapping to occur.
execute ":nnoremap ,t :! bundle exec ruby ".shellescape(expand('%:p'))."<CR>"
creates a ,t mapping that will execute your test on what is the current file at the time of execution.
But each time you do that you'll lose the previous ,t. I'm not sure that's what you want to do.

Echo shell command within vim

I am writing some map commands that run external commands. For example, I may have the following map command to compile the working project.
nnoremap <F5> :!mvn compile test<CR>
However, when vim switches to a shell, it's not clear what command is running. Is there a way for the command to show up on the shell, short of echoing it? It seems tedious to need to write the following each time, but it would do what I want.
nnoremap <F5> :!echo "mvn compile test"<CR>:!mvn compile test<CR>
If your external command processor is a UNIX style shell, it has an echo feature, and you need only to pass the x option to it:
map <F5> :!sh -xc 'mvn compile test'<CR>

How to open pdf files under cursor (using 'gf') with external PDF readers in vim

The current gf command will open *.pdf files as ascii text. I want the pdf file opened with external tools (like okular, foxitreader, etc.). I tried to use autocmd to achieve it like this:
au BufReadCmd *.pdf silent !FoxitReader % & "open file under cursor with FoxitReader
au BufEnter *.pdf <Ctrl-O> "since we do not really open the file, go back to the previous buffer
However, the second autocmd failed to work as expected. I could not figure out a way to execute <Ctrl-o> command in a autocmd way.
Could anyone give me a hint on how to <Ctrl-O> in autocmd, or just directly suggest a better way to open pdf files with gf?
Thanks.
That's because what follows an autocmd is an ex command (the ones beginning
with a colon). To simulate the execution of a normal mode command, use the
:normal command. The problem is that you can't pass a <C-O> (and not
<Ctrl-O>) directly to :normal, it will be taken as literal characters (<,
then C, then r) which is not a very meaningful normal command. You have two
options:
1.Insert a literal ^O Character
Use controlvcontrolo to get one:
au BufEnter *.pdf normal! ^O
2.Use :execute to Build Your Command
This way you can get a more readable result with the escaped sequence:
au BufEnter *.pdf exe "normal! \<c-o>"
Anyway, this is not the most appropriate command. <C-O> just jumps to the
previous location in the jump list, so your buffer remains opened. I would do
something like:
au BufEnter *.pdf bdelete
Instead. Still I have another solution for you.
Create another command with a map, say gO. Then use your PDF reader
directly, or a utility like open if you're in MacOS X or Darwin (not sure if
other Unix systems have it, and how it's called). It's just like double clicking
the icon of the file passed as argument, so it will open your default PDF reader
or any other application configured to open any file by default, like images or
so.
:nnoremap gO :!open <cfile><CR>
This <cfile> will be expanded to the file under the cursor. So if you want to
open the file in Vim, use gf. If you want to open it with the default
application, use gO.
If you don't have this command or prefer a PDF-only solution, create a map to
your preferred command:
:nnoremap gO :!FoxitReader <cfile> &<CR>
If the default app is acceptable, then simply using :!open % in command mode works. You can always map this to a suitable leader combination in your vim config file etc.
If you want something that works with normal mode, then you could try something like the following (i use this too for opening HTML files), and modify to your own needs:
if has('win32') || has ('win64')
autocmd FileType html nmap <Leader>g :silent ! start firefox "%"<cr>
elseif has('mac')
autocmd FileType html nmap <Leader>g :!open "%"<cr><cr>
endif

Can I use cppcheck when I execute :wq in Vim editor for c/c++

I want to override wq/q/w!/w/q! to user defined command along with its functionality.
Example :
If I use :wq to exit, the command should do static code check of that particular c/c++ file and exit.
Please help me in this case.
Thanks in advance.
The built in solution to your problem is called an "autocommand" in Vim.
It is a way to invoke a command at a specific time like opening, saving or closing a buffer.
See :help autocmd for the full list
In your case, you should add to your .vimrc the following command
autocmd BufWritePre *.cpp,*.hpp !cppcheck %
BufWritePre means 'before writing the buffer' (You can also use BufWrite or BufWritePost)
*.cpp,*.hpp means the auto command will only be applied when saving cpp or hpp files. You can add c and h files if you want.
% means 'path of the current buffer'
cppcheck must be in your path
You are not overriding the defaut behaviour of 'w' but you are using 'hooks' to add custom commands.
I wouldn't do that. It obliges us (well, you actually) to save only when the file is really compilable -- which make no sense when we have to abort the current editing because an urging meeting that we've forget about is about to begin; saving the file in that situation is the normal way to proceed.
Moreover, what is the purpose of running cppcheck on a :wq? How can we exploit the result?
Instead, I'd have a mapping that run cppcheck, though :make in order to exploit the vim quickfix feature (:h quickfix)
function s:Check()
try
let save_makeprg=&makeprg
set makeprg=cppcheck
" you may have to specify other files/extensions
:make *.cpp *.hpp
finally
let &makeprg=save_makeprg
endtry
endfunction
nnoremap <buffer> <c-f7> :call <sid>Check()<cr>
<block>
function FunForQuickfix(makeprgIn, makeefmIn)
try
let save_makeprg=&makeprg
let save_makeefm=&efm
let &makeprg=a:makeprgIn
let &efm=a:makeefmIn
:wa
:make
:cw
finally
let &makeprg=save_makeprg
let &efm=save_makeefm
endtry
endfunction
function CompileAndRunTestCodeByScons()
call FunForQuickfix('scons . -j8 -u', '%f:%l:%c:\ %m,%f:%l:\ %m,build/release64/%f:%l:%c:\ %m,build/release64/%f:%l:\ %m,%f\|%l\|,build/release64/%f:%s,%m:%l:Assertion,%sExpression:\ false,scons:\ building\ terminated\ because\ of\ errors,%sError%m')
endfunction
function CppCheck()
call FunForQuickfix("cppcheck *.cpp -j 8 --enable=all", "\[%f:%l\]:\ %m")
endfunction
nmap ma :wa<CR>:call CompileAndRunTestCodeByScons()<CR>
nmap mc :wa<CR>:call CppCheck()<CR>
nmap <F3> :cp<cr>
nmap <F4> :cn<cr>
</block>
add this in ~/.vimrc, then use ma to compile code and mc to run cppcheck
this code is copy from Luc Hermitte, and i chang it
You might want some things even better, use cppcheck and other checkes while you are developing in vim.
Install and use that vim plugin: https://github.com/scrooloose/syntastic

How to automatically update tag file in vim?

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

Resources