6

Is there a robust way to detect whether a window has a neighbour in a given direction? So far, the only solution I found uses wincmd,

  let winnum = winnr()
  noautocmd wincmd h
  if winnum != winnr()
    noautocmd wincmd l
    return 0
  else 
    return 1
  endif

but is it robust? Ideally, I would like to find a way that does not use wincmd; perhaps something similar to the following tmux command:

tmux display-message -p #{pane_at_left}
2

The winnr function was updated to take movement arguments as patch 8.1.1140 on April 8, 2019. If your version of Vim has this updated function, :echo has('patch-8.1.1140') will output 1.

The movement argument can be 'h', 'j', 'k', or 'l', optionally preceeded by a count. For example, winnr('h') will return the window number of the window to the left of the current window. If there is no window to the left, the current window's window number will be returned. This can be used to check whether the current window has a neighbor to the left, where winnr() !=# winnr('h').

| improve this answer | |
5

You can do this by looking at the window positions. Take "right" as an example. If any window has a left column position greater than the current window's rightmost column, then the current window has some right neighbor. Think about this for a few minutes. Of course, you would need to write similar functions for the other cardinal directions.

function! HasWinToRight()
    let l:rightedge = win_screenpos(0)[1] + winwidth(0) - 1
    for l:win in range(1, winnr('$'))
        if l:win != winnr() && win_screenpos(l:win)[1] > l:rightedge
            return 1
        endif
    endfor
    return 0
endfunction

This solution is much more robust than any that switches windows, since window switching has unpredictable side-effects, even with noautocmd.

It will not tell you which window is to the immediate right, as defined by wincmd l. In general this would also depend on the cursor position and row positions of the other windows. That is, a window may have many right neighbors but wincmd l picks one.

| improve this answer | |
3

I am a little late after @Mass but I tried to do a more generic function which takes the direction to test as argument:

" Values of the argument
"   1 : Top
"   2 : Right
"   3 : Bottom
"   4 : Left
function! HasNeighbour(direction)
    " Position of the current window
    let currentPosition = win_screenpos(winnr())

    if a:direction == 1
        " if we are looking for a top neigbour simply test if we are on the first line
        return currentPosition[0] != 1
    elseif a:direction == 4
        " if we are looking for a left neigbour simply test if we are on the first column
        return currentPosition[1] != 1
    endif

    " Number of windows on the screen
    let winNr = winnr('$')

    while winNr > 0
        " Get the position of each window
        let position = win_screenpos(winNr)
        let winNr = winNr - 1

        " Test for window on the right
        if ( a:direction == 2 && ( currentPosition[1] + winwidth(0) ) < position[1] )
            return 1
        " Test for windo on the bottom
        elseif ( a:direction == 3 && ( currentPosition[0] + winheight(0) ) < position[0] )
            return 1
        endif
    endwhile
endfunction

This way if you want to know if the current window has a right neighbour you can use HasNeighbour(2), to test for neighbour on the left HasNeighbour(4) will do, etc...

| improve this answer | |

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.