4


I wanna do the following:

autocmd BufAdd * let b:foo = 1

But as the documentation describe, at this point the buffer is still the old one and can be only accessed by the <abuf>, which is inf act the new buffers number.

NOTE: When this autocommand is executed, the current buffer "%" may be different from the buffer being created "< afile>".

Tests show that for my case it is never the new buffer and the variable is always defined for the previous buffer. So I try to find out how I can use the <afile> or <abuf> to set a variable to the buffer scope.


Edit:
Maybe the problem is not that clear from the minimal example above. There is an additional condition to set this variable. So not each buffer that will be entered get this variable (and so I was able to differentiate between them).


Edit 2: Cause @DoktorOSwaldo want some more context.
I often use the preview window to display tags and more. Unfortunately all the displayed buffers are added to the buffer list and waste memory usage (theoretically). So the simple idea was to define an autocommand, that affects a new opened buffer in the preview window. It must be new, cause already open buffers are expected as used by the user himself. These buffers get the local option to be not listen (setlocal nobuflisted) and should be wiped out, if the buffer in the preview window switches.
For the workflow case, that a buffer that is not open yet opens in the preview window and cause some circumstances the user want now to edit this buffer and open it in a different window. If this happen, I must set the buffer to be listed again and don't wiped out if not visible anymore. Cause to simply check if the buffer is listed or not isn't enough, cause then this will also be triggered by many special buffers like a file explorer or tag viewer... Therfore the simple solution should be to set a variable local to the buffer loaded into the preview window. Afterwards if this buffer get loaded outside this window I can identify it by this local variable.
The idea on some lines of code:

augroup PreviewWindow
   autocmd!
   autocmd BufAdd * if &previewwindow | setlocal nobuflisted |
           \ setlocal bufhidden = 'wipe' | let b:preview = v:true | endif

   autocmd BufEnter * if ! &previewwindow && exists('b:preview') &&
           \ b:preview | setlocal buflisted | setlocal bufhidden = '' |
           \ let b:preview = v:false | endif
augroup END



Final Solution:
This is my final implementation (that seems to work right now), using the concatenation of two events by using a flag.

augroup PreviewWindow
  autocmd!

  " Global flag for event composition, if a new buffer has been added into the preview window.
  let g:new_preview = 0

  " -> a buffer is shown in the preview window, that does not exits so far
  " In this case the the buffer is not already loaded and setting local variables does not work.
  " Set a global flag that mark this event to handle it later on when the buffer is loaded.
  autocmd BufAdd * nested if &previewwindow |
        \ let g:new_preview = v:true |
        \ endif

  " -> event that should follow after a (new) buffer has entered to the preview window
  " Check if the global flag has been set, that this is a new preview buffer.
  " The buffer is now available and local settings and variables can be defined.
  " Make sure the buffer gets cleared after it loose its window.
  " Set a buffer variable to mark it for further events.
  autocmd BufWinEnter * nested if &previewwindow && g:new_preview |
    \ let g:new_preview = v:false |
    \ setlocal nobuflisted |
    \ setlocal bufhidden=wipe |
    \ let b:previewonly = v:true |
    \ endif

  " -> the buffer in the preview window will be opened anywhere else
  " In case a buffer is entered, that has the buffer variable to be a 'previewony ' buffer,
  " it will be remove from there, added to the buffer list again and will not
  " be deleted when not displayed anymore.
  autocmd BufEnter * nested 
     \ try |
     \   if b:previewonly |
     \     unlet b:previewonly |
     \     setlocal buflisted |
     \     setlocal bufhidden= |
     \   endif |
     \ catch |
     \ endtry

augroup END


More Background
Cause some people are sill confused about why I want to implement this behavior, described in Edit 2, I like to explain it more exhaustive. Maybe it turns out I'm wrong or its simply a rly special case. So lets get started:
Assume ur working on three files
File A:

include <File B> as B
include <File C> as C

function main() {
  call B.foo()
  call B.bar()
}

File B:

function foo() {
  return "foo"
}

File C:

function bar() {
  return "bar"
}

So assume further we have some tool that generates us a tag for each function in the project (e.g. gutentags).
No imagine the following window structure, what simply makes it easier to talk about it.
+---------------------------------------------------------------+
|                                                                                 |
|                                 Preview                                   |
+------------------------------+-------------------------------+
|                                        |                                        |
|                File A               |                File B               |
|                                        |                                        |
+------------------------------+-------------------------------+

1. Case
Suppose working in the left window with File A. Move the cursor on the foo function call and open the word under cursor tag in the preview window. By this File B is shown in preview window, but also still in the right window. For this case I don't want to set any properties to the buffer in the preview window, cause it would affect a buffer I activly working on. Therefore my autocommand applies not new buffers which are opened into the preview window.

2. Case
Go ahead and do the same for the bar function. So File C is opened in a new buffer which gets displayed in the preview window. Now I want to apply my properties on this buffer. Cause the buffer for File C should not be in the list, so switching buffers with bn or bp does not jump to this buffer. Furthermore I want to have this buffer deleted as soon as it is not displayed in the preview window (in fact open something different in the preview window like another tag from another file). This was case two.

3. Case
The last case now, if I opened the new buffer with File C to preview the tag and descide afterwards (while it shown in the preview window) I've to adjust function bar. So I open manually File C (in a new split/in the window of File A/...). Now the previously hidden, which should been deleted when not displayed anymore, gets an "active" buffer I'm working on. So I want to decide when to save this buffer, or close or hide or... Therfore I've to remove all this properties I previously added to it.

Additionally I've to commit that I use the CursorHold event to try open the current word under the cursor as an tag in the preview window. This is a proposal by Vims documentation/help itself and is a good timesaver, cause it make lookups much faster and only get into effect if I stop working (e.g. thinking about this function/object I use currently).

Hopefully this makes my point more clear.

5
  • please provide the difference between the two buffers, why do you need to set the flag in an auto command? Commented Mar 26, 2018 at 13:44
  • @DoktorOSwaldo enough? :) Commented Mar 26, 2018 at 13:58
  • Why can you not just set 'bufhidden' to wipe and 'nobuflisted' when you create the preview window with :pedit in the first place? Your code looks like it will try and set other buffer's 'buflisted' and 'bufhidden' options. This just feels wrong. e.g. What if the other buffer is a help document? That shouldn't become listed. Commented Mar 26, 2018 at 15:59
  • Cause this would effect also buffers I'm actually working on. And I don't get, why it should try to set these options for other buffers, cause there is always the condition in front, isn't it? Commented Mar 26, 2018 at 16:03
  • @PeterRincker I added much more explanation at the both of the question, right after the solution. Maybe this helps to understand my point. Commented Mar 27, 2018 at 12:21

2 Answers 2

6

In general, you can use expand() to convert the mentioned special <afile> / <abuf> into a buffer name / number. The setbufvar() function can access variables in a different buffer. Combined, something like this looks like a possible approach:

autocmd BufAdd * call setbufvar(expand('<abuf>'), 'foo', 1)

Unfortunately, I get E94: No matching buffer for 16; apparently, the data structures aren't yet set up for buffer variables when BufAdd fires.

Alternatives

At least, you get the buffer number, and can use that as a key into a (global) Dictionary to store your flag:

let g:foo = {} " Maps buffer numbers to boolean flags
autocmd BufAdd * let g:foo[expand('<abuf>')] = 1

" To check buffer "nr":
if get(g:foo, nr, 0) ...
Sign up to request clarification or add additional context in comments.

5 Comments

Awesome that looks exactly like what I'm looking for. I was aware about the expand, but not the setbufvar. I will try it out now. I thought about the alternative as well, but this lacks if u have to remove them from the list again, what is less flexible.
I'm afraid you have to use the alternative global variable (or move from BufNew to a later event); I could not make it work in Vim 8.0.1358.
Okay it looks like rly does not work, cause the buffer does not exits at this point. So I rly have to use a list. By this I've to add a third autocmd to remove it from the list again.
The amount of buffers in a Vim session typically isn't that large, and Vim doesn't reuse the number. It would waste a bit of memory, but the cleanup is optional IMO. You could also run the cleanup on CursorHold (or any of your own plugin's actions), using bufexists() to check for entries to be discarded.
But it could get big if my preview window gets filled by a CursorHold autocmd. :)
0

I may be a bit naive here, but have you tried the BufWinEnter and BufWinLeave?

augroup PreviewWindow
   autocmd!
   autocmd BufWinEnter * if &previewwindow | setlocal nobuflisted |
           \ setlocal bufhidden = 'wipe' |  endif

   autocmd BufWinLeave * if &previewwindow &&
           \  setlocal buflisted | setlocal bufhidden = '' |
           \ endif
augroup END

Okay this fails if multiple previews are open on the same buffer, what is the desired behaviour then?

Update 1:

Ingo's solution is of course fine (as always). But a easy alternative would be to turn it around:

augroup PreviewWindow
   autocmd!
   autocmd BufHidden * if &previewwindow | setlocal nobuflisted |
           \ setlocal bufhidden = 'wipe' |  endif

   autocmd BufWinEnter * if !&previewwindow &&
           \  setlocal buflisted | setlocal bufhidden = '' |
           \ endif
augroup END

This needs to have a global nobuflisted set. Still has the problem if the preview is opened on a already active Buffer, then the normal window is closed and the preview kept open.

1 Comment

That cause the problem that if a buffer is already anywhere open and I working on it, then working in another buffer and preview a tag that is defined in the previous one, this buffer will be affected too. The core problem is to load preview buffers only temporally, but do not cumber the mormal work flow by remove buffers the user is activly working on. This can be the case if the buffer is already in work or if it comes into. Bot cases I've to consider.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.