How can a buffer be duplicated in Vim? - vim

I'm looking for a way to make a new buffer which is a copy of the current buffer.
I could then do something like the following to duplicate the current tab to a new tab in gVim for example:
:let b = bufnr("%") | tabnew | execute 'buffer' b | *duplicate*
However, this question isn't specific to tabs or gVim; I may want to duplicate the buffer after a split command or a vert diffsplit command. (Actually, vert diffsplit was the first instance that I realised I wanted to duplicate buffers.)
Ideally I also want to retain as much of the original buffer and window state as possible, including cursor position, with the exception that the original buffer read-only state is disregarded and the new buffer is always writeable.
Currently when I encounter this task, I type ggyG, open or move to the new buffer, then type Vp, but not only do I loose my cursor position for the new window, the copy command I use necessitates loosing the position in the original window as well. The process can surely be streamlined into a single command.

The following sequence of commands should provide a good starting point…
in the original buffer:
:%y
:let my_view = winsaveview()
:let my_ft = &filetype
:new
in the new buffer:
:execute "setf " . my_ft
:0put
:call winrestview(my_view)
Note that the "state" you want to duplicate is not buffer-specific but window-specific.

My clone plugin provides a :CloneAs {file} command for this. It basically creates a new buffer and copies over the original buffer, cursor position, and crucial options.

Related

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

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.

Command T to open file in previously opened buffer

I'm using Janus MacVim by Carlhuda, and I wonder if there's a way to tweak Command-T to open a file (buffer) only once, instead of into multiple splits of the same buffer.
Eg: Assumming your directory/project has two files: A.txt and B.txt.
1) Cmd T, then select A.txt.
2) Work on A.txt, then Cmd T, split B.txt with Ctrl V.
3) Work on B.txt, then need to switch back to A: Cmd T, A.txt. Currently Command T would either open A buffer to current split, or create a new split of A. What I want is that the previously opened A buffer would be active again (the cursor would jump back to A) instead of a new split A got created.
So essentially if a buffer has already been opened, resume to that split buffer. Is there a tweak or shortcuts for this?
You probably want :drop or :tab drop instead of the default :tabe for opening files in the Command-T search buffer. This is configurable in your .gvimrc file:
function! CommandTAcceptSelectionTab()
ruby $command_t.accept_selection :command => 'tab drop'
endfunction
This one bothered the heck out of me, too!
There is a 'switchbuf' option but that works only for :sbuffer and few more commands but not for :split, :new and others.
As far as I know it needs some vimscript woodoo, which I used some time ago but do not use anymore and just use :sb with completion.

vim: vnew, but accepting a buffer instead of a filename?

Currently, if I want to create a new window then load a buffer, I use :vnew :buf foo.py. Is there one command which will do both?
Yes, there is a command for that:
:[N]sb[uffer] [N] :sb :sbuffer
Split window and edit buffer [N] from the buffer list. If [N]
is not given, the current buffer is edited. Respects the
"useopen" setting of 'switchbuf' when splitting. This will
also edit a buffer that is not in the buffer list, without
setting the 'buflisted' flag.
You may find these ones useful also:
:[N]sbn[ext] [N] :sbn :sbnext
Split window and go to [N]th next buffer in buffer list.
Wraps around the end of the buffer list. Uses 'switchbuf'
:[N]sbN[ext] [N] :sbN :sbNext :sbp :sbprevious
:[N]sbp[revious] [N]
Split window and go to [N]th previous buffer in buffer list.
Wraps around the start of the buffer list.
Uses 'switchbuf'.
The problem with both commands is that they will split horizontally. You can precede them with :vert[ical], but that breaks your one command paradigm :-)
Anyway, :vert sb foo.py is not that much of typing, and if you really use it often, you might want to consider creating a map for it. Maybe something like:
cnoremap ,sb vert sb
Just tell :vnew the path to the file:
:vnew foo.py
Edit:
As sidyll said, there is no built in command that splits the window vertically to edit a buffer, then I have created a new ex commands which does what you want:
command! -nargs=1 -complete=buffer -bang Vbuffer vnew | buf<bang> <args>
The ! after command will replace an old :Vbuffer if it exists (you can remove that since I have added it for testing), -nargs=1 means that the new command accepts 1 argument which is passed to the :buf command with <args>, -complete=buffer will suggest buffer names as you type tab for the argument name and -bang indicates that the new command accepts the ! option which is also passed to the :buf command with <bang>.
Just add that line to your ~/.vimrc and re-:source it. ;-)

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.

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.

Resources