:split! on a modified buffer abandons changes

3 views
Skip to first unread message

Ben Fritz

unread,
Jun 27, 2008, 4:09:12 PM6/27/08
to vim_dev
Consider:

Assume you have an existing file, file.a

gvim -N -u NONE

:e file.a
(make some changes to the buffer, but do not save)
:new
:split file.a

This will correctly re-use the (modifed) buffer for file.a.

Exit Vim. Restart in the same way:

gvim -N -u NONE

:e file.a
(make some changes to the buffer)
:split file.a
(this causes E37 as discussed in another thread)
:split! file.a
(this abandons the changes to file.a, reloading the file instead of re-
using the buffer)

I think this is incorrect behavior (why should the behavior of :split
file depend on the buffer it is called from?) but at the very least
the help for :split_f should say that it reloads the buffer. Except,
it only reloads the buffer when called from the same buffer you are
using as an argument. If called from any other buffer, it re-uses an
existing buffer.

Ben Fritz

unread,
Jun 27, 2008, 8:22:58 PM6/27/08
to vim_dev
I finally understand all the behavior of :split that has been
troubling me!

First of all, :split with no arguments does no loading of buffers, as
has been said. Hence, no BufWinEnter autocmd. My confusion was in
thinking of :split {file} as the same command. These are two very
different commands. In fact, :split {file} is apparently a synonym
with :new {file}. Not only that, but the help for :new (with no
arguments) says the following:

Autocommands are executed in this order:
1. WinLeave for the current window
2. WinEnter for the new window
3. BufLeave for the current buffer
4. BufEnter for the new buffer
This behaves like a ":split" first, and then a ":e" command.

Armed with this knowledge, I can explain all the behavior that
troubled me with :split {file}:

1. WinEnter contains the old buffer name in <amatch>, <afile>, and %
2. E37 when doing :split %

First, :split is done. This will create a new window, with the current
buffer, without loading any buffers. At this point the WinLeave and
WinEnter autocmds fire. Hence, <afile>, <amatch>, and the values of %
and # are unchanged. Problem 1 explained. Then, an :e is done. This
will, if the file is different, behave just like a normal :e command,
and use whatever buffer is currently loaded for that file. If the file
is the same, it still acts like an :e command, which will indeed
reload the buffer from disk. Problem 2 explained.

Knowing that :split {file} is basically a synonym for :split | edit
{file}, the behavior I have been experiencing is shown to be correct
after all, if a little confusing. To clarify things, I think the help
files should be updated in a few locations:


CTRL-W s *CTRL-W_s*
CTRL-W S *CTRL-W_S*
CTRL-W CTRL-S *CTRL-W_CTRL-S*
:[N]sp[lit] [++opt] [+cmd] *:sp* *:split*
Split current window in two. The result is two viewports on
the same file. Make new window N high (default is to use half
the height of the current window). Reduces the current window
height to create room (and others, if the 'equalalways' option
is set, 'eadirection' isn't "hor", and one of them is higher
than the current or the new window). This does not load a
buffer or read a file, so autocmd events like
|BufWinEnter|, |BufEnter|, etc. will not be triggered. But,
see |:split_f|.
Note: CTRL-S does not work on all terminals and might block
further input, use CTRL-Q to get going again.
Also see |++opt| and |+cmd|.


----------------------------------------------------------------------------

:[N]new [++opt] [+cmd] {file}
:[N]sp[lit] [++opt] [+cmd] {file} *:split_f*
Create a new window and start editing file {file} in it.
If [+cmd] is given, execute the command when the file has been
loaded |+cmd|.
Also see |++opt|.
Make new window N high (default is to use half the existing
height). Reduces the current window height to create room
(and others, if the 'equalalways' option is set).
Just like |:new|, this works exactly like :split|edit {file},
which can cause some behavior that might be unexpected, for
example:
- |WinEnter| autocmds will contain the buffer for the current
window in |<amatch>|, |<afile>|, and |:%|. I.e. they will not
contain {file}.
- Doing :split % will _not_ act like |:split| with no
arguments. It will attempt to reload the buffer after the
:split, which will cause |E37| if the buffer is modified.

----------------------------------------------------------------------------

*BufWinEnter*
BufWinEnter After a buffer is loaded into a window. This
can be when the buffer is first loaded (after
processing the modelines), when a hidden
buffer is displayed in a window (and is no
longer hidden), or a buffer already visible in
a window is also displayed in another window
(but note that |:split| with no arguments does
not load a buffer).
Reply all
Reply to author
Forward
0 new messages