Close Multiple Buffers Programatically in Vim - vim

I'm trying to write a function that allows me to toggle TPope's Vim Fugitive git-log viewer.
The plugin allows you to view the history of your project, by opening up git objects as buffers that begin with fugitive://
I'm trying to write a function in vimscript that will allow me to close all of these buffers at once, when they're open. The function currently looks like this, and is quite close to working:
function! ToggleGLog()
if buflisted(bufname('fugitive'))
:cclose
:bd fugitive*<C-a><cr>
else
Glog
endif
endfunction
command! ToggleGLog :silent :call ToggleGLog()
nnoremap <silent> <leader>gl :ToggleGLog<CR>
The problem that I'm encountering is that the <C-a><cr> portion of the function doesn't work. Normally, the <C-a> would expand the * selector to match all the buffers that start with "fugitive."
How can I write this so that the names of those buffers are automatically expanded and the :bd command will close them all?

How about the following?
execute "normal! :bdelete fugitive*\<C-a>\<CR>"
normal lets Vim run the command to its right as if you typed it, including keys like <C-a>. But as the latter is somewhat special, it needs to be interpreted; this is what execute is doing here. (See the end part of :help normal.)

Related

Vim key binding to call a function with input from user

There might be a simple solution for this. I couldn't find any solution to it (I might be searching with wrong context)
Here is my requirement.
I wrote the below key mapping in vimrc. It should print the line "Hello user_name." n times, where n and user_name are the user input once the key is pressed.
autocmd FileType ruby nnoremap <expr> <C-h> :call FuncPrnt(<-syntax to pass input from user->)
function! FuncPrnt(count, uname)
let c=a:count
let i=0
while i<c
call append(line("."), "Hello ".a:uname.".")
let i+=1
endwhile
endfunction
On Pressing the key user enters 3 and 'Ironman'. The output would be like
Hello Ironman.
Hello Ironman.
Hello Ironman.
Thanks in advance
A simpler approach is to just use a non-<expr> mapping to prepare the Ex command without executing it:
nnoremap <C-h> :call FuncPrnt(,"")<left><left><left><left>
If you associate that with a filetype (such as "ruby" in your case), make sure you create a local mapping using <buffer>. Otherwise the mapping will be global and will work on every buffer and not only those with Ruby source files.
If you use an autocmd in your vimrc, make sure you wrap it in an augroup to prevent getting duplicated commands if you reload your vimrc.
Alternatively, you can add filetype mappings for Ruby in a file ~/.vim/ftplugin/ruby.vim which gets automatically loaded by Vim whenever a file of type Ruby is loaded. (That way you don't need to use explicit autocmds, Vim will take care of those details on your behalf.)
Got the answer. Just in case someone else is searching for similar solution
autocmd FileType ruby nnoremap <expr> <C-h> input("", ":call FuncPrnt(,\"\")<left><left><left><left>")
will print the command and waits for the user to edit. Once the user edits and enters it is executed
Thinking outside of the box a little bit (questioning the premise), perhaps the best in this case is to define a user-defined command instead of a mapping.
You can define one here with:
command! -buffer -bar -count=1 -nargs=1 FuncPrnt
\ call FuncPrnt(<count>, <q-args>)
That way you can use it with:
:3FuncPrnt Ironman
If you omit the count, 1 will be used. (You can pick a different default as the argument to -count=N.)
You can use Tab completion for FuncPrnt, so perhaps :3Fu<Tab> or even :3F<Tab> might be enough to complete the command.
This might end up being quicker or more convenient to type than <C-H>3<right><right>, since it doesn't involve moving your hand to the arrow keys.

Save file in vim before search with FZF

I have this mapping:
nnoremap <silent> <leader><space> :Files<CR>
This works fine, but when I have a changed file already open, I get an error when I switch to a new file.
Is it possible to save the file before starting fzf?
I tried something like this, but this doesn't work if I don't have a file open. (start vi without file and start fzf)
nnoremap <silent> <leader><space> :w<CR>:Files<CR>
First, use :update instead of :write. This will only write if there are indeed unpersisted changes.
You can check for an empty buffer with empty(bufname('')), but as there are other corner cases, I would rather just silence the error:
nnoremap <silent> <leader><space> :execute 'silent! update'<Bar>Files<CR>
Alternative
Alternatively, you can look into the 'hidden' option, as #romainl mentioned. With this, Vim won't complain if a buffer that has unsaved changes is not shown in a window any longer, and only confront you on quitting Vim. Many power users have :set hidden.

Set cursor shape on suspending vim

I'm using iTerm2 and Vim 7.4 on top of OS X 10.9.
In my bash shell, my cursor is a blinking line. I've installed Vitality (https://github.com/sjl/vitality.vim/) in order to get the Vim cursor to be a block in normal mode and a line in insert mode. Then, in order to get my cursor to revert to a line on exiting vim, I've added the following autocmd to my .vimrc (sourced from this stack overflow question):
autocmd VimLeave * let &t_me="\<Esc>]50;CursorShape=1\x7"
This is all working great; the one problem is that when I suspend Vim via Ctrl-Z (which I do frequently), my cursor remains a block. Is there some way to detect that Vim is being suspended (maybe via an autocmd) and set the cursor to a line? Also, presumably I would then have to reset the cursor to a block on resuming Vim.
There's no :autocmd event for suspending, but you can solve this part by hooking into the <C-z> command:
:nnoremap <silent> <C-z> :let &t_me=...<CR><C-z>
Restoring the cursor on restore is more difficult. It looks like the Vitality plugin already uses autocmd events to change the shape, so one mode change (into / out of insert mode) would be required to correct things.
If that's not enough, you'd have to install a separate fire-once autocmd (e.g. on CursorMoved,CursorHold) in the above mapping. Or you could try sending the :let command via feedkeys(), in the hope that it would only be executed after Vim awakes (not tested that).
I use Ingo's suggestion along with what I found here:
Update Vim after it suspended?
... To toggle a different terminal setting (called "Bracketed Paste Mode") when
I suspend Vim. You can tweak this for any other escape sequence pairs you
need, as the general concept is not BPM specific. This trick solves the 'fg'
problem. Here it is:
" (Re)Set Bracketed Paste Mode
function SetBPM(mode)
execute "silent !echo -ne '\033[?2004" . a:mode . "'"
endfunction
" toggle BPM when suspending (hook ctrl-z)...
nnoremap <silent> <C-z> :call SetBPM("l")<CR>:suspend<bar>:call SetBPM("h")<CR>

Is it possible to configure behaviour of NERDTreeToggle to use NERDTreeFind when opening?

Is it possible to configure NERDTree so that :NERDTreeToggle acts like :NERDTreeFind if a buffer is not open (instead of the default :NERDTree) ?
Failing that, would it be possible to create a mapping/small script that could check the visibility of the NERDTree window and if open close it, if closed invoke NERDTreeFind ?
I looked at the NERDTree documentation to find if the visibility of the NERDTree window was open, but could not find it.
You can set let NERDTreeQuitOnOpen=1 to close the tree when you select a file, and create a mapping for find:
nmap <leader>p :NERDTreeFind<CR>
there is a function, which may help you to distinguish if the NERDTree is opened.
nerdtree#isTreeOpen()
you could test a little bit with :echom nerdtree#isTreeOpen() when you opened/closed the Nerdtree.
I'm now learning to use Vim too and had the same desire to make NERDTreeToggle to use NERDTreeFind when opening. After some digging/googling, I had a go at writing a simple Vim script below, and it seems to work for me! :]
function! ToggleNERDTreeFind()
if g:NERDTree.IsOpen()
execute ':NERDTreeClose'
else
execute ':NERDTreeFind'
endif
endfunction
And I just bound the above function to a shortcut key to use for both finding/closing NERDTree. Hope this helps.
nnoremap <leader>f :call ToggleNERDTreeFind()<CR>
small improvment of the function provided by thomaswhyyou which also works
if current buffer is empty:
function! ToggleNERDTreeFind()
if g:NERDTree.IsOpen()
execute ':NERDTreeClose'
else
if bufname('%') == ''
execute ':NERDTree'
else
execute ':NERDTreeFind'
endif
endif
endfunction

How to map keys in vim differently for different kinds of buffers

The problem i am facing is that i have mapped some keys and mouse events for seraching in vim while editing a file. But those mappings impact the functionality if the quickfix buffer.
I was wondering if it is possible to map keys depending on the buffer in which they are used.
EDIT - I am adding more info for this question
Let us consider a scenario. I want to map <C-F4> to close a buffer/window. Now this behavior could depend on a number of things.
If i am editing a buffer it should just close that buffer without changing the layout of the windows. I am using buffkil plugin for this.
It does not depend on extension of file but on the type of buffer. I saw in vim documentation that there are unlisted and listed buffer. So if it is listed buffer it should close using bufkill commands.
If it is not a listed buffer it should use <c-w>c command to close buffer and changing the window layout.
I am new at writing vim functions/scripts, can someone help me getting started on this
function KillBuffer()
if &buflisted
" bufkill command here
else
execute "normal! \<C-w>c"
endif
endfunction
noremap <C-F4> :call KillBuffer()<CR>
Put this in your .vimrc
Or, if you want to handle quickfix window as unlisted buffers (in my Vim it is listed):
function KillBuffer()
if &buflisted && !&filetype=="qf"
" bufkill command here
else
execute "normal! \<C-w>c"
endif
endfunction
noremap <C-F4> :call KillBuffer()<CR>
According to the manual, you could replace execute "normal! \<C-w>c" with simpler close! in the above scripts.
You can create filetype specific settings. First, in your vimrc file, make sure filetype plugins are enabled by adding
filet plugin on
Then make a filetype specific plugin. Under Unix create a file called ~/.vim/after/ftplugin/[file-type-name].vim and put your mapping in there. In Windows the directory is $HOME/vimfiles/after/ftplugin. The [file-type-name] is the type detected by Vim, sometimes the same as the filename extension, e.g c.vim, python.vim, etc. Vim can tell you what the type is after you open the file if you enter
:echo &ft
You can intercept certain types of files loading and assign buffer specific mappings.
au! BufRead *.ext call <SID>init_hotkeys()
function s:init_hotkeys()
nnoremap <buffer> <CR> :Action<CR>
endfunction
To map complex logic on the hotkey you can use write something like this in your vimrc, or even better - put the following to the closebuffer.vim file inside your vim plugin directory
function s:close_buffer()
if &buflisted
" your command here from the killbuf plugin
echo "Listed Buffer"
else
wincmd c
" or
" normal <c-w>c
endif
endfunction
nnoremap <C-F4> :call <SID>close_buffer()<CR>
I use this in my vimrc to insert an empty line above or below the current line using only return and shift-return (as opposed to o<Esc> or O<Esc>) without interfering with the open file behaviour you want in the quickfix list.
" Use enter to insert newlines in normal mode, but not in quickfix
function! s:insert_line(direction)
if &buftype == "quickfix"
execute "normal! \<Enter>"
else
if a:direction == 'below'
execute "normal! o\<Esc>"
else
execute "normal! O\<Esc>"
endif
endif
endfunction
nmap <Enter> :call <SID>insert_line('below')<CR>
nmap <S-Enter> :call <SID>insert_line('above')<CR>
Hopefully someone else will find this useful.

Resources