Resize vim split based on number of visible lines

Viewed 77

I am trying to write a function in my vimrc which lets me create a small split which looks as though it is inside the current file but is, in fact, a different file.

To do this cleanly, I want this split to appear immediately below the cursor which means I need to resize my splits appropriately. Unfortunately, I cannot find a way to measure the number of visible lines between my cursor and the top of the window. In files where I have folded code, the approach of using line(".") - line("w0") ("." gives line number of cursor; "w0" gives line number of topmost visible line) does not work since this calculation includes the hidden lines inside the folds. Does anybody know how this could be achieved?

Images for reference before and after inserting the split:

original file

5 line split added immediately below cursor

1 Answers
line(".") - line("w0")

gives you the number of physical lines between the top of the window and the current line. As you figured out, this method doesn't account for folds.

You can count the number of folds within a range with something like this:

function! CountFolds(top_line, bottom_line)
    let folded_lines = []
    for line_nr in range(a:top_line, a:bottom_line)
        if foldlevel(line_nr) == 0
            call add(folded_lines, 0)
        else
            call add(folded_lines, 1)
        endif
    endfor
    return count(uniq(folded_lines), 1)
endfunction

and then remove it from your initial line count:

let top_line = line("w0")
let bottom_line = line(".")
let physical_lines = bottom_line - top_line
let screen_lines = physical_lines - CountFolds(top_line, bottom_line)

Reference:

:help range()
:help foldlevel()
:help add()
:help uniq()
:help count()

Note that you may need your script to account for soft-wrapped lines as well, a topic that is well worth another question.

Related