Programatically execute command to close current buffer and switch to last state - vim

I'm editing a file :e foo.
Now I'd like to save it, close the buffer (so I can go back to the state before I opened foo), using a command.
I have this right now:
command! GC silent execute ":wq" | silent execute ":close"
But if I didn't have any buffer open before, I get this error:
E444: Cannot close last window
How can I close the window, such that if it's the last window, it still closes it, and returns me back to the empty screen that you get when you just run vim?

I think you're looking for the :update + :bdelete command combination. The first persists changes if there are any, and the latter removes the buffer. If there are other split windows, the current one is closed. Otherwise, if you have other arguments / hidden buffers, the next one is displayed in the single window. If there is no other window, an empty buffer (like :enew) is shown.

What you see when you start Vim without a file as argument, $ vim, is just an empty buffer. If its state is not altered in any way it is discarded when you do :e file.
You can see that with :ls: the only buffer available is file.
If you want an empty buffer (and I have no idea why you would want that) you'll need to create one explicitly with:
:enew
unless there's an option that I don't know about.
Anyway, I'd suggest you to do:
$ vim file
rather than:
$ vim
:e file

Do you want to do save all files, and exit vim ? Then just type ZZ.
Or you want to do save all files if updated, and close all windows ? Then
command! GC bufdo update | windo bw

Related

Quit vim, when a buffer has unsaved changes and is un-named?

I created a blank "scratch buffer" (i.e. not associated with a specific file) in vim, by using :vnew. Then I played around with some text, now I simply want to exit the editor - not keeping the contents of this "scratch buffer".
When I type the command:
:q!
Vim gives me:
[No Name][+]
E37: No write since last change (add ! to override)
E162: No write since last change for buffer "[No Name]"
Press ENTER or type command to continue
How can I quit vim from this state?
This happens when you have a modified hidden buffer. Use :qa! to exit anyway.
From :h :quit :
:q[uit]! Quit without writing, also when currently visible
buffers have changes. Does not exit when this is the
last window and there is a changed hidden buffer.
In this case, the first changed hidden buffer becomes
the current buffer.
Use ":qall!" to exit always.
In case someone wants to reproduce it:
Start vim and modify the unnamed buffer
Edit another file (you might need to :set hidden), ie :e README
Try to exit with :q!
At best you could call it a "transient" buffer (in memory but not associated with a specific file) but what you created with :vnew is not a "scratch" buffer.
In Vim, a "scratch" buffer is a normal buffer in which you set a bunch of local options. It can be done with a command like this:
:vnew | setlocal nobuflisted buftype=nofile bufhidden=wipe noswapfile

Gvim: Move tab to new window

The opposite question seems to be asked a lot: how to move a window into a new tab in an existing window. What I'm hoping is that a tab that I have open in gvim can be moved out into its own window or into another existing window.
Is this possible?
Thanks!
Same Vim instance
If that tab shows just a single window, you just have to note its buffer number (e.g. via :ls or :echo bufnr(''), or by including it in the statusline), and then close the tab via :close (:set hidden helps with modified buffers), then going to the target tab / window, and re-opening the buffer there via :buf N or :sbuf N.
If you need to support multiple windows in a tab page, you'd have to write a custom command / mapping that first remembers the buffers, and then applies the above steps for all of them.
Different Vim instances
Edit: The above is for movement within a single Vim instance. If you want to move a buffer to another GVIM instance, you first have to :bdelete it in the current Vim, to avoid swap file messages. Launching in new instances is easy:
:execute 'bdelete | !start gvim' shellescape(expand('%:p'), 1)
This passes the (full absolute) path of the current file to a fresh GVIM.
To move a file to an existing GVIM (you need to know its v:servername), you need to use the remote client-server communication (:help remote.txt), e.g. by sending a similar :drop command via remote_send(), like this:
:execute 'bdelete | call remote_send("GVIM1", ":drop " . ' . string(fnameescape(expand('%:p'))) . '. "\<CR>")'
Here is how you can "move" the current buffer to a second GVim instance:
:!gvim --remote %
:bw
Note that Vim must be built with the +clientserver option.
No, it is not possible.
You cannot move a vim tab into a window, no matter new or existing. Because a vim tab page is a collection of windows. You cannot move a collection of windows into one single window.

How do I close a single buffer (out of many) in Vim?

I open several files in Vim by, for example, running
vim a/*.php
which opens 23 files.
I then make my edit and run the following twice
:q
which closes all my buffers.
How can you close only one buffer in Vim?
A word of caution: “the w in bw does not stand for write but for wipeout!”
More from manuals:
:bd
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.
If you know what you’re doing, you can also use :bw
:bw
Like |:bdelete|, but really delete the
buffer.
If this isn't made obvious by the the previous answers:
:bd will close the current buffer. If you don't want to grab the buffer list.
Check your buffer id using
:buffers
you will see list of buffers there like
1 a.php
2 b.php
3 c.php
if you want to remove b.php from buffer
:2bw
if you want to remove/close all from buffers
:1,3bw
Rather than browse the ouput of the :ls command and delete (unload, wipe..) a buffer by specifying its number, I find that using file names is often more effective.
For instance, after I opened a couple of .txt file to refresh my memories of some fine point.. copy and paste a few lines of text to use as a template of sorts.. etc. I would type the following:
:bd txt <Tab>
Note that the matching string does not have to be at the start of the file name.
The above displays the list of file names that match 'txt' at the bottom of the screen and keeps the :bd command I initially typed untouched, ready to be completed.
Here's an example:
doc1.txt doc2.txt
:bd txt
I could backspace over the 'txt' bit and type in the file name I wish to delete, but where this becomes really convenient is that I don't have to: if I hit the Tab key a second time, Vim automatically completes my command with the first match:
:bd doc1.txt
If I want to get rid of this particular buffer I just need to hit Enter.
And if the buffer I want to delete happens to be the second (third.. etc.) match, I only need to keep hitting the Tab key to make my :bd command cycle through the list of matches.
Naturally, this method can also be used to switch to a given buffer via such commands as :b.. :sb.. etc.
This approach is particularly useful when the 'hidden' Vim option is set, because the buffer list can quickly become quite large, covering several screens, and making it difficult to spot the particular buffer I am looking for.
To make the most of this feature, it's probably best to read the following Vim help file and tweak the behavior of Tab command-line completion accordingly so that it best suits your workflow:
:help wildmode
The behavior I described above results from the following setting, which I chose for consistency's sake in order to emulate bash completion:
:set wildmode=list:longest,full
As opposed to using buffer numbers, the merit of this approach is that I usually remember at least part of a given file name letting me target the buffer directly rather than having to first look up its number via the :ls command.
Use:
:ls - to list buffers
:bd#n - to close buffer where #n is the buffer number (use ls to get it)
Examples:
to delete buffer 2:
:bd2
You can map next and previous to function keys too, making cycling through buffers a breeze
map <F2> :bprevious<CR>
map <F3> :bnext<CR>
from my vimrc
Close buffer without closing the window
If you want to close a buffer without destroying your window layout (current layout based on splits), you can use a Plugin like bbye. Based on this, you can just use
:Bdelete (instead of :bdelete)
:Bwipeout (instead of :bwipeout)
Or just create a mapping in your .vimrc for easier access like
:nnoremap <Leader>q :Bdelete<CR>
Advantage over vim's :bdelete and :bwipeout
From the plugin's documentation:
Close and remove the buffer.
Show another file in that window.
Show an empty file if you've got no other files open.
Do not leave useless [no file] buffers if you decide to edit another file in that window.
Work even if a file's open in multiple windows.
Work a-okay with various buffer explorers and tabbars.
:bdelete vs :bwipeout
From the plugin's documentation:
Vim has two commands for closing a buffer: :bdelete and :bwipeout. The former removes the file from the buffer list, clears its options, variables and mappings. However, it remains in the jumplist, so Ctrl-o takes you back and reopens the file. If that's not what you want, use :bwipeout or Bbye's equivalent :Bwipeout where you would've used :bdelete.
How about
vim -O a a
That way you can edit a single file on your left and navigate the whole dir on your right...
Just a thought, not the solution...
[EDIT: this was a stupid suggestion from a time I did not know Vim well enough. Please don't use tabs instead of buffers; tabs are Vim's "window layouts"]
Maybe switch to using tabs?
vim -p a/*.php opens the same files in tabs
gt and gT switch tabs back and forth
:q closes only the current tab
:qa closes everything and exits
:tabo closes everything but the current tab
Those using a buffer or tree navigation plugin, like Buffergator or NERDTree, will need to toggle these splits before destroying the current buffer - else you'll send your splits into wonkyville
I use:
"" Buffer Navigation
" Toggle left sidebar: NERDTree and BufferGator
fu! UiToggle()
let b = bufnr("%")
execute "NERDTreeToggle | BuffergatorToggle"
execute ( bufwinnr(b) . "wincmd w" )
execute ":set number!"
endf
map <silent> <Leader>w <esc>:call UiToggle()<cr>
Where "NERDTreeToggle" in that list is the same as typing :NERDTreeToggle. You can modify this function to integrate with your own configuration.

vi, vim buffers overrun

I'm losing all previous buffers when by mistake I'm trying to switch behind the last buffer [n:].
If for example I open couple of files in editor
:ls
1 # "/etc/moduli" line 1
2 %a "/etc/motd" line 1
:n
E163: There is only one file to edit
:p
E163: There is only one file to edit
now i can navigate between tabs just using :b [number]
Please advice how to fix this behavior. How can I prevent buffers from closing in this case?
I think you're confusing something there. A buffer is something like an open file. When you switch to the next file in the argument list using :n you close the current buffer and open the next one, so the changes must either be saved or discarded at this point.
Additionally the default behaviour of vim is to display an error message if you try to go beyond the last file in your argument list, so losing anything is not very easy in vim.
Maybe describing your actions (pressed keys) could help here, if this does not answer your question.
[edit]
Ok, now I know what the problem is: There is a difference between a buffer and the list of files to edit that you supply when starting vim. If you start vim with
vim a.txt b.txt
there are 2 files to edit. This does not mean, there are multiple buffers. You can navigate using :n and :p (meaning n(ext) file and p(revious) file). If you have the global flag :hidden set, this means that every buffer you close will become a hidden buffer. The file is still being edited, but it is not shown in any window. This value is possibly set upon startup of vim in your system. Try adding :se nohidden to your .vimrc and try the following:
:help buffer-hidden
[/edit]
:bn
will display the next file in your buffer (in your case "/etc/moduli")
:bp
will display the previous file in your buffer (also "/etc/moduli" because it does a permutation)
One thing that you'll notice is that the file you're editing is marked with
%a
whereas
#
means it's the last file you displayed.
Hope it helps you.
:n and :p doesn't switch between buffers :)
try :bufnext and :bufprev
maybe you'll like:
nmap <LEADER>k :bnext<CR>:redraw<CR>
nmap <LEADER>j :bprevious<CR>:redraw<CR>
nmap <LEADER>d :bd<CR>
nnoremap <LEADER>b :buffers<CR>:buffer<space>
Press ,j for the previous buffer, ,k for the next buffer, ,d to close the current buffer and ,b to list your buffers and select one with number keys.

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