Frage

How do I create a new buffer as a clone of another buffer? In other words, the contents should be the same, but these should be 2 distinct buffers in the end. I'm more interested in programmatic way of doing this, rather than from the point of view of mappings, as this is needed for the future plugin.

Recommendations like yanking one buffer, then giving focus to another one and pasting wouldn't work here since it would mean that we've overwritten user's previous yank and therefore spoiled user's experience after the invocation of our plugin method. I'm looking for some way to do it as sneaky as possible.

Furthermore, as a bonus, this new buffer should be created hidden because it will be used just to store some processed data quickly and then die immediately. Preferably, this should be done without any splits as they will introduce annoying blinking (because of Vim redrawing the screen) even if closed as soon as possible (for example, :new/:close combo). We also cannot assume that the buffer which we want to clone has a name.

Thank you.

Conclusion


Some testing revealed that transferring data with

:put=getbufline(...)

is the fastest method, and the most secure one since it does not interfere with user experience in any way.

Although, nobody answered on this, I've managed to find a function which will create a new hidden buffer without any splits, i.e. it will be created silently on the background with no window. To learn more see :h bufnr(). Example:

let buffer_number = bufnr('My New Hidden Buffer', 1)

Furthermore, this call will implicitly do the following:

let &l:buflisted = 0

on this newly created buffer, so it will be also hidden from :ls, which is exactly what we need to satisfy above requirements.

As a result, there will be no blinking or any visual irritation for the user like from :new/:close combo... a truly hidden buffer for some dirty work.

War es hilfreich?

Lösung

There's a function for this called getbufline(). Look up :h getbufline().

Here it is in action, incorporated into this clone command:

:new | put =getbufline('#',1,'$') | 1d_

This clones the current buffer into a new split.

Notes:

  • The vertical <Bar> chains Ex commands, in this case three of them;
  • :new creates a new buffer in a split window and moves the focus there;
  • :put = evaluates the expression passed to it and inserts items from a list as lines;
  • getbufline() is called to read lines from start 1 to finish '$' from the "alternate file" '#';
  • :1d_ gets rid of the empty line 1 produced as a side effect by :put.

For your convenience, here is the command again, packaged as the user command :Clone.

:command! Clone new | put =getbufline('#',1,'$') | 1d_

Andere Tipps

You can use let var=getline(1,'$') to get all lines in a buffer and put them into a variable. Then you can either use the data directly in a list, or you can use the append() or setline() functions to write that text in another buffer. If you want the data in a file to process externally, you can use the writefile() function.

Or, you can write to a file using :w newfilename and if the current buffer already has a file name associated, this will just create a new file with the current buffer content without changing the associated file at all. You can then open that file or use the readfile() function to get the text into Vim. If your processing occurs outside of Vim, this may be the better option because it doesn't involve keeping a lot of data in a list or opening a new buffer.

I assume, your buffer already has a name? Then here is another approach:

:sp|f foobar|exe "norm! \<C-^>"

:sp splits the buffer

:f foobar set's the buffer name for both split windows to foobar (and sets the old buffername to the alternate file)

exe "norm! \<C-^>" switches in the current window to the previous buffer

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top