Bug? BufRead sets local options in wrong tab on reload

16 views
Skip to first unread message

Ben Fritz

unread,
May 11, 2009, 2:59:09 PM5/11/09
to vim_dev
I posted this originally on vim_use but only got one response, from
someone who thinks it's a bug. The original thread is here:

http://groups.google.com/group/vim_use/browse_thread/thread/d93a0878b9a5bb91/8619edd9992fdd20

Basically, I have two tabs open, each with a single buffer loaded, and
a BufRead autocmd that will fire when the file in one of the tabs is
(re)loaded. This BufRead autocmd sets the "wrap" option locally. When
the autocmd fires, the buffer in the currently active tab gets the
option, regardless of whether this is the buffer being reloaded.

Test case for reproduction is as follows:
vim -u NONE -N -i NONE

:autocmd BufRead *.txt setlocal wrap
:view test.txt
:tabe test.c
:setlocal nowrap

Now modify test.txt outside of Vim and give focus back to Vim to
trigger a reload of test.txt.

Vim is still in the test.c tab. When the BufRead autocmd fires, 'wrap'
is set for test.c instead of test.txt.

Is this a bug? If not, please explain :-)

I'm running gvim 7.2.160 on MS Windows (the "Cream" build).

Andy Wokula

unread,
May 12, 2009, 7:55:45 AM5/12/09
to vim...@googlegroups.com
Ben Fritz schrieb:

The 'wrap' option is local to the window. (Obviously) Vim does not
switch to the buffer's window when reloading a file -> the option can be
set in the wrong window.

I found that :setf {ft-name} does nothing when auto-reloading a file
(intentionally I guess), so

:au FileType text setl wrap

works better for me. And it somehow looks better anyway ...

Of course you need to define the filetype "text".


In other words ...

Setting a window-local option from a buffer-event like BufRead does not
look right ... and Vim indeed has some separation:

BufRead event -> FileType event

BufRead: buffer must match
FileType: buffer + buffer's window must be current, else FileType event
is not fired


--
Andy

Henrik Öhman

unread,
May 12, 2009, 9:04:58 AM5/12/09
to vim_dev
On May 12, 1:55 pm, Andy Wokula <anw...@yahoo.de> wrote:
> Ben Fritz schrieb:
>
> > I posted this originally on vim_use but only got one response, from
> > someone who thinks it's a bug. The original thread is here:
>
> >http://groups.google.com/group/vim_use/browse_thread/thread/d93a0878b...
>
> > Basically, I have two tabs open, each with a single buffer loaded, and
> > a BufRead autocmd that will fire when the file in one of the tabs is
> > (re)loaded. This BufRead autocmd sets the "wrap" option locally. When
> > the autocmd fires, the buffer in the currently active tab gets the
> > option, regardless of whether this is the buffer being reloaded.

[snip]

> The 'wrap' option is local to the window.  (Obviously) Vim does not
> switch to the buffer's window when reloading a file -> the option can be
> set in the wrong window.

I also had some battles with window local options, and 'wrap' in
particular, in the past. The way window local options are both 'window
local' and 'buffer local' can be mighty confusing. For instance, do

vim -u NONE -N file1.txt file2.txt
:bn
:setl nowrap

Now :setl wrap? returns 'wrap' for file1.txt and 'nowrap' for
file2.txt (in the same window). However, doing

:b1
:for i in [1,2] | echo bufname(i) . ": &l:wrap = " . getbufvar(i,
"&l:wrap") | endfor
:b2
:for i in [1,2] | echo bufname(i) . ": &l:wrap = " . getbufvar(i,
"&l:wrap") | endfor

prints

file1.txt: &l:wrap = 0
file2.txt: &l:wrap = 0

file1.txt: &l:wrap = 1
file2.txt: &l:wrap = 1

Thus, getbufvar() actually only returns the window local state of an
option which is actually dependent on both window local and buffer
local state. I'm sure there's a good(?) explanation for this, but I
haven't found it.

Eventually I was convinced that this is the way that Vim works, and
just gave up on trying to set 'wrap' automatically. I would argue that
some window local options, such as 'wrap' and 'diff', should be local
to buffer instead, but I'm sure there are plenty of valid arguments
against this as well.

Regards,
Henrik.

Andy Wokula

unread,
May 12, 2009, 10:46:11 AM5/12/09
to vim...@googlegroups.com
Henrik Öhman schrieb:

Right: When a buffer is no longer displayed in any window, the old
window-local options are remembered together with other buffer data
and restored when the buffer is displayed again.

But these "hidden" window-local options are not accessible ... they are
only used for restoring.

The gory details are here:
:h local-options

Not sure if this is something for the todo list, i.e.
If a buffer is not shown in any window, window-local options saved together
with the buffer (for restoring) should be accessible with getbufvar().

--
Andy

Henrik Öhman

unread,
May 12, 2009, 11:27:41 AM5/12/09
to vim_dev


On May 12, 4:46 pm, Andy Wokula <anw...@yahoo.de> wrote:
> Right: When a buffer is no longer displayed in any window, the old
> window-local options are remembered together with other buffer data
> and restored when the buffer is displayed again.
>
> But these "hidden" window-local options are not accessible ... they are
> only used for restoring.
>
> The gory details are here:
>     :h local-options
>
> Not sure if this is something for the todo list, i.e.
> If a buffer is not shown in any window, window-local options saved together
> with the buffer (for restoring) should be accessible with getbufvar().

I think that we can agree on that getbufvar() returning the window
local option value for the buffer currently displayed in the active
window, regardless of the buffer identifier passed to getbufvar(), is
wrong. The behaviour you're suggesting would indeed be preferable, but
I'm not sure that there's an important enough use case for it.

I do have one use case, though: I quite often use two windows to diff
different pairs of files. If I switch to another pair of files,
without turning off 'diff', Vim will eventually become quite confused
as to which files I actually want to diff. In this case, I'd like to
reset the 'diff' option for all buffers, regardless of for which window
(s) this option is remembered. The best method I've found to do this
is ':only | bufdo setl nodiff noscb fdm=syntax | vsplit', and I think
it would be nice to be able to use setbufvar() instead.

Now, before anyone yells :diffoff!, don't. It does silly things, such
as turning on 'wrap', setting 'fdm' to manual. It also doesn't apply
to all buffers.

Regards,
Henrik.

Ben Fritz

unread,
May 12, 2009, 12:40:43 PM5/12/09
to vim_dev


On May 12, 6:55 am, Andy Wokula <anw...@yahoo.de> wrote:

>
> I found that :setf {ft-name} does nothing when auto-reloading a file
> (intentionally I guess), so
>
> :au FileType text setl wrap
>
> works better for me. And it somehow looks better anyway ...
>
> Of course you need to define the filetype "text".
>
> In other words ...
>
> Setting a window-local option from a buffer-event like BufRead does not
> look right ... and Vim indeed has some separation:
>
> BufRead event -> FileType event
>
> BufRead: buffer must match
> FileType: buffer + buffer's window must be current, else FileType event
> is not fired
>

Your method does not seem to work for me. My simple test case may be
too simple. From the vim_use email:

> My actual situation is more complicated. The :setlocal wrap is not in
> an autocmd, but rather in $HOME/vimfiles/ftplugin/txt.vim, detected by
> file extension in $HOME/vimfiles/ftdetect/txt.vim with the following
> command:
>
> au BufNewFile,BufRead *.t{e,}xt,*.log,*.csv,*.err set filetype=txt

This is the case in which I originally observed the behavior.

When I remove the setlocal wrap from the ftplugin file, and add an
FileType autocmd to do the same, I get the same results.

It was always my understanding that the ftplugin files only got
sourced during application of a filetype, which also fires off the
FileType event. Am I missing something? Or perhaps I'm setting the
filetype in a strange manner?

I think I can use a combination of <afile> and setbufvar() in an
autocmd, if the ftplugin route doesn't work.

Ben Fritz

unread,
May 12, 2009, 12:55:35 PM5/12/09
to vim_dev


On May 12, 11:40 am, Ben Fritz <fritzophre...@gmail.com> wrote:
> When I remove the setlocal wrap from the ftplugin file, and add an
> FileType autocmd to do the same, I get the same results.
>

I worded that a bit awkwardly. What I meant was, I removed the
"setlocal wrap" from the ftplugin file, reloaded Vim, and created a
FileType autocmd from the command line (I did NOT add the FileType
autocmd to the ftplugin file).

Ben Fritz

unread,
May 12, 2009, 2:21:42 PM5/12/09
to vim_dev
Well...I finally found some :help related to this. From :help ftplugin
(then scroll down or search for the "OPTIONS" section):

> To make sure the filetype plugin only affects the current buffer use the
>
> :setlocal
>
> command to set options. And only set options which are local to a buffer (see
> the help for the option to check that). When using |:setlocal| for global
> options or options local to a window, the value will change for many buffers,
> and that is not what a filetype plugin should do.

However, I am still stumped about a good way to accomplish setting
window-local options based on filetype. I tried this, in my .vimrc:

autocmd FileType txt call setbufvar(expand("<afile>"), "&wrap", 1)
autocmd FileType txt call setbufvar(expand("<afile>"),
"&linebreak", 1)

The wrong window STILL gets its option set, even though I explicitly
specify the buffer to apply it to.

Andy Wokula

unread,
May 13, 2009, 4:07:00 AM5/13/09
to vim...@googlegroups.com
Ben Fritz schrieb:

> On May 12, 6:55 am, Andy Wokula <anw...@yahoo.de> wrote:
>
>> I found that :setf {ft-name} does nothing when auto-reloading a file
>> (intentionally I guess), so
>>
>> :au FileType text setl wrap
>>
>> works better for me. And it somehow looks better anyway ...
>>
>> Of course you need to define the filetype "text".
>>
>> In other words ...
>>
>> Setting a window-local option from a buffer-event like BufRead does not
>> look right ... and Vim indeed has some separation:
>>
>> BufRead event -> FileType event

>> BufRead: buffer must match
>> FileType: buffer + buffer's window must be current, else FileType event
>> is not fired

Ok. It only works this way by accident:

I used :setf text like in the filetype.vim file(s), instead of
:setl ft=text, and :setf is short for

if !did_filetype()
setlocal filetype={filetype}
endif

did_filetype() "returns non-zero when autocommands are being executed
and the FileType event has been triggered at least once." (since
creation of the buffer or so ...).

> Your method does not seem to work for me. My simple test case may be
> too simple. From the vim_use email:
>
>> My actual situation is more complicated. The :setlocal wrap is not in
>> an autocmd, but rather in $HOME/vimfiles/ftplugin/txt.vim, detected by
>> file extension in $HOME/vimfiles/ftdetect/txt.vim with the following
>> command:
>>
>> au BufNewFile,BufRead *.t{e,}xt,*.log,*.csv,*.err set filetype=txt

Use :setf, see above.

> This is the case in which I originally observed the behavior.
>
> When I remove the setlocal wrap from the ftplugin file, and add an
> FileType autocmd to do the same, I get the same results.

no surprise: the trigger is the same.

> It was always my understanding that the ftplugin files only got
> sourced during application of a filetype, which also fires off the
> FileType event. Am I missing something? Or perhaps I'm setting the
> filetype in a strange manner?

--
Andy

Reply all
Reply to author
Forward
0 new messages