Nathan
Nathan

Reputation: 7855

How do I make window splits maintain consistent sizing with the current as large and others as small

The idea is to do something similar to what Golden Ratio (the vim plugin) does. But instead of sizing to a "golden ratio", I want to set a specific size to the unselected windows.

Ex:

# Window 1 selected
----------------------
|        |   |   |   |
|        |   |   |   |
|   1    | 2 | 3 | 4 |
|        |   |   |   |
|        |   |   |   |
----------------------

# Window 3 selected
----------------------
|   |   |        |   |
|   |   |        |   |
| 1 | 2 |    3   | 4 |
|   |   |        |   |
|   |   |        |   |
----------------------

Here's what I've written so far (It's just a WIP):

function g:ResizeWindow()
  let tabs = gettabinfo()
  let current_tabnr = tabpagenr()
  let current_window = win_getid()

  let tab = filter(tabs, 'v:val.tabnr == current_tabnr')[0]

  for window in tab.windows
    if window != current_window
      call win_gotoid(window)
      exe 'vertical resize' 20
    endif
  endfor

  call win_gotoid(current_window)
  let current_window_size = &columns - ((len(tab.windows) - 1) * 20)
  exe 'vertical resize' current_window_size
endfunction

autocmd WinNew,WinEnter * :call g:ResizeWindow()

To test, you can open a single buffer and just :vsp it several times. Then when you navigate the windows, it seems to work in most case but occasionally one of the windows collapses in an inconsistent way. It's much smaller than the rest. Usually this happens as I navigate from the left to right... and the back from right to left.

Any ideas on what's wrong with this and how to fix it?

Upvotes: 0

Views: 202

Answers (1)

Zorzi
Zorzi

Reputation: 792

super interesting function!

Here's a working version:

function g:ResizeWindow()
  let tabs = gettabinfo()
  let current_tabnr = tabpagenr()
  let current_window = win_getid()

  let tab = filter(tabs, 'v:val.tabnr == current_tabnr')[0]

  let small_size = 5

  for window in tab.windows
    if window == current_window
      let size = &columns - ((len(tab.windows) - 1) * small_size) - (len(tab.windows) - 1)
    else
      let size = small_size
    endif
    noautocmd call win_gotoid(window)
    exe 'noautocmd vertical resize ' . size
  endfor

  call win_gotoid(current_window)
endfunction

set winwidth=1
set winminwidth=1
autocmd WinNew,WinEnter * :call g:ResizeWindow()

Explanation

I did quite a few changes to your initial WIP, here are the main problems your code encountered:

  • The function was called recursively: call of the function win_gotoid was triggering the autocmd. So this was messing up all the sizes

  • The default minimum window size (minwinwidth) and default window size (winwidth) were messing up with the size you applied

  • You resized the current window as last, which squished the window on the right

  • Your main window size calculation didn't take in account the window separators


Disclaimer

This function breaks if there is an horizontal split on one window!

Upvotes: 1

Related Questions