Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize a window to fit, taking into account only logical lines?

Tags:

vim

I'm looking to write a function that I can call from a map. The idea is to resize a window to fit the buffer contents. This isn't too difficult:

fu! ResizeWindow(vert) "{{{
    if a:vert
        let longest = max(map(range(1, line('$')), "virtcol([v:val, '$'])"))
        exec "vertical resize " . (longest+4)
    else
        exec 'resize ' . line('$')
        1
    endif
endfu "}}}

I would, however, like the function to take logical lines into account when calculating the height (I'm not overly worried about width).

For example, a line that has wrapped (due to :set wrap) would count as two or more lines. A block of 37 lines that are folded would only count as one.

Does anyone know of a convenient way of getting this 'logical line count' without having to try and calculate it manually? If I do need to do this manually are there any other cases I'm missing that would cause a line to be represented with a potentially different number of lines?

like image 302
Greg Sexton Avatar asked Feb 05 '12 11:02

Greg Sexton


1 Answers

For anyone interested, I gave up trying to find a simple solution to this. Below is the code I ended up with. It takes into account a couple of obvious edge cases; I'm sure others remain. Suggestions for improvement are very welcome.

fu! Sum(vals) "{{{
    let acc = 0
    for val in a:vals
        let acc += val
    endfor
    return acc
endfu "}}}
fu! LogicalLineCounts() "{{{
    if &wrap
        let width = winwidth(0)
        let line_counts = map(range(1, line('$')), "foldclosed(v:val)==v:val?1:(virtcol([v:val, '$'])/width)+1")
    else
        let line_counts = [line('$')]
    endif
    return line_counts
endfu "}}}
fu! LinesHiddenByFoldsCount() "{{{
    let lines = range(1, line('$'))
    call filter(lines, "foldclosed(v:val) > 0 && foldclosed(v:val) != v:val")
    return len(lines)
endfu "}}}
fu! AutoResizeWindow(vert) "{{{
    if a:vert
        let longest = max(map(range(1, line('$')), "virtcol([v:val, '$'])"))
        exec "vertical resize " . (longest+4)
    else
        let line_counts  = LogicalLineCounts()
        let folded_lines = LinesHiddenByFoldsCount()
        let lines        = Sum(line_counts) - folded_lines
        exec 'resize ' . lines
        1
    endif
endfu "}}}
like image 109
Greg Sexton Avatar answered Nov 15 '22 10:11

Greg Sexton