1

Lets pretend I have a Vim session with buffers that look like this:

+-------------+--------------+
|             |              |
|             |              |
|             |              |
|             |              |
|             |              |
|      1      |       2      |
|             |              |
|             |              |
|             |              |
|             |              |
|             |              |
+-------------+--------------+

Is there a way to query which buffer is to the right of buffer #1?

Ideally, I'd want something like this (Obviously this isn't Vimscript but I hope it gives you the idea):

get_neighboring_buffers(current_buffer=1, direction="right")
# Result: [2]

And then consider this window layout

+-------------+--------------+
|             |              |
|             |              |
|             |      2       |
|             |              |
|             |              |
|      1      +--------------+
|             |              |
|             |              |
|             |      3       |
|             |              |
|             |              |
+-------------+--------------+

In this case, the same function might return more than one buffer:

get_neighboring_buffers(current_buffer=1, direction="right")
# Result: [2, 3]

Alternatively, is there a way to check which buffer is more "on-top" of another?

get_topmost_buffer([2, 3])
# Result: 2

I'm trying to find the nearest-right buffer for a script I'm writing but am having trouble finding resources about this online.

Ideally, the solution should be able to handle the 3-buffer setup I showed but if it only works with the first example (the vertical split) then that's fine.

Any help would be appreciated.

3

Is there a way to query which buffer is to the right of buffer #1?

I'm not sure it's reliable, but you could try this function:

fu! Get_right_buffers() abort
    let right_edge = win_screenpos(0)[1] + winwidth(0)
    return filter(map(filter(getwininfo(),
        \ {i,v -> v.tabnr == tabpagenr()}),
        \ {i,v -> v.wincol == right_edge + 1 ? getwininfo()[i].bufnr : -1}),
        \ {i,v -> v != -1})
endfu

getwininfo() gives you information about all the windows of all the tabpages.

The purpose of the innermost filter() invocation is to remove the information about the windows in the other tabpages.
The purpose of the map() invocation is to convert those information into the numbers of the buffers whose left edge is next to the right edge of the current window.

For more information, see:

:h win_screenpos()
:h winwidth()
:h filter()
:h map()
:h getwininfo()
:h tabpagenr()

Alternatively, if your Vim version includes the patch 8.1.0307 you could try to use the winlayout() function.

You would have to parse the nested list it returns to get the information you want.

From :h winlayout():

winlayout([{tabnr}])                                        *winlayout()*
            The result is a nested List containing the layout of windows
            in a tabpage.

            Without {tabnr} use the current tabpage, otherwise the tabpage
            with number {tabnr}. If the tabpage {tabnr} is not found,
            returns an empty list.

            For a leaf window, it returns:
                    ['leaf', {winid}]
            For horizontally split windows, which form a column, it
            returns:
                    ['col', [{nested list of windows}]]
            For vertically split windows, which form a row, it returns:
                    ['row', [{nested list of windows}]]

            Example:
                    " Only one window in the tab page
                    :echo winlayout()
                    ['leaf', 1000]
                    " Two horizontally split windows
                    :echo winlayout()
                    ['col', [['leaf', 1000], ['leaf', 1001]]]
                    " Three horizontally split windows, with two
                    " vertically split windows in the middle window
                    :echo winlayout(2)
                    ['col', [['leaf', 1002], ['row', ['leaf', 1003],
                                         ['leaf', 1001]]], ['leaf', 1000]]

Alternatively, is there a way to check which buffer is more "on-top" of another?

You could try this function:

fu! Get_topmost_buffer(a,b) abort
    if bufwinnr(a:a) == -1
        return 'buffer '.a:a.' is not displayed in this tabpage'
    elseif bufwinnr(a:b) == -1
        return 'buffer '.a:b.' is not displayed in this tabpage'
    elseif win_screenpos(bufwinnr(a:a))[0] == win_screenpos(bufwinnr(a:b))[0]
        return 'the windows of buffer '.a:a.' and '.a:b.' are at the same level'
    else
        return win_screenpos(bufwinnr(a:a))[0] > win_screenpos(bufwinnr(a:b))[0]
            \ ? a:b
            \ : a:a
    endif
endfu

For more information, see:

:h bufwinnr()
:h win_screenpos()

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.