6

I am writing a plugin which needs to have two windows displayed at the same time:

 _______
|   |   |
| A | B |
|___|___|

I need to keep in memory a reference to those windows as I execute my plugin. This is because I need to be able to jump between the two windows automaticaly.

I use the winnr() function that returns the current window number, which I can use later like so:

let s:winA = winnr()
new
let s:winB = winnr()

" stuff

" go to window A
execute s:winA . "wincmd w"

But in this case, both variables will have the value 1, this is because the winnr() return the position of the current window in the tab display.

I tried to use the bufnr('%') which return the buffer number for the current buffer. This is great, but when I do:

let s:bufA = bufnr('%')
new
let s:bufB = bufnr('%')

" stuff

" go to buffer A
execute 'buffer '. s:bufA

The current window load the buffer, and the cursor will not jump to the existing window containing the buffer.


Here is my question:

How to store permanent information about windows so the cursor can jump on it later?

5

I think what you are looking for is the function win_getid() combined to the function win_gotoid().

:h win_getid() says:

win_getid([{win} [, {tab}]])

Get the window ID for the specified window.
When {win} is missing use the current window.
With {win} this is the window number. The top window has number 1.

The advantage of these functions is that ID is linked to a window and does not change when the position of the window is changed

Your script would become something like:

let s:winA = win_getid()
new
let s:winB = win_getid()

" stuff

" go to window A
call win_gotoid(s:winA)
3

You can't store a window number reliably because it changes every time a window is created and destroyed. You can use winbufnr() if you know the buffer's ID.

When the buffer doesn't matter, I use a window variable to keep track of the windows I open:

new
let w:_plugin_variable = 1

The variable above is just a boolean, but you could use your own identifier if you want to keep windows paired to each other. For example:

let w:_plugin_variable = ['parent', 123]
new
let w:_plugin_variable = ['child', 123]

The first item being the relationship and the second as some special identifier. This way is useful if both windows might contain the same buffer but have different settings/purposes.

To find the windows, you just iterate over all window numbers to get the variable you're looking for:

for i in range(1, winnr('$'))
  let id = getwinvar(i, '_plugin_variable', -1)
  if id != -1
    " Do something with the information.
    break
  endif
endfor

In the loop above, i is the window's number. You can get settings from the window with getwinvar(i, '&textwidth') or switch to it with execute i 'wincmd w'.

The same thing can be done with tabs using tabpagenr(), tabpagewinnr(), gettabvar(), gettabwinvar(), etc.

  • Nice! Do you think there's performance drawback from doing this? – nobe4 Jul 10 '16 at 15:40
  • 1
    @nobe4 I'm pretty sure that any performance impact would be unnoticeable since you'd be dealing with dozens of windows at most (per tab) in realistic scenarios. – Tommy A Jul 10 '16 at 15:57
  • 1
    See also this answer (useful in a wider context). – Sato Katsura Jul 10 '16 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.