Autocmd-buflocal response to wrong buffer - vim

I use vim open a file, and the buffer id(bufnr()) is 2, then I run a function PreviewJupyterMD in Vim commandline by call PreviewJupyterMD().
The function body is like:
function! PreviewJupyterMD()
" creat a md file and load file name to a variable l:md_file
...
...
exec "edit" . l:md_file
let b:created_for_jupyter = 1
autocmd BufUnload <buffer> call MDCleanUp()
endfunction
So what I do is use edit open a new file and load it to buffer 3(I checked it by bufnr(), too). And add a local variable to buffer 3. Then I want vim run MDCleanUp function for buffer 3 when I close Vim.
What MDCleanUp do is check whether buffer has a variable if so delete file of that buffer from disk:
function! MDCleanUp()
if exists("b:created_for_jupyter")
call delete(expand("<afile>:p"))
endif
" below 2 line use to know this function run on which buffer
echom bufnr()
sleep 4
endfunction
The actural behavior is MDCleanUp run twice, but all output message by echom bufnr() is 2, output 2 twice!
Would you give me some instruction or suggestion about why the output is:
2
2
and how to let it be:
2
3
Thanks in advance!

Related

How to test if there is only default buffer open?

I'm writing a plugin that loads sessions only if no buffers have been open. So far I'm testing vs argc.
if (argc() != 0)
return
endif
This works fine if I pass in arguments from the command line: vim file1
However, the problem is that I have some scripts that wrap around vim:
function foo {
vim file1
}
$ foo
In the latter case, argc is empty and thus the above if condition fails.
How do you test if vim was invoked with only the default buffer open?
If you pass files to Vim, that will be reflected in argc (also when you wrap the Vim invocation). Rather, the corner case is launching Vim with an edit command, e.g. vim -c "edit foo". If you need to detect that, you need to check two things:
the current buffer is the default blank buffer
no other text buffers have been loaded
Here's a set of functions to implement that:
function! IsBlank( bufnr )
return (empty(bufname(a:bufnr)) &&
\ getbufvar(a:bufnr, '&modified') == 0 &&
\ empty(getbufvar(a:bufnr, '&buftype'))
\)
endfunction
function! ExistOtherBuffers( targetBufNr )
return ! empty(filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != a:targetBufNr'))
endfunction
function! IsEmptyVim()
let l:currentBufNr = bufnr('')
return IsBlank(l:currentBufNr) && ! ExistOtherBuffers(l:currentBufNr)
endfunction
The best I could come up with was to write a function. I thought bufnr('$') would do it but it lists that highest loaded buffer number. The bufnr('$') function returns 1 even though I have not opened a file (simply launched vim). Also buffers can be unloaded with :bw, which does not change what bufnr('$') returns.
Anyway this is the function:
function! NumBuffers()
let rc = 0
for idx in range(bufnr('$'))
if bufloaded(idx)
let rc += 1
endif
endfor
return rc
endfunction

Favourite places in vim

Is there a command in vim that can bookmark a place (path to the file, line number in that file), so that I can go to that place easily later?
It would be similar as NERDTree :Bookmark command. You can open your file with NERDTreeFromBookmark. I'm looking for the same functionality with the difference that bookmark is not only a file but file + line number.
Thank you
Yes you can do so with the 'mark' command. There are two types of bookmarks you can create, local and global. You are referring to a global bookmark.
You can type 'mP' to create a bookmark called P. Notice the case, uppercase indicates it is a global bookmark. To go to that bookmark, type `P.
Hope this helps
Source
The viminfo setting can contain the option !, which makes it store any global variables with uppercase letters in the viminfo file. Using this, you can define a variable called g:BOOKMARKS and store your bookmarks in there.
Here's some vimscript you could use to do that:
set viminfo+=!
if !exists('g:BOOKMARKS')
let g:BOOKMARKS = {}
endif
" Add the current [filename, cursor position] in g:BOOKMARKS under the given
" name
command! -nargs=1 Bookmark call s:Bookmark(<f-args>)
function! s:Bookmark(name)
let file = expand('%:p')
let cursor = getpos('.')
if file != ''
let g:BOOKMARKS[a:name] = [file, cursor]
else
echom "No file"
endif
wviminfo
endfunction
" Delete the user-chosen bookmark
command! -nargs=1 -complete=custom,s:BookmarkNames DelBookmark call s:DelBookmark(<f-args>)
function! s:DelBookmark(name)
if !has_key(g:BOOKMARKS, a:name)
return
endif
call remove(g:BOOKMARKS, a:name)
wviminfo
endfunction
" Go to the user-chosen bookmark
command! -nargs=1 -complete=custom,s:BookmarkNames GotoBookmark call s:GotoBookmark(<f-args>)
function! s:GotoBookmark(name)
if !has_key(g:BOOKMARKS, a:name)
return
endif
let [filename, cursor] = g:BOOKMARKS[a:name]
exe 'edit '.filename
call setpos('.', cursor)
endfunction
" Completion function for choosing bookmarks
function! s:BookmarkNames(A, L, P)
return join(sort(keys(g:BOOKMARKS)), "\n")
endfunction
I'm not sure how readable the code is, but basically, the Bookmark command accepts a single parameter to use as a name. It will store the current filename and cursor position to the g:BOOKMARKS dictionary. You can use the GotoBookmark command with a mark name to go to it. DelBookmark works in the same way, but deletes the given mark. Both functions are tab-completed.
Another way to jump through them is by using this command:
" Open all bookmarks in the quickfix window
command! CopenBookmarks call s:CopenBookmarks()
function! s:CopenBookmarks()
let choices = []
for [name, place] in items(g:BOOKMARKS)
let [filename, cursor] = place
call add(choices, {
\ 'text': name,
\ 'filename': filename,
\ 'lnum': cursor[1],
\ 'col': cursor[2]
\ })
endfor
call setqflist(choices)
copen
endfunction
CopenBookmarks will load the bookmarks in the quickfix window, which seems like a nice interface to me.
This solution is similar to Eric's -- it uses the .viminfo file, so if something goes wrong with it, you'll probably lose your marks. And if you save your marks in one vim instance, they won't be immediately available in another.
I don't know how comfortable your are with vimscript, so just in case -- to use this, you can put the code in a file under your plugin vimfiles directory, for example plugin/bookmarks.vim. Should be completely enough. Here's the entire code in a gist as well: https://gist.github.com/1371174
EDIT: Changed the interface for the solution a bit. Original version can be found in the gist history.
I have used this script (number marks). There might be better ones though. Wait for other answers!
This doesn't solve your problem as stated, but you may find it helps.
MRU.vim - Most Recently Used files plugin
Type :MRU and you get a nice searchable list of your most recently used files. Pressing enter on one brings you to it.
" When editing a file, always jump to the last known cursor position.
" And open enough folds to make the cursor is not folded
" Don't do it when the position is invalid or when inside an event handler
" (happens when dropping a file on gvim).
autocmd BufWinEnter *
\ if line("'\"") <= line("$") |
\ exe "normal! g`\"" | exe "normal! zv" |
\ endif

VIM: Execute Ruby script on each line as cursor moves and update a buffer to show in split window

I'm trying to solve a problem with VIM. Here is what I'm trying to achieve:
I have a file with several lines in it. As I move my cursor from line to line, I want to send the current line as an argument to a Ruby script. The result of this script should be redirected to a VIM buffer which will be shown in a split window above the original text.
so far, I have been able to write a function that sends one line to the script and the results show up in a buffer above. I am not sure how to get this function to run each time the cursor moves to a new line and make the results update the same buffer. Any pointers would be appreciated.
My code:
function! BB()
redir => a
let str = getline(".")
let str1 = "\"" . str . "\""
silent execute "!${HOME}/scripts/test.rb " . str1
redir END
new
put! = a
endfunction
command! -nargs=0 BB echo BB()
The first thing that comes to my mind is mapping keys movements. Something like:
map j j:call BB()<CR>
map k k:call BB()<CR>

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.

Vim autocommand trigger on opening "nothing"

I want vim to open up the :Explorer when no file is opened or created. Eg. when I call vim without any options.
calling vim newfile.txt should still behave the normal way though.
How would I go about doing this? I can't seem to find the correct autocmd for it.
If you want to do this for vim invocation only, the best way is to use argc():
autocmd VimEnter * :if argc() is 0 | Explore | endif
argc() function returns a number of filenames specified on command-line when vim was invoked unless something modified arguments list, more information at :h argc().
Found the answer myself:
"open to Explorer when no file is opened
function! TabIsEmpty()
" Remember which window we're in at the moment
let initial_win_num = winnr()
let win_count = 0
" Add the length of the file name on to count:
" this will be 0 if there is no file name
windo let win_count += len(expand('%'))
" Go back to the initial window
exe initial_win_num . "wincmd w"
" Check count
if win_count == 0
" Tab page is empty
return 1
else
return 0
endif
endfunction
" Test it like this:
" echo TabIsEmpty()
function! OpenExplorer()
if (TabIsEmpty())
:Explore
end
endfunction
The greatest part of this code was taken from this question.

Resources