Reputation: 654
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.
Upvotes: 4
Views: 3030
Reputation: 6016
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.
Upvotes: 0
Reputation: 172510
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.
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) ...
Upvotes: 6