How do I close a buffer while keeping the window open? [duplicate] - vim

Vim's multilayered views (Windows, Buffers and Tabs) left me a little confused. Let's say I split the display (:sp) and then select a different buffer to display in each window. Now I want to close one of the buffers, yet I don't want the window to close (After the closing it can display the next buffer on the list or an empty buffer, it doesn't matter). How can I do this?

I messed with this a bit and finally came up with:
:bp | sp | bn | bd
Here's the copy/paste version for key mapping:
:bp<bar>sp<bar>bn<bar>bd<CR>
I've tested it a fair bit and it works consistently in various conditions. When used on the last buffer it will leave you with a new blank buffer.
Throw this in your .vimrc:
map <leader>q :bp<bar>sp<bar>bn<bar>bd<CR>
Restart Vim, or just :source ~/.vimrc for changes to take effect. Next time you want to close a buffer just type: \q (if \ is your leader key)

I searched for this today and came up with
:b#|bd#
which changes the current window to the previously open buffer and deletes/hides the buffer you just switched away from.
This requires at least two known buffers.
If another window but the current shows the same buffer this will still destroy splitting. You can change all windows to the previously open buffer with
:windo b#
I added more detail about the former command discussing a mapping for it (and some pitfalls) in an answer to a similar question.

There's a script on the Vim wiki to do this. I don't think there is a builtin that does what you want.
The latest version of vim-bufkill is on github.

nmap <leader>d :bprevious<CR>:bdelete #<CR>
Works as it should until one buffer is open in several windows. Good enough unless you want to use the bigger scripts out there.
Edit: this is what i use right now:
function! BufferDelete()
if &modified
echohl ErrorMsg
echomsg "No write since last change. Not closing buffer."
echohl NONE
else
let s:total_nr_buffers = len(filter(range(1, bufnr('$')), 'buflisted(v:val)'))
if s:total_nr_buffers == 1
bdelete
echo "Buffer deleted. Created new buffer."
else
bprevious
bdelete #
echo "Buffer deleted."
endif
endif
endfunction

I think this is what you're looking for
http://www.vim.org/htmldoc/windows.html#window-moving
Try this:
Look ar your buffer id using
:buffers
you will see list of buffers there like
1 a.cpp
2 b.py
3 c.php
if you want to remove b.py from buffer
:2bw
if you want to remove/close all from buffers
:1,3bw

For those who use NERDTree.
I fix this using this plugin https://github.com/jistr/vim-nerdtree-tabs and now I can close the only buff/file/tab without closing the window.
After having the plugin above installed put the following code on my .vimrc:
let g:nerdtree_tabs_autoclose=0
The description for the variable above is: Close current tab if there is only one window in it and it's NERDTree (default 1)
More info here: https://github.com/jistr/vim-nerdtree-tabs#configuration

A simple version I use personally is
:bp|bd#
It goes to the previous buffer and deletes the other buffer (which is actually the original where we jumped from).
This does what you would expect in 99% of cases without any complicated scripts.
As a keyboard shortcut I use the following
nnoremap <silent> <Leader>c :bp<BAR>bd#<CR>

I don't think there is a one shot way to do this, but you could do :enew or :ls to list your buffers and swap to a different one using :b [number].
Once you've got a different buffer in the window :bd # will delete the previous buffer in the window, and since the current buffer still exists the window won't be closed.

I used to use :
:bp<bar>sp<bar>bn<bar>bd<CR>
But I found certain occasions where it closed my window.
Recently I noticed that I always use this when I am working on a project and need to quickly open my .tmux.conf .zshrc before going back to work.
For this usage, I find better to :
switch back to the buffer I was previously working on with C-6
type :bd# to delete the previous buffer (I have mapped it like this : nnoremap <leader>d :bd#<CR>)
It allows me to control the buffer I'm going back to and feels more natural.

Here is a very readable vimscript function, which handles all cases well,
behave similar to built-in:bd (if only one window, just invoke it!),
issue a warning and do nothing if buffer modifed.
if no other buffer, create one, via :enew.
if alternate buffer exist and in buffer-list, switch to it, else go next, via:bn.
more reasonable behavior for multiple-window layout
not closing any window,
always stay on the original window.
for each window that displays current buffer, do as listed above, then delete old current buffer.
nnoremap <Leader>b :call DeleteCurBufferNotCloseWindow()<CR>
func! DeleteCurBufferNotCloseWindow() abort
if &modified
echohl ErrorMsg
echom "E89: no write since last change"
echohl None
elseif winnr('$') == 1
bd
else " multiple window
let oldbuf = bufnr('%')
let oldwin = winnr()
while 1 " all windows that display oldbuf will remain open
if buflisted(bufnr('#'))
b#
else
bn
let curbuf = bufnr('%')
if curbuf == oldbuf
enew " oldbuf is the only buffer, create one
endif
endif
let win = bufwinnr(oldbuf)
if win == -1
break
else " there are other window that display oldbuf
exec win 'wincmd w'
endif
endwhile
" delete oldbuf and restore window to oldwin
exec oldbuf 'bd'
exec oldwin 'wincmd w'
endif
endfunc

Simply do :new|bd# or Paste this into your vimrc
let mapleader = " "
" CLOSE current Buffer without closing window
nnoremap <silent><leader>d :new<BAR>bd#<CR>
" CLOSE current window
noremap <leader>x <c-w>c
Then hit (space + d) or (space + x)
EDIT: even better with
nnoremap <silent><leader>d :new<BAR>bd#<BAR>bp<CR>

Would
:enew
do what you want? it will edit a new, unnamed buffer in the current window leaving the existing file open in any other windows.

My favorite solution for this is the bufkill.vim plugin (GitHub). It provides alternate versions of the various :b-prefix commands that work the same as their counterparts, but leave the window open. They display whatever the last visible buffer contained, or an empty/new buffer if there was no prior buffer.
From the documentation:
When you want to unload/delete/wipe a buffer, use:
:bun/:bd/:bw to close the window as well (vim command), or
:BUN/:BD/:BW to leave the window(s) intact (this script).

To 'close' a view, use :hid[e]. Works if you have managed to split the viewport or opened multiple files. You can't hide the last buffer on display.
1 Further tip that helped me: use :e ./path/to/file.work to open a file in viewport without splitting the window.
P.S. At two days into vim I still have trouble finding the precise help commands. Hopefully this will help someone else keep working until they really get time to understand vim.

If you're like me and you came here trying to do the opposite, close the window without closing the buffer, you can do that via:
:close

I like this answer most, although I prefer
<CTRL-^>:bd#
because it is faster to type and I don't need a keymapping.
The command <CTRL-^> (same as on English keyboard) switches to the alternate file and :bd# deletes the other buffer.

use ":bd" as a command.

Related

Vim: Delete Buffer When Quitting Split Window

I have this very useful function in my .vimrc:
function! MyGitDiff()
!git cat-file blob HEAD:% > temp/compare.tmp
diffthis
belowright vertical new
edit temp/compare.tmp
diffthis
endfunction
What it does is basically opening the file I am currently working on from repository in a vertical split window, then compare with it. This is very handy, as I can easily compare changes to the original file.
However, there is a problem. After finishing the compare, I remove the split window by typing :q. This however doesn't remove the buffer from the buffer list and I can still see the compare.tmp file in the buffer list. This is annoying because whenever I make new compare, I get this message:
Warning: File "temp/compare.tmp" has changed since editing started.
Is there anyway to delete the file from buffers as well as closing the vertical split window?
Perhaps you need the bwipe command?
:bw[ipeout][!] N1 N2 ...
Like |:bdelete|, but really delete the buffer. Everything
related to the buffer is lost. All marks in this buffer
become invalid, option settings are lost, etc. Don't use this
unless you know what you are doing.
One option would be to define the following:
function! DelBuf(filename)
let bname = bufname(filename)
if l:bname != ""
let bidx = buffer_number(l:bname)
exec = "bw " . l:bidx
endif
endfunction
and add a call to DelBuf("comapre.tmp") at the beginning of your function.
In theory it should be possible to bind DelBuf to the `bufhidden event like this:
autocmd! bufhidden "compare.tmp" call DelTmp("compare.tmp")
... but for some reason it didn't work for me.
You need to use autocmd winleave bd (buffer delete). Be warned that if you have the buffer open in more than one window they will all be removed.
I usually define the following things for diff-buffers:
setlocal bt=nofile bh=wipe nobl noswf ro
nnoremap <buffer> q :bw<cr>
The first line is what will make the difference in your case (:h 'bh' -> no need for a single execution autcocommand), the second line is just a shortcut.
BTW: use r! git instead of producing a temporary file. This way, you won't have to clear that file either.

Completely exit location list (lcl) created by Syntastic as well the main buffer when using :q, :q! or :wq! in VIM

I'm using Syntastic plugin. I have some files with some errors (Warnings) that I can't change. When I have a file opened with error messages, and I quit the file(buffer) pressing :q, the error messages are still visible(another buffer), so I have to press :q twice to completely exit when editing a file.
So, how do I press :q just once with a file with a buffer containing my file and another buffer (location list) containing Syntastic errors? I've searched a little bit and the command to close the location list is :lcl.
When I exit a buffer with :q, if the location list for that buffer is active, I want to close it with the location list within, calling :lcl. I'm reading some autocmd BufLeave and BufWinLeave and trying to create a mapping for this, but I cant know the difference between the two. Can someone help me?
Remembering, :w, :q, :q!, :wq should all work as intended.
As lcl work even if there is no error window you can map q to lcl and q
cnoremap q<cr> \|lcl\|q<cr>
As suggested an abbreviation seems better
cabbrev q lcl\|q
(note the \ before |, without it does the abbreviation then quit )
I realize this question is old and that the answer was accepted sometime ago. I tried using the accepted answer but it does not seem to work any more.
I did however find a workaround from this question, should others run in to this.
Basically, use a script to check if there are any other remaining windows open and if the last remaining window is a location-list, quit.
:autocmd WinEnter * if &buftype ==# 'quickfix' && winnr('$') == 1 | quit | endif
I think this may not be ideal but works well enough in the meantime.

How can I execute a command when a buffer is closed in vim?

Is there something like a close-window-hook in vim/vimscript, so that I can call a function every time a window is closed?
I want to use it for the following scenario:
I use an extra scratch window to display information about the file, and when I close the file I want the scratch window to be closed automatically so that vim exits.
If you have any ideas how to achieve that without a hook that will be just as fine.
edit:
I know about :qa[ll], but I am lazy and only want to type :q or ZZ.
edit2.71828183:
I accepted the autocommand answer as it was closest to the original question, but found another solution in using a preview window instead of a split window. A preview window is automatically closed when the last "normal" window is closed..
autocommands are amazing! I'm pretty sure that in this case, BufLeave will do the job, but you might want BufWinLeave? Have a look at :help autocmd-events for a full list of events.
The other bit you'll care about is: you can have buffer-local autocommands! (:help autocmd-buflocal)
You can define one for the current buffer using au BufLeave <buffer> .... My best guess is that you could run this in whatever command creates the scratch window. You should be able to cache the scratch window's buffer number in a global variable when you open the scratch window, then your autocommand could just delete that buffer (:help :bdelete).
au BufLeave <buffer> bdelete g:scratch_buffer
call CreateScratchWindow()
function CreateScratchWindow() {
...
let g:scratch_buffer = bufnr("")
}
There's also a function winbufnr, for getting buffer numbers by window. You can use either one - just make sure that the scratch window/buffer is current when you use it! (The "" means current window/buffer).
Add a mapping.
:nnoremap :q :qa
then, if you only want to use :q one day, you can just
:qa<backspace>
and normally, you can just
:q<enter>
and get
:qa<enter>
for free.
Ok, not really a new question, but I found it looking for, what I now know, BufWinLeave. However, the scenario the author is describing is something I have in my vimrc with NerdTree, e.g. when the last buffer is closed, I want vim to close the NerdTree "buffer" and then quit.
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
Replace the NERDTree specific stuff with how the scratch buffer is identified.
You can use
:quitall
or
:qall
to close all windows at once.
add a ! if you want to ignore unsaved changes.
:qall!

How can I close a buffer without closing the window?

Vim's multilayered views (Windows, Buffers and Tabs) left me a little confused. Let's say I split the display (:sp) and then select a different buffer to display in each window. Now I want to close one of the buffers, yet I don't want the window to close (After the closing it can display the next buffer on the list or an empty buffer, it doesn't matter). How can I do this?
I messed with this a bit and finally came up with:
:bp | sp | bn | bd
Here's the copy/paste version for key mapping:
:bp<bar>sp<bar>bn<bar>bd<CR>
I've tested it a fair bit and it works consistently in various conditions. When used on the last buffer it will leave you with a new blank buffer.
Throw this in your .vimrc:
map <leader>q :bp<bar>sp<bar>bn<bar>bd<CR>
Restart Vim, or just :source ~/.vimrc for changes to take effect. Next time you want to close a buffer just type: \q (if \ is your leader key)
I searched for this today and came up with
:b#|bd#
which changes the current window to the previously open buffer and deletes/hides the buffer you just switched away from.
This requires at least two known buffers.
If another window but the current shows the same buffer this will still destroy splitting. You can change all windows to the previously open buffer with
:windo b#
I added more detail about the former command discussing a mapping for it (and some pitfalls) in an answer to a similar question.
There's a script on the Vim wiki to do this. I don't think there is a builtin that does what you want.
The latest version of vim-bufkill is on github.
nmap <leader>d :bprevious<CR>:bdelete #<CR>
Works as it should until one buffer is open in several windows. Good enough unless you want to use the bigger scripts out there.
Edit: this is what i use right now:
function! BufferDelete()
if &modified
echohl ErrorMsg
echomsg "No write since last change. Not closing buffer."
echohl NONE
else
let s:total_nr_buffers = len(filter(range(1, bufnr('$')), 'buflisted(v:val)'))
if s:total_nr_buffers == 1
bdelete
echo "Buffer deleted. Created new buffer."
else
bprevious
bdelete #
echo "Buffer deleted."
endif
endif
endfunction
I think this is what you're looking for
http://www.vim.org/htmldoc/windows.html#window-moving
Try this:
Look ar your buffer id using
:buffers
you will see list of buffers there like
1 a.cpp
2 b.py
3 c.php
if you want to remove b.py from buffer
:2bw
if you want to remove/close all from buffers
:1,3bw
For those who use NERDTree.
I fix this using this plugin https://github.com/jistr/vim-nerdtree-tabs and now I can close the only buff/file/tab without closing the window.
After having the plugin above installed put the following code on my .vimrc:
let g:nerdtree_tabs_autoclose=0
The description for the variable above is: Close current tab if there is only one window in it and it's NERDTree (default 1)
More info here: https://github.com/jistr/vim-nerdtree-tabs#configuration
A simple version I use personally is
:bp|bd#
It goes to the previous buffer and deletes the other buffer (which is actually the original where we jumped from).
This does what you would expect in 99% of cases without any complicated scripts.
As a keyboard shortcut I use the following
nnoremap <silent> <Leader>c :bp<BAR>bd#<CR>
I don't think there is a one shot way to do this, but you could do :enew or :ls to list your buffers and swap to a different one using :b [number].
Once you've got a different buffer in the window :bd # will delete the previous buffer in the window, and since the current buffer still exists the window won't be closed.
I used to use :
:bp<bar>sp<bar>bn<bar>bd<CR>
But I found certain occasions where it closed my window.
Recently I noticed that I always use this when I am working on a project and need to quickly open my .tmux.conf .zshrc before going back to work.
For this usage, I find better to :
switch back to the buffer I was previously working on with C-6
type :bd# to delete the previous buffer (I have mapped it like this : nnoremap <leader>d :bd#<CR>)
It allows me to control the buffer I'm going back to and feels more natural.
Here is a very readable vimscript function, which handles all cases well,
behave similar to built-in:bd (if only one window, just invoke it!),
issue a warning and do nothing if buffer modifed.
if no other buffer, create one, via :enew.
if alternate buffer exist and in buffer-list, switch to it, else go next, via:bn.
more reasonable behavior for multiple-window layout
not closing any window,
always stay on the original window.
for each window that displays current buffer, do as listed above, then delete old current buffer.
nnoremap <Leader>b :call DeleteCurBufferNotCloseWindow()<CR>
func! DeleteCurBufferNotCloseWindow() abort
if &modified
echohl ErrorMsg
echom "E89: no write since last change"
echohl None
elseif winnr('$') == 1
bd
else " multiple window
let oldbuf = bufnr('%')
let oldwin = winnr()
while 1 " all windows that display oldbuf will remain open
if buflisted(bufnr('#'))
b#
else
bn
let curbuf = bufnr('%')
if curbuf == oldbuf
enew " oldbuf is the only buffer, create one
endif
endif
let win = bufwinnr(oldbuf)
if win == -1
break
else " there are other window that display oldbuf
exec win 'wincmd w'
endif
endwhile
" delete oldbuf and restore window to oldwin
exec oldbuf 'bd'
exec oldwin 'wincmd w'
endif
endfunc
Simply do :new|bd# or Paste this into your vimrc
let mapleader = " "
" CLOSE current Buffer without closing window
nnoremap <silent><leader>d :new<BAR>bd#<CR>
" CLOSE current window
noremap <leader>x <c-w>c
Then hit (space + d) or (space + x)
EDIT: even better with
nnoremap <silent><leader>d :new<BAR>bd#<BAR>bp<CR>
Would
:enew
do what you want? it will edit a new, unnamed buffer in the current window leaving the existing file open in any other windows.
My favorite solution for this is the bufkill.vim plugin (GitHub). It provides alternate versions of the various :b-prefix commands that work the same as their counterparts, but leave the window open. They display whatever the last visible buffer contained, or an empty/new buffer if there was no prior buffer.
From the documentation:
When you want to unload/delete/wipe a buffer, use:
:bun/:bd/:bw to close the window as well (vim command), or
:BUN/:BD/:BW to leave the window(s) intact (this script).
To 'close' a view, use :hid[e]. Works if you have managed to split the viewport or opened multiple files. You can't hide the last buffer on display.
1 Further tip that helped me: use :e ./path/to/file.work to open a file in viewport without splitting the window.
P.S. At two days into vim I still have trouble finding the precise help commands. Hopefully this will help someone else keep working until they really get time to understand vim.
If you're like me and you came here trying to do the opposite, close the window without closing the buffer, you can do that via:
:close
I like this answer most, although I prefer
<CTRL-^>:bd#
because it is faster to type and I don't need a keymapping.
The command <CTRL-^> (same as on English keyboard) switches to the alternate file and :bd# deletes the other buffer.
use ":bd" as a command.

Close file without quitting VIM application?

I use the :e and :w commands to edit and to write a file. I am not sure if there is "close" command to close the current file without leaving Vim?
I know that the :q command can be used to close a file, but if it is the last file, Vim is closed as well; Actually on Mac OS MacVim does quit. Only the Vim window is closed and I could use Control-N to open a blank Vim window again. I would like Vim to remain open with a blank screen.
This deletes the buffer (which translates to close the file)
:bd
As already mentioned, you're looking for :bd, however this doesn't completely remove the buffer, it's still accessible:
:e foo
:e bar
:buffers
1 #h "foo" line 1
2 %a "bar" line 1
Press ENTER or type command to continue
:bd 2
:buffers
1 %a "foo" line 1
Press ENTER or type command to continue
:b 2
2 bar
You may instead want :bw which completely removes it.
:bw 2
:b 2
E86: Buffer 2 does not exist
Not knowing about :bw bugged me for quite a while.
If you have multiple split windows in your Vim window then :bd closes the split window of the current file, so I like to use something a little more advanced:
map fc <Esc>:call CleanClose(1)
map fq <Esc>:call CleanClose(0)
function! CleanClose(tosave)
if (a:tosave == 1)
w!
endif
let todelbufNr = bufnr("%")
let newbufNr = bufnr("#")
if ((newbufNr != -1) && (newbufNr != todelbufNr) && buflisted(newbufNr))
exe "b".newbufNr
else
bnext
endif
if (bufnr("%") == todelbufNr)
new
endif
exe "bd".todelbufNr
endfunction
:[N]bd[elete][!] *:bd* *:bdel* *:bdelete* *E516*
:bd[elete][!] [N]
Unload buffer [N] (default: current buffer) and delete it from
the buffer list. If the buffer was changed, this fails,
unless when [!] is specified, in which case changes are lost.
The file remains unaffected. Any windows for this buffer are
closed. If buffer [N] is the current buffer, another buffer
will be displayed instead. This is the most recent entry in
the jump list that points into a loaded buffer.
Actually, the buffer isn't completely deleted, it is removed
from the buffer list |unlisted-buffer| and option values,
variables and mappings/abbreviations for the buffer are
cleared.
If you've saved the last file already, then :enew is your friend (:enew! if you don't want to save the last file). Note that the original file will still be in your buffer list (the one accessible via :ls).
If you modify a file and want to close it without quitting Vim and without saving, you should type :bd!.
:bd can be mapped. I map it to F4, Shift-F4 if I need to force-close because of some change I no longer want.
The bufkill.vim plugin adds BD etc., to delete the buffer without closing any splits (as bd) would alone.
Insert the following in your .vimrc file and, with pressing F4, it will close the current file.
:map <F4> :bd<CR>
Look at the Butane plugin to keep the window layout when closing a buffer.
For me close-buffers is pretty useful plugin:
:Bdelete this to close that you can remap.
I have the same issue so I made the plugin.
This plugin replace :q and other commands and then prevent the window closed.
if you still have issue, please try to use following plugin.
https://github.com/taka-vagyok/prevent-win-closed.vim

Resources