this is some codes in my vim config in .vimrc file below
" Compile function
map r :call CompileRunGcc()<CR>
func! CompileRunGcc()
exec "w"
if &filetype == 'c'
exec "!g++ % -o %<"
exec "!time ./%<"
elseif &filetype == 'cpp'
exec "!g++ % -o %<"
exec "!time ./%<"
elseif &filetype == 'java'
exec "!javac %"
exec "!time java %<"
elseif &filetype == 'sh'
:!time bash %
elseif &filetype == 'python'
silent! exec "!clear"
exec "!time python3 %"
elseif &filetype == 'html'
exec "!firefox % &"
elseif &filetype == 'markdown'
exec "MarkdownPreview"
elseif &filetype == 'vimwiki'
exec "MarkdownPreview"
endif
endfunc
noremap R :call CompileBuildrrr()<CR>
func! CompileBuildrrr()
exec "w"
if &filetype == 'vim'
exec "source $MYVIMRC"
elseif &filetype == 'markdown'
exec "echo"
endif
endfunc
input:vim --version
output:VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Aug 29 2020 14:11:37)
It's an error message that happens when we source a file from a function which is defined in that file.
I guess you've defined your function in your vimrc which you're trying to source.
It should be :source % BTW if you want to source the current script and not only the .vimrc.
PS: you should have a look at :h :make because !compilername is what we had to do some 20ish years ago with the not-improved Vi. Vim has introduced (almost from the start) integrated compilation with the quickfix feature. And given how gnumake is configured on all systems (but mingw), :make %< is enough to compile C++, C, Fortran... For some other languages compiler plugins :h :compiler are also provided by Vim.
Related
I run vim in terminal and whenever I search for something using grep, like
:grep search_for filename
it closes the vim, shows result in terminal with the "Press Enter to continue" message and only after I press enter it shows the results back in vim. How to prevent this terminal opening and show results directly in vim?
One method would be to do the following:
function! Grep(...)
return system(join([&grepprg] + [a:1] + [expandcmd(join(a:000[1:-1], ' '))], ' '))
endfunction
command! -nargs=+ -complete=file_in_path -bar Grep cgetexpr Grep(<f-args>)
command! -nargs=+ -complete=file_in_path -bar LGrep lgetexpr Grep(<f-args>)
cnoreabbrev <expr> grep (getcmdtype() ==# ':' && getcmdline() ==# 'grep') ? 'Grep' : 'grep'
cnoreabbrev <expr> lgrep (getcmdtype() ==# ':' && getcmdline() ==# 'lgrep') ? 'LGrep' : 'lgrep'
augroup quickfix
autocmd!
autocmd QuickFixCmdPost cgetexpr cwindow
autocmd QuickFixCmdPost lgetexpr lwindow
augroup END
This will let you type out :grep foo without the need for "Press Enter" prompt. I would recommend you read the article/gist as well.
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
I want a minimum way of using git blame from vim (I don't want to use the whole Fugitive plugin). What I have right now is this:
This function is from the vim help page and enables me to open shell commands in a scratch buffer.
function! s:ExecuteInShell(command)
let command = join(map(split(a:command), 'expand(v:val)'))
let winnr = bufwinnr('^' . command . '$')
silent! execute winnr < 0 ? 'botright new ' . fnameescape(command) : winnr . 'wincmd w'
setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap number
echo 'Execute ' . command . '...'
silent! execute 'silent %!'. command
silent! execute 'resize ' . line('$')
silent! redraw
silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>'
echo 'Shell command ' . command . ' executed.'
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
Together with the above function I would like to do:
noremap <leader>b :Shell git blame -L line(".") - 5, line(".") + 5 %<cr>
to get a git blame window for the rows around the cursor position in the current buffer.
Now I have two questions:
1: How can I make the scratch buffer that opens read-only so I can close it using only q? I would like to make this change in the function so that all: Shell commands can be closed with q.
2: How can i get line(".") - 5 expand into current line - 5 row number?
To make a buffer read-only and not modifiable, you can put
setlocal readonly nomodifiable
at the end of your function.
In the case of your next question, you can use execute and eval
noremap <leader>b :execute "Shell git blame -L " . eval(line(".")-5)) . ",+10 %"<cr>
I recommend to read these descriptions, and help in general:
:h execute
:h eval
:h readonly
:h nomodifiable
Also here is the link to the mentioned function on wikia.
I use a simple hack to get my vim git integration:
This solves my git commit/add , blame and op.
map <F5> :!git add %;git commit -m "commit" %<CR>
map <F3> :!git blame % > %.blame<CR>:vsplit %.blame<CR>
map <F4> :!git log --abbrev-commit % > %.log<CR>:vsplit %.log<CR>
i have something here, the script can be copied and added to the .vimrc file.
command Blame will run git blame on the current file, will split the screen and put the result of 'git blame -w' into the lower buffer (buffer is put into read only mode), your cursor will be in the blame buffer (current line as in source file)
while in the lower buffer: GShow will split the lower screen and open the commit 'git show -w [hash]' for the current line in the right hand buffer (buffer again in read only mode).
"======================================================
" Function runs git blame on file in current buffer and
" puts output into a new window
" move to current line in git output
" (can't edit output)
"======================================================
command! -nargs=* Blame call s:GitBlame()
function! s:GitBlame()
let cmdline = "git blame -w " . bufname("%")
let nline = line(".") + 1
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
execute "$read !" . cmdline
setlocal nomodifiable
execute "normal " . nline . "gg"
execute "set filetype=cpp"
endfunction
"======================================================
" function runs git show on report of git blame;
" the first token of a line is taken as SHA checsum of the
" git commit
"======================================================
command! -nargs=* GShow call s:GitShowFromBlame()
function! s:GitShowFromBlame()
let curline = getline( "." )
let tokens = split(curline)
let cmdline = "git show -w " . tokens[0]
"botright new
"topleft new
"vsplit new
"vnew new
vertical new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
execute "$read !" . cmdline
setlocal nomodifiable
execute "normal 1gg"
execute "set filetype=cpp"
endfunction
My take on this
fun! GbSyncLines(is_ow2bw)
let l:ow = getbufvar(+expand('<abuf>'), 'origWindow')
let l:bw = getbufvar(+expand('<abuf>'), 'blameWindow')
let l:origLine=line('.', win_getid(l:ow))
let l:blameLine=line('.', win_getid(l:bw))
if a:is_ow2bw == 1
eval win_execute(win_getid(l:bw), "windo call cursor(" . l:origLine . ", 0)")
else
eval win_execute(win_getid(l:ow), "windo call cursor(" . l:blameLine . ", 0)")
endif
endfun
fun! GbMake(view, origWindow)
let l:origWindow=a:origWindow
let l:file_dir=expand('#'.winbufnr(a:origWindow).':h')
let l:file_name=expand('#'.winbufnr(a:origWindow).':t')
let l:origLine=line('.', win_getid(a:origWindow))
sil exe a:view
setl buftype=nofile bufhidden=wipe
exe "lcd ".l:file_dir
exe "0r ! git blame " . l:file_name
setl nomodifiable
setl nonumber norelativenumber
if v:shell_error != 0
exe l:origWindow . "wincmd w"
return
end
eval searchpos('(')
eval searchpairpos('(', '', ')')
norm! gE
exe "vertical resize " . col('.')
let l:blameWindow = winnr()
let b:blameWindow = winnr()
let b:origWindow = a:origWindow
let l:origLine=line('.', win_getid(b:origWindow))
eval cursor(l:origLine , 1)
nnoremap <buffer> <C-]> :call GcommitShow(expand("<cword>"), line(".")) <CR>
au BufWipeout <buffer> call win_execute(win_getid(getbufvar(+expand('<abuf>'), 'origWindow')), "windo setl scrollbind&")
au WinEnter <buffer> :call GbSyncLines(1)
au WinLeave <buffer> :call GbSyncLines(0)
setl scrollbind
exe a:origWindow . "wincmd w"
setl scrollbind
exe "syncbind"
if a:view == "enew"
exe l:blameWindow . "wincmd w"
end
endfun
fun! GcommitShowClose()
let l:w=getbufvar(expand('<abuf>'), 'origWindow')
let l:l=getbufvar(expand('<abuf>'), 'origLine')
let l:v=getbufvar(expand('<abuf>'), 'origView')
eval GbMake("enew", l:w)
eval winrestview(l:v)
eval cursor(l:l, 1)
endfun
fun! GcommitShow(commit, linenr)
let l:origWindow=b:origWindow
let l:viewsave=winsaveview()
sil exe "enew | setlocal buftype=nofile | setlocal bufhidden=wipe | 0r ! git show " . a:commit
setl nomodifiable
setl nonumber norelativenumber
if v:shell_error != 0
eval GbMake('enew', l:origWindow)
return
end
let b:origWindow=l:origWindow
let b:origLine=a:linenr
let b:origView=l:viewsave
nnoremap <buffer> <C-O> :call GcommitShowClose()<CR>
eval cursor(1, 1)
endfun
fun! Gb()
eval GbMake('vnew', winnr())
endfun
command! Gb call Gb()
while in the blame window, CTRL+] shortcut will show git show for commit the cursor is on. Then CTRL+O will get back to the git blame.
Note lcd on start - command will work even when you are not in the git dir. The gist
I am trying to write a function to cause vim to open the relative header/source file in a split window.
What I have works (see below) apart from the file it opens in the split doesn't have syntax highlighting.
function! SplitOther()
let s:fname = expand("%:p:r")
if expand("%:e") == "h"
set splitright
exe "vsplit" fnameescape(s:fname . ".cpp")
elseif expand("%:e") == "cpp"
set nosplitright
exe "vsplit" fnameescape(s:fname . ".h")
endif
endfunction
autocmd! BufReadPost *.h,*.cpp call SplitOther()
I have tried appending syntax on to the command (just before the endfunction) but that doesn't seem to want to work.
I think it happens when the file isn't in a buffer before splitting? I'm not 100% sure though.
Edit
I change my function to have allow the definition of file pairs, I'm not sure if it will change my question at all so here's the extended version:
function! SplitOther()
let s:pairs = [ [ "h", "cpp" ], [ "vert", "frag" ] ]
let s:fname = expand("%:p:r")
for [s:left, s:right] in s:pairs
if expand("%:e") == s:left
set splitright
exe "vsplit" fnameescape(s:fname . "." . s:right)
elseif expand("%:e") == s:right
set nosplitright
exe "vsplit" fnameescape(s:fname . "." . s:left)
endif
endfor
endfunction
autocmd! BufReadPost * call SplitOther()
Got it!
When the file was being loaded into the vsplit it's filetype wasn't being set.
I noted that when vsplit is called the new split grabs focus and that is the window that does not have syntax highlighting so you can simply add exe "filetype" "detect" at the end of the function to tell vim to detect the filetype of the current window.
The result:
function! SplitOther()
let s:pairs = [ [ "h", "cpp" ], [ "vert", "frag" ] ]
let s:fname = expand("%:p:r")
for [s:left, s:right] in s:pairs
if expand("%:e") == s:left
set splitright
exe "vsplit" fnameescape(s:fname . "." . s:right)
break
elseif expand("%:e") == s:right
set nosplitright
exe "vsplit" fnameescape(s:fname . "." . s:left)
break
endif
endfor
exe "filetype" "detect"
endfunction
autocmd! BufRead * call SplitOther()
The problem is that filetype detection is triggered by an autocmd, but by default, autocommands do not nest (cp. :help autocmd-nested).
Also, by using :autocmd! with a bang, you're clearing all other such global autocmds; this might affect other customizations or plugins! You should define your own scope via :augroup, then it's safe. Taken together:
augroup MyAltSplitPlugin
autocmd! BufReadPost * nested call SplitOther()
augroup END
I try create a map for open ~/.vimrc, but open the ~/.vimrc only when the buffer is empty, else split and open.
I try this
fun! BufferIsEmpty() "{{{
if line('$') == 1 && getline(1) == ''
return 1
else
return 0
endif
endf "}}}
fun! NotEmptySplit() "{{{
if !BufferIsEmpty()
sp
endif
return
endf
command! -nargs=0 NotEmptySplit call NotEmptySplit()
nnoremap <silent><leader>ve :NotEmptySplit <bar> ~/.vimrc<CR>
but I get this error
E488: Trailing characters
To take kev's excellent answer a bit further:
How about pulling out a generic 'open file in split if buffer not empty' function.
fu! OpenInSplitIfBufferDirty(file)
if line('$') == 1 && getline(1) == ''
exec 'e' a:file
else
exec 'sp' a:file
endif
endfu
nnoremap <silent> <leader>ve :call OpenInSplitIfBufferDirty($MYVIMRC)<cr>
command -nargs=1 -complete=file -bar CleverOpen :call OpenInSplitIfBufferDirty(<q-args>)
Adding -bar option will fix the E488 error.
command! -bar -nargs=0 NotEmptySplit call NotEmptySplit()
nnoremap <silent><leader>ve :NotEmptySplit <BAR> ~/.vimrc<CR>
But it will raise another E488 error from <BAR> ~/.vimrc<CR>.
I'm trying to refactor your code:
fun! OpenVimrc()
if line('$') == 1 && getline(1) == ''
e $MYVIMRC
else
sp $MYVIMRC
endif
endf
nnoremap <silent><leader>ve :call OpenVimrc()<CR>
These is a variable called b:changedtick to track changing counter.