vim :make without external window - vim

in vim, when I use
:make
the output of make is displayed in a "external" window, I don't like this and I use this map
nnoremap <leader>m :w <bar> make<CR><CR><CR>:copen<CR>
but, in some case the output of make is
make: Nothing to be done for `all'.
how I can add a autoclose to copen when the copen have make: Nothing to be done for all. ?

You can check the contents of the quickfix list via getqflist(). Then, I would only conditionally open the quickfix window if the first line does not match the text you don't want to see:
nnoremap <leader>m :w <bar> make<CR><CR><CR>
\:if get(get(getqflist(), 0, {}), 'text', '') !~# 'Nothing to be done' <Bar>
\ copen <Bar>
\endif<CR>
The access via get() avoids errors when the list is empty.
You could also always open the list, and then use :cclose in the conditional, if that better fits your needs.

i have a vim script that helps me a lot:
first it saves the current edit window (if possible, won't work if read only)
then it runs make and redirects errors (stderr) to temp file (stdout is ignored)
if build failed then open quick fix windows and fill it with error messages.
delete temporary file
command! -nargs=* Build call s:RunBuild()
function! s:RunBuild()
let tmpfile = tempname()
"build and surpresses build status messages to stdout
"(stdout message are not very informative and may be very very long)
"Error messages are redirected to temporary file.
let buildcmd = "make -j 2> " . tmpfile . " >/dev/null"
let fname = expand("%")
if fname != ""
" save current buffer if possible (your bad if file is read only)
write
endif
" --- run build command ---
echo "Running make ... "
let cmd_output = system(buildcmd)
"if getfsize(tmpfile) == 0
if v:shell_error == 0
cclose
execute "silent! cfile " . tmpfile
echo "Build succeded"
else
let old_efm = &efm
set efm=%f:%l:%m
execute "silent! cfile " . tmpfile
let &efm = old_efm
botright copen
endif
call delete(tmpfile)
endfunction
Then i map the F5 key to do the build in each vim mode
"F5 - run make (in normal mode)
:nnoremap :Build
"F5 - run make (in visual mode)
:vnoremap :Build
"F5 - run make (in insert mode)
:inoremap :Build

Related

How to make vim for running and compiling Java files as an IDE?

I already use a vim function in Linux vimrc file to execute Java files by just pressing 'F5'.
Below is the function which I use.
inoremap <F5> <Esc> :call CompileRunGcc()<CR><CR>
func! CompileRunGcc()
exec "w"
if &filetype == 'java'
exec "!javac %"
exec "!time java -cp %:p:h %:t:r"
endif
endfunc
But when there is a compiling error, it shows the error message and also the output of the previous compiled program.
What I want is to be shown only the error message without the output of the previous compiled program. How can I do that?
IMO, you'd better use the quickfix list feature to import the errors and warnings found into Vim. From there you'll be able to navigate the errors with :cnext, :cprev...
Regarding what's best with Java, you'll have to explore the various Java related compiler plugins. There is a :compiler javac for instance.
Regarding how to know whether the compilation has succeeded or not I use the method I've described in a similar Q/A: https://stackoverflow.com/a/56991040/15934
The only thing that changes is the way the exec_line variable would be built. It would look like (untested)
" From my build-tools-wrapper plugin
function! lh#btw#build#_get_metrics() abort
let qf = getqflist()
let recognized = filter(qf, 'get(v:val, "valid", 1)')
" TODO: support other locales, see lh#po#context().tranlate()
let errors = filter(copy(recognized), 'v:val.type == "E" || v:val.text =~ "\\v^ *(error|erreur)"')
let warnings = filter(copy(recognized), 'v:val.type == "W" || v:val.text =~ "\\v^ *(warning|attention)"')
let res = { 'all': len(qf), 'errors': len(errors), 'warnings': len(warnings) }
return res
endfunction
" in a java ftplugin
function s:build_and_run(file) abort
let tgt = fnamemodify(a:file, ':r')
" to make sure the buffer is saved
exe 'update ' . a:file
exe 'make ' . tgt
if lh#btw#build#_get_metrics().errors
echom "Error detected, execution aborted"
copen
return
endif
let path = fnamemodify(a:file, ':p:h')
let exec_line = '!time java -cp ' . path. ' ' . tgt
exe exec_line
endfunction
" With <buffer>, I assume this is defined in a java-ftplugin, because the
" specific '!time java'. It could be generalized to many different
" languages though.
nnoremap <buffer> ยต :<C-U>call <sid>build_and_run(expand('%'))<cr>
You can use the v:shell_error variable to check whether the javac command has failed. In that case, you can skip running the program, in which case the error messages will be left around for you to inspect.
function! CompileRunGcc()
exec "w"
if &filetype ==# 'java'
exec "!javac %"
if !v:shell_error
exec "!time java -cp %:p:h %:t:r"
endif
endif
endfunction

Using Uncrustify with VIM

In my vimrc I call Uncrustify by this command:
%!uncrustify -l CPP -c D:\uncrustify\default.cfg
After that on some code I get a Windows Fatal error:
But when I call uncrustify on the same code in the console using the -f option, there is no error.
How can I change my vimrc to avoid such errors in the future? What can invoke this error?
In order to integrate Uncrustify with Vim properly, add the following to your .vimrc:
" Restore cursor position, window position, and last search after running a
" command.
function! Preserve(command)
" Save the last search.
let search = #/
" Save the current cursor position.
let cursor_position = getpos('.')
" Save the current window position.
normal! H
let window_position = getpos('.')
call setpos('.', cursor_position)
" Execute the command.
execute a:command
" Restore the last search.
let #/ = search
" Restore the previous window position.
call setpos('.', window_position)
normal! zt
" Restore the previous cursor position.
call setpos('.', cursor_position)
endfunction
" Specify path to your Uncrustify configuration file.
let g:uncrustify_cfg_file_path =
\ shellescape(fnamemodify('~/.uncrustify.cfg', ':p'))
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction
Now you can either map this function (Uncrustify) to a combination of keys or you could do the convenient trick that I use. Create a file ~/.vim/after/ftplugin/cpp.vim where you can override any Vim settings particularly for C++ and add the following line there:
autocmd BufWritePre <buffer> :call Uncrustify('cpp')
This basically adds a pre-save hook. Now when you save the file with C++ code it will be automatically formatted by Uncrustify utilizing the configuration file you supplied earlier.
For example, the same could be done for Java: in ~/.vim/after/ftplugin/java.vim add:
autocmd BufWritePre <buffer> :call Uncrustify('java')
You got the point.
NOTE: Everything presented here is well-tested and used every day by me.
I have found the placing the following code into your .vimrc to be sufficient:
let g:uncrustifyCfgFile = '~/.uncrustify.cfg'
function! UncrustifyFunc(options) range
exec a:firstline.','.a:lastline.'!uncrustify '.a:options
\.' -c '.g:uncrustifyCfgFile.' -q -l '.&filetype
endfunction
command! -range=% UncrustifyRange <line1>,<line2>call UncrustifyFunc('--frag')
command! Uncrustify let s:save_cursor = getcurpos()
\| %call UncrustifyFunc('')
\| call setpos('.', s:save_cursor)
Note this does assume that you have "uncrustify" binary in your $PATH.
It also assumes your configure file is ~/.uncrustify.cfg however you can change that by modifiying the g:uncrustifyCfgFile variable.
To call run
:Uncrustify
It also works on ranges (which was what promoted me to make this function). Visual selection example:
:'<,'>UncrustifyRange
I have only tired it with C, CPP and JAVA (I assume others will work as well)
In addition to #Alexander Shukaev's answer, adding the following will perform a check for uncrustify config correctness and not auto format if error is detected:
let output = system('uncrustify -q -c ' . a:cfgfile)
if v:shell_error != 0
echo output
endif
return v:shell_error
endfunction
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
if CheckUncrustifyCfg(g:uncrustify_cfg_file_path)
echo "Config file" g:uncrustify_cfg_file_path "has errors"
echo "No formatting will be performed"
return
endif
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction

Vim - show diff on commit in mercurial;

In my .hgrc I can provide an editor or a command to launch an editor with options on commit.
I want to write a method or alias that launches $ hg ci, it would not only open up message in Vim, but also would split window and there print out $ hg diff.
I know that I can give parameters to vim by using +{command} option. So launching $ vim "+vsplit" does the split but any other options goes to first opened window. So I assume i need a specific function, yet I have no experience in writing my own Vim scripts.
The script should:
Open new vertical split with empty buffer (with vnew possibly)
In empty buffer launch :.!hg diff
Set empty buffer file type as diff :set ft=diff
I've written such function:
function! HgCiDiff()
vnew
:.!hg diff
set ft=diff
endfunction
And in .hgrc I've added option: editor = vim "+HgCiDiff()"
It kind of works, but I would like that splited window would be in right side (now it opens up in left) and mercurial message would be focused window. Also :wq could be setted as temporary shortcut to :wq<CR>:q! (having an assumption that mercurial message is is focused).
Any suggestions to make this a bit more useful and less chunky?
UPDATE: I found vim split guide so changing vnew with rightbelow vnew opens up diff on the right side.
So I expanded my own code:
function! HgCiDiff()
"In .hgrc editor option I call vim "+HgCiDiff()"
"It opens new split with diff inside
rightbelow vnew
:.!hg diff
set ft=diff
saveas! /tmp/hgdiff.txt
execute "normal \<c-w>w"
endfunction
Yet It missed :wq mapping as :wqa, yet using :wqa is not that hard.
Sources of my vimrc is located here: http://hg.jackleo.info/vim-configs/src/08df5cb9d143/vimrc
Sources of my hgrc is located here: http://hg.jackleo.info/home-configs/src/22f5fb47a7d2/.hgrc
Update: as suggested by Randy Morris I updated my code and now it works just as I wanted. Thanks! Also added few extra features as the time went by.
function! HgCiDiff()
"In .hgrc editor option I call vim "+HgCiDiff()"
"It opens new split with diff inside
rightbelow vnew
setlocal buftype=nofile
:.!hg diff
setlocal ft=diff
wincmd p
setlocal spell spelllang=en_us
cnoremap wq wqa
cnoremap q qa
start
endfunction
Edit
Hmm I think this might not be what you are after on second reading. I understand you want a multi-file (unified) diff. I'd really use a hg-aware UI tool and a separate vim editor for the commit message. Sorry about that.
I'll leave the 'original' response stand in case you didn't know VCSCommand + Hg + Vim yet:
My weapon of choice is to abstract it all away with
vcscommand.vim : CVS/SVN/SVK/git/hg/bzr integration plugin
You would
:VCSVimDiff
to diffsplit against the repo version (also with Leadercv)
:VCSVimDiff <revid>
to compare against a specific revision.
My solution consists of three vim files. It doesn't require hg configuration changes, and only shows the diff for the files you're committing, if you've used hg commit file1 file2:
~/.vim/ftdetect/hg.vim
au BufRead,BufNewFile /tmp/hg-editor-*.txt set filetype=hg
~/.vim/syntax/hg.vim
" Vim syntax file
" Language: hg commit file
" Maintainer: Marius Gedminas <marius#gedmin.as>
" Filenames: /tmp/hg-editor-*.txt
" Last Change: 2012 July 8
" Based on gitcommit.vim by Tim Pope
if exists("b:current_syntax")
finish
endif
syn case match
syn sync minlines=50
if has("spell")
syn spell toplevel
endif
syn match hgComment "^HG: .*"
hi def link hgComment Comment
let b:current_syntax = "hg"
~/.vim/ftplugin/hg.vim
" Show diff while editing a Mercurial commit message
" Inspired by http://stackoverflow.com/questions/8009333/vim-show-diff-on-commit-in-mercurial
" and Michael Scherer' svn.vim
function! HgCiDiff()
let i = 0
let list_of_files = ''
while i <= line('$') && getline(i) != 'HG: --'
let i = i + 1
endwhile
while i <= line('$')
let line = getline(i)
if line =~ '^HG: \(added\|changed\)'
let file = substitute(line, '^HG: \(added\|changed\) ', '', '')
let file = "'".substitute(file, "'", "'\''", '')."'"
let list_of_files = list_of_files . ' '.file
endif
let i = i + 1
endwhile
if list_of_files == ""
return
endif
pclose
new
setlocal ft=diff previewwindow bufhidden=delete nobackup noswf nobuflisted nowrap buftype=nofile
silent exec ':0r!hg diff ' . list_of_files
setlocal nomodifiable
goto 1
redraw!
" nooo idea why I have to do this
syn enable
endfunction
call HgCiDiff()
Here's my variation based on Marius Gedminas and JackLeo's versions:
function! HgCiDiff()
" find files that were changed (not interested in added or deleted)
let changed_files = []
let pattern = '\vHG: changed \zs(.+)\ze'
while search("HG: changed", "W") > 0
let line_text = getline(line("."))
call add(changed_files, matchstr(line_text, pattern))
endwhile
let diff_cmd = "hg diff " . join(changed_files, " ")
" Reset cursor to beginning of the buffer
call cursor(1, 1)
rightbelow vnew
setlocal buftype=nofile
let diff_output = system(diff_cmd)
call append(0, split(diff_output, "\n"))
" Reset cursor to beginning of the buffer
call cursor(1, 1)
setlocal ft=diff
wincmd p
setlocal spell spelllang=en_us
cnoremap wq wqa
cnoremap q qa!
startinsert
endfunction

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

Can anybody help me to get solution for my requirement?
Requirement is when a user exits from vim, cppcheck should happen and if any warning or error occurs then it should be prompted to a user.
Thanks in advance.
I assume you don't care if the command is executed asynchronously, since you're quitting the buffer anyway. You can use the :! command to run shell commands and :read to capture the output to a new window:
function! s:RunShellCommand(cmdline)
let first = 1
let words = []
" Expand and escape cmd arguments.
" shellescape() should work with '\'
for part in split(a:cmdline)
if first
" skip the cmd. ugly, i know.
let first = 0
else
if part[0] =~ '\v[%#<]'
let part = expand(part)
endif
let part = shellescape(part, 1)
endif
call add(words, part)
endfor
let expanded_cmdline = join(words)
" Create the new window
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'Showing output from cmd: ' . expanded_cmdline)
call append(line('$'), substitute(getline(2), '.', '=', 'g'))
" This is where actual work is getting done :-)
silent execute '$read !'. expanded_cmdline
" Uncomment the line below if you want the buffer to be
" non-modifiable
" setlocal nomodifiable
1
endfunction
Then you can define an autocommand for when a buffer is unloading:
au BufUnload *.cpp s:RunShellCommand('cppcheck %')
or a somewhat more generic command which you can call at any time:
command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
Now, to prevent closing your buffer, you have to remap :wq or :q to a function that will perform the aforementioned (plus perhaps some confirmation?), since once :quit is invoked, it cannot be aborted.

Can vim monitor realtime changes to a file

My question is similar to this how to monitor a text file in realtime
but I want to do it in vim. I know I can read an opened file use tail -f sample.xml file, and when new content is written to the file, it'll also write the new content to my screen. Can I have vim automatically fill the new data when a file is updated?
You can :set autoread so that vim reads the file when it changes. However (depending on your platform), you have to give it focus.
From the help:
When a file has been detected to have
been changed outside of Vim and it
has not been changed inside of Vim,
automatically read it again. When the
file has been deleted this is not
done.
Don't know about automatically, but you can type:
:e!
to reload the file
Put the following in your .vimrc:
" check one time after 4s of inactivity in normal mode
set autoread
au CursorHold * checktime
like #flukus said in a comment to a previous answer you can call feedkeys["lh"] (it moves the cursor to the right and back to the left, which normaly doesn't do harm when viewing a log file)
So, if you combine the rest of the answer you have a oneliner you can run from ex (whithin vim) when needed:
:set autoread | au CursorHold * checktime | call feedkeys("lh")
***(if you would want to jump (nearly) to the end of the file, just use "G" instead of "lh" with feedkeys)***
Explanation:
autoread: reads the file when changed from the outside (but it doesnt work on its own, there is no internal timer or something like that. It will only read the file when vim does an action, like a command in ex :!
CursorHold * checktime: when the cursor isn't moved by the user for the time specified in 'updatetime' (which is 4000 miliseconds by default) checktime is executed, which checks for changes from outside the file
call feedkeys("lh"): the cursor is moved once, right and back left. and then nothing happens (... which means, that CursorHold is triggered, which means we have a loop)
Additionally you can :set syntax=logtalk to color the log
To stop the scrolling when using call feedkeys("G"), execute :set noautoread - now vim will tell, that the file was change ans ask if one wants to read the changes or not)
(Does this have any sideeffects?)
Edit: I see one side-effect: if one uses "G" as the feedkey, it will scroll down every currently opened buffer?! So, it's not possible to work in the left buffer of a splittet window while having the right buffer scroll down a logfile automatically
Edit2: Another side effect is that when you enter the command line window(by using q:) an error message always pops up.
Stick this in your .vimrc and it should work like a boss. (Taken from: http://vim.wikia.com/wiki/Have_Vim_check_automatically_if_the_file_has_changed_externally)
" Function to Watch for changes if buffer changed on disk
function! WatchForChanges(bufname, ...)
" Figure out which options are in effect
if a:bufname == '*'
let id = 'WatchForChanges'.'AnyBuffer'
" If you try to do checktime *, you'll get E93: More than one match for * is given
let bufspec = ''
else
if bufnr(a:bufname) == -1
echoerr "Buffer " . a:bufname . " doesn't exist"
return
end
let id = 'WatchForChanges'.bufnr(a:bufname)
let bufspec = a:bufname
end
if len(a:000) == 0
let options = {}
else
if type(a:1) == type({})
let options = a:1
else
echoerr "Argument must be a Dict"
end
end
let autoread = has_key(options, 'autoread') ? options['autoread'] : 0
let toggle = has_key(options, 'toggle') ? options['toggle'] : 0
let disable = has_key(options, 'disable') ? options['disable'] : 0
let more_events = has_key(options, 'more_events') ? options['more_events'] : 1
let while_in_this_buffer_only = has_key(options, 'while_in_this_buffer_only') ? options['while_in_this_buffer_only'] : 0
if while_in_this_buffer_only
let event_bufspec = a:bufname
else
let event_bufspec = '*'
end
let reg_saved = #"
"let autoread_saved = &autoread
let msg = "\n"
" Check to see if the autocommand already exists
redir #"
silent! exec 'au '.id
redir END
let l:defined = (#" !~ 'E216: No such group or event:')
" If not yet defined...
if !l:defined
if l:autoread
let msg = msg . 'Autoread enabled - '
if a:bufname == '*'
set autoread
else
setlocal autoread
end
end
silent! exec 'augroup '.id
if a:bufname != '*'
"exec "au BufDelete ".a:bufname . " :silent! au! ".id . " | silent! augroup! ".id
"exec "au BufDelete ".a:bufname . " :echomsg 'Removing autocommands for ".id."' | au! ".id . " | augroup! ".id
exec "au BufDelete ".a:bufname . " execute 'au! ".id."' | execute 'augroup! ".id."'"
end
exec "au BufEnter ".event_bufspec . " :checktime ".bufspec
exec "au CursorHold ".event_bufspec . " :checktime ".bufspec
exec "au CursorHoldI ".event_bufspec . " :checktime ".bufspec
" The following events might slow things down so we provide a way to disable them...
" vim docs warn:
" Careful: Don't do anything that the user does
" not expect or that is slow.
if more_events
exec "au CursorMoved ".event_bufspec . " :checktime ".bufspec
exec "au CursorMovedI ".event_bufspec . " :checktime ".bufspec
end
augroup END
let msg = msg . 'Now watching ' . bufspec . ' for external updates...'
end
" If they want to disable it, or it is defined and they want to toggle it,
if l:disable || (l:toggle && l:defined)
if l:autoread
let msg = msg . 'Autoread disabled - '
if a:bufname == '*'
set noautoread
else
setlocal noautoread
end
end
" Using an autogroup allows us to remove it easily with the following
" command. If we do not use an autogroup, we cannot remove this
" single :checktime command
" augroup! checkforupdates
silent! exec 'au! '.id
silent! exec 'augroup! '.id
let msg = msg . 'No longer watching ' . bufspec . ' for external updates.'
elseif l:defined
let msg = msg . 'Already watching ' . bufspec . ' for external updates'
end
echo msg
let #"=reg_saved
endfunction
let autoreadargs={'autoread':1}
execute WatchForChanges("*",autoreadargs)
Tail Bundle should do what you want. Note, haven't used it myself.
There is a plugin also:
https://github.com/djoshea/vim-autoread
This was the only way I could make this work on OSX.
If unix + neovim
:term tail -f <filename>
Obviously this won't work for everyone, but it's how I do it.
To enable reloading if you open a specific file, you can add this to your .vimrc and use a modeline like vim: set ft+=.watch:. It takes advantage of the feature to set multiple filetypes for a buffer (see below):
vim9script
command WatchFiles {
autocmd! AUWatchFile FocusGained,VimResume,BufEnter,WinEnter,CursorHold * checktime
autocmd! AUWatchFile BufEnter,InsertEnter,CursorHold,CursorHoldI <buffer> checktime
setlocal autoread
checktime
}
command UnwatchFiles {
autocmd! AUWatchFile
set autoread<
}
# To enable this, you may use e.g. a modeline: `vim: set ft+=.watch`
def WatchAutomatically()
# Check if the "list" of filetypes (a dot separated string) contains 'watch'.
if -1 != match(&filetype, "\\(^\\|\\.\\)watch\\($\\|\\.\\)")
WatchFiles
endif
enddef
augroup AUWatchFile | augroup END
autocmd BufWinEnter * call WatchAutomatically()
More details
You are able to set multiple filetypes separated by .:
When a dot appears in the value then this separates two filetype
names. Example:
/* vim: set filetype=c.doxygen : */ ~
See :help 'filetype'.
Keep in mind that you should manipulate the filetype first and set additional options after that in the modeline. Otherwise these options may be overridden by the settings specific for the filetype.
Btw, the above is a Vim9 script (which I discovered today). Translating it back to a good-old Vim script is trivial:
Use " for comments.
Transform multi-line commands like this:
command UnwatchFiles
\ autocmd! AUWatchFile
\ | set autoread<
Remove the vim9script line.
See :help Vim9-script for details.
Shortcomings
Reloading is not limited to the buffer which contains the modeline. You may disable it again with :UnwatchFiles.
It is still dump polling.
VIM will warn you when a file has been updated so that you don't overwrite changes that have been made since you opened it. It will prompt you at that point to reload the file.

Resources