neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 7ba043f0f31cc0c9a783bcb28d6f700a42ba6ff4
parent 98ec3fdf744ffce5e685da76a5ef6f2b000649f6
Author: luukvbaal <luukvbaal@gmail.com>
Date:   Mon, 21 Apr 2025 13:48:26 +0200

feat(api): add "max_height" argument to nvim_win_text_height (#32835)

Useful to e.g. limit the height to the window height, avoiding unnecessary
work. Or to find out how many buffer lines beyond "start_row" take up a
certain number of logical lines (returned in "end_row" and "end_vcol").
Diffstat:
Mruntime/doc/api.txt | 15+++++++++++++--
Mruntime/doc/news.txt | 3+++
Mruntime/lua/vim/_meta/api.lua | 13++++++++++++-
Mruntime/lua/vim/_meta/api_keysets.lua | 1+
Mruntime/lua/vim/lsp/util.lua | 7++++---
Msrc/nvim/api/keysets_defs.h | 1+
Msrc/nvim/api/window.c | 25+++++++++++++++++++++++--
Msrc/nvim/plines.c | 71+++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/nvim/window.c | 16++++++++++------
Mtest/functional/api/window_spec.lua | 458++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
10 files changed, 424 insertions(+), 186 deletions(-)

diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt @@ -3358,13 +3358,24 @@ nvim_win_text_height({window}, {opts}) *nvim_win_text_height()* 0-based inclusive, rounded down to full screen lines. When omitted include the whole line. • end_vcol: Ending virtual column index on "end_row", - 0-based exclusive, rounded up to full screen lines. When - omitted include the whole line. + 0-based exclusive, rounded up to full screen lines. When 0 + only include diff filler and virtual lines above + "end_row". When omitted include the whole line. + • max_height: Don't add the height of lines below the row + for which this height is reached. Useful to e.g. limit the + height to the window height, avoiding unnecessary work. Or + to find out how many buffer lines beyond "start_row" take + up a certain number of logical lines (returned in + "end_row" and "end_vcol"). Return: ~ Dict containing text height information, with these keys: • all: The total number of screen lines occupied by the range. • fill: The number of diff filler or virtual lines among them. + • end_row: The row on which the returned height is reached (first row + of a closed fold). + • end_vcol: Ending virtual column in "end_row" where "max_height" or + the returned height is reached. 0 if "end_row" is a closed fold. See also: ~ • |virtcol()| for text width. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt @@ -108,6 +108,9 @@ The following new features were added. API • |vim.hl.range()| now allows multiple timed highlights +• |nvim_win_text_height()| can limit the lines checked when a certain + `max_height` is reached, and returns the `end_row` and `end_vcol` for which + `max_height` or the calculated height is reached. DEFAULTS diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua @@ -2526,9 +2526,20 @@ function vim.api.nvim_win_set_width(window, width) end --- When omitted include the whole line. --- - end_vcol: Ending virtual column index on "end_row", --- 0-based exclusive, rounded up to full screen lines. ---- When omitted include the whole line. +--- When 0 only include diff filler and virtual lines above +--- "end_row". When omitted include the whole line. +--- - max_height: Don't add the height of lines below the row +--- for which this height is reached. Useful to e.g. limit the +--- height to the window height, avoiding unnecessary work. Or +--- to find out how many buffer lines beyond "start_row" take +--- up a certain number of logical lines (returned in +--- "end_row" and "end_vcol"). --- @return table<string,any> # Dict containing text height information, with these keys: --- - all: The total number of screen lines occupied by the range. --- - fill: The number of diff filler or virtual lines among them. +--- - end_row: The row on which the returned height is reached (first row of +--- a closed fold). +--- - end_vcol: Ending virtual column in "end_row" where "max_height" or the returned +--- height is reached. 0 if "end_row" is a closed fold. --- function vim.api.nvim_win_text_height(window, opts) end diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua @@ -318,6 +318,7 @@ error('Cannot require a meta file') --- @field end_row? integer --- @field start_vcol? integer --- @field end_vcol? integer +--- @field max_height? integer --- @class vim.api.keyset.xdl_diff --- @field on_hunk? fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer? diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua @@ -1649,9 +1649,10 @@ function M.open_floating_preview(contents, syntax, opts) vim.treesitter.start(floating_bufnr) if not opts.height then -- Reduce window height if TS highlighter conceals code block backticks. - local conceal_height = api.nvim_win_text_height(floating_winnr, {}).all - if conceal_height < api.nvim_win_get_height(floating_winnr) then - api.nvim_win_set_height(floating_winnr, conceal_height) + local win_height = api.nvim_win_get_height(floating_winnr) + local text_height = api.nvim_win_text_height(floating_winnr, { max_height = win_height }).all + if text_height < win_height then + api.nvim_win_set_height(floating_winnr, text_height) end end end diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h @@ -229,6 +229,7 @@ typedef struct { Integer end_row; Integer start_vcol; Integer end_vcol; + Integer max_height; } Dict(win_text_height); typedef struct { diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c @@ -483,10 +483,21 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err) /// When omitted include the whole line. /// - end_vcol: Ending virtual column index on "end_row", /// 0-based exclusive, rounded up to full screen lines. -/// When omitted include the whole line. +/// When 0 only include diff filler and virtual lines above +/// "end_row". When omitted include the whole line. +/// - max_height: Don't add the height of lines below the row +/// for which this height is reached. Useful to e.g. limit the +/// height to the window height, avoiding unnecessary work. Or +/// to find out how many buffer lines beyond "start_row" take +/// up a certain number of logical lines (returned in +/// "end_row" and "end_vcol"). /// @return Dict containing text height information, with these keys: /// - all: The total number of screen lines occupied by the range. /// - fill: The number of diff filler or virtual lines among them. +/// - end_row: The row on which the returned height is reached (first row of +/// a closed fold). +/// - end_vcol: Ending virtual column in "end_row" where "max_height" or the returned +/// height is reached. 0 if "end_row" is a closed fold. /// /// @see |virtcol()| for text width. Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *arena, Error *err) @@ -545,6 +556,14 @@ Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *are }); } + int64_t max = INT64_MAX; + if (HAS_KEY(opts, win_text_height, max_height)) { + VALIDATE_RANGE(opts->max_height > 0, "max_height", { + return rv; + }); + max = opts->max_height; + } + if (start_lnum == end_lnum && start_vcol >= 0 && end_vcol >= 0) { VALIDATE((start_vcol <= end_vcol), "%s", "'start_vcol' is higher than 'end_vcol'", { return rv; @@ -552,7 +571,7 @@ Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *are } int64_t fill = 0; - int64_t all = win_text_height(win, start_lnum, start_vcol, end_lnum, end_vcol, &fill); + int64_t all = win_text_height(win, start_lnum, start_vcol, &end_lnum, &end_vcol, &fill, max); if (!HAS_KEY(opts, win_text_height, end_row)) { const int64_t end_fill = win_get_fill(win, line_count + 1); fill += end_fill; @@ -560,5 +579,7 @@ Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *are } PUT_C(rv, "all", INTEGER_OBJ(all)); PUT_C(rv, "fill", INTEGER_OBJ(fill)); + PUT_C(rv, "end_row", INTEGER_OBJ(end_lnum - 1)); + PUT_C(rv, "end_vcol", INTEGER_OBJ(end_vcol)); return rv; } diff --git a/src/nvim/plines.c b/src/nvim/plines.c @@ -953,35 +953,37 @@ int plines_m_win_fill(win_T *wp, linenr_T first, linenr_T last) /// Get the number of screen lines a range of text will take in window "wp". /// -/// @param[in] start_lnum Starting line number, 1-based inclusive. -/// @param[in] start_vcol >= 0: Starting virtual column index on "start_lnum", -/// 0-based inclusive, rounded down to full screen lines. -/// < 0: Count a full "start_lnum", including filler lines above. -/// @param[in] end_lnum Ending line number, 1-based inclusive. -/// @param[in] end_vcol >= 0: Ending virtual column index on "end_lnum", -/// 0-based exclusive, rounded up to full screen lines. -/// < 0: Count a full "end_lnum", not including filler lines below. -/// @param[out] fill If not NULL, set to the number of filler lines in the range. +/// @param[in] start_lnum Starting line number, 1-based inclusive. +/// @param[in] start_vcol >= 0: Starting virtual column index on "start_lnum", +/// 0-based inclusive, rounded down to full screen lines. +/// < 0: Count a full "start_lnum", including filler lines above. +/// @param[in,out] end_lnum Ending line number, 1-based inclusive. Set to last line for +/// which the height is calculated (smaller if "max" is reached). +/// @param[in,out] end_vcol >= 0: Ending virtual column index on "end_lnum", +/// 0-based exclusive, rounded up to full screen lines. +/// < 0: Count a full "end_lnum", not including filler lines below. +/// Set to the number of columns in "end_lnum" to reach "max". +/// @param[in] max Don't calculate the height for lines beyond the line where "max" +/// height is reached. +/// @param[out] fill If not NULL, set to the number of filler lines in the range. int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_t start_vcol, - const linenr_T end_lnum, const int64_t end_vcol, int64_t *const fill) + linenr_T *const end_lnum, int64_t *const end_vcol, int64_t *const fill, + int64_t const max) { - int width1 = 0; - int width2 = 0; - if (start_vcol >= 0 || end_vcol >= 0) { - width1 = wp->w_width_inner - win_col_off(wp); - width2 = width1 + win_col_off2(wp); - width1 = MAX(width1, 0); - width2 = MAX(width2, 0); - } - + int width1 = wp->w_width_inner - win_col_off(wp); + int width2 = width1 + win_col_off2(wp); + width1 = MAX(width1, 0); + width2 = MAX(width2, 0); int64_t height_sum_fill = 0; int64_t height_cur_nofill = 0; int64_t height_sum_nofill = 0; linenr_T lnum = start_lnum; + linenr_T cur_lnum = lnum; + bool cur_folded = false; if (start_vcol >= 0) { linenr_T lnum_next = lnum; - hasFolding(wp, lnum, &lnum, &lnum_next); + cur_folded = hasFolding(wp, lnum, &lnum, &lnum_next); height_cur_nofill = plines_win_nofill(wp, lnum, false); height_sum_nofill += height_cur_nofill; const int64_t row_off = (start_vcol < width1 || width2 <= 0) @@ -991,25 +993,42 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_ lnum = lnum_next + 1; } - while (lnum <= end_lnum) { + while (lnum <= *end_lnum && height_sum_nofill + height_sum_fill < max) { linenr_T lnum_next = lnum; - hasFolding(wp, lnum, &lnum, &lnum_next); + cur_folded = hasFolding(wp, lnum, &lnum, &lnum_next); height_sum_fill += win_get_fill(wp, lnum); height_cur_nofill = plines_win_nofill(wp, lnum, false); height_sum_nofill += height_cur_nofill; + cur_lnum = lnum; lnum = lnum_next + 1; } - if (end_vcol >= 0) { + int64_t vcol_end = *end_vcol; + bool use_vcol = vcol_end >= 0 && lnum > *end_lnum; + if (use_vcol) { height_sum_nofill -= height_cur_nofill; - const int64_t row_off = end_vcol == 0 + const int64_t row_off = vcol_end == 0 ? 0 - : (end_vcol <= width1 || width2 <= 0) + : (vcol_end <= width1 || width2 <= 0) ? 1 - : 1 + (end_vcol - width1 + width2 - 1) / width2; + : 1 + (vcol_end - width1 + width2 - 1) / width2; height_sum_nofill += MIN(row_off, height_cur_nofill); } + if (cur_folded) { + vcol_end = 0; + } else { + int linesize = linetabsize_eol(wp, cur_lnum); + vcol_end = MIN(use_vcol ? vcol_end : INT64_MAX, linesize); + } + + int64_t overflow = height_sum_nofill + height_sum_fill - max; + if (overflow > 0 && width2 > 0 && vcol_end > width2) { + vcol_end -= (vcol_end - width1) % width2 + (overflow - 1) * width2; + } + + *end_lnum = cur_lnum; + *end_vcol = vcol_end; if (fill != NULL) { *fill = height_sum_fill; } diff --git a/src/nvim/window.c b/src/nvim/window.c @@ -933,22 +933,26 @@ void ui_ext_win_viewport(win_T *wp) last_botline = MIN(last_botline, line_count); if (cur_topline < last_topline || (cur_topline == last_topline && wp->w_skipcol < last_skipcol)) { + int64_t vcole = last_skipcol; + linenr_T lnume = last_topline; if (last_topline > 0 && cur_botline < last_topline) { // Scrolling too many lines: only give an approximate "scroll_delta". - delta -= win_text_height(wp, cur_topline, wp->w_skipcol, cur_botline, 0, NULL); delta -= last_topline - cur_botline; - } else { - delta -= win_text_height(wp, cur_topline, wp->w_skipcol, last_topline, last_skipcol, NULL); + lnume = cur_botline; + vcole = 0; } + delta -= win_text_height(wp, cur_topline, wp->w_skipcol, &lnume, &vcole, NULL, INT64_MAX); } else if (cur_topline > last_topline || (cur_topline == last_topline && wp->w_skipcol > last_skipcol)) { + int64_t vcole = wp->w_skipcol; + linenr_T lnume = cur_topline; if (last_botline > 0 && cur_topline > last_botline) { // Scrolling too many lines: only give an approximate "scroll_delta". - delta += win_text_height(wp, last_topline, last_skipcol, last_botline, 0, NULL); delta += cur_topline - last_botline; - } else { - delta += win_text_height(wp, last_topline, last_skipcol, cur_topline, wp->w_skipcol, NULL); + lnume = last_botline; + vcole = 0; } + delta += win_text_height(wp, last_topline, last_skipcol, &lnume, &vcole, NULL, INT64_MAX); } delta += last_topfill; delta -= wp->w_topfill; diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua @@ -177,33 +177,25 @@ describe('API/win', function() local win = curwin() feed('gg') - screen:expect { - grid = [[ + local s1 = [[ ^prologue | |*8 - ]], - } + ]] + screen:expect(s1) -- cursor position is at beginning eq({ 1, 0 }, api.nvim_win_get_cursor(win)) -- move cursor to end api.nvim_win_set_cursor(win, { 101, 0 }) - screen:expect { - grid = [[ + screen:expect([[ |*7 ^epilogue | | - ]], - } + ]]) -- move cursor to the beginning again api.nvim_win_set_cursor(win, { 1, 0 }) - screen:expect { - grid = [[ - ^prologue | - |*8 - ]], - } + screen:expect(s1) -- move focus to new window command('new') @@ -211,8 +203,7 @@ describe('API/win', function() -- sanity check, cursor position is kept eq({ 1, 0 }, api.nvim_win_get_cursor(win)) - screen:expect { - grid = [[ + local s2 = [[ ^ | {1:~ }|*2 {3:[No Name] }| @@ -220,13 +211,12 @@ describe('API/win', function() |*2 {2:[No Name] [+] }| | - ]], - } + ]] + screen:expect(s2) -- move cursor to end api.nvim_win_set_cursor(win, { 101, 0 }) - screen:expect { - grid = [[ + screen:expect([[ ^ | {1:~ }|*2 {3:[No Name] }| @@ -234,22 +224,11 @@ describe('API/win', function() epilogue | {2:[No Name] [+] }| | - ]], - } + ]]) -- move cursor to the beginning again api.nvim_win_set_cursor(win, { 1, 0 }) - screen:expect { - grid = [[ - ^ | - {1:~ }|*2 - {3:[No Name] }| - prologue | - |*2 - {2:[No Name] [+] }| - | - ]], - } + screen:expect(s2) -- curwin didn't change back neq(win, curwin()) @@ -860,8 +839,14 @@ describe('API/win', function() end) describe('text_height', function() + local screen, ns, X + before_each(function() + screen = Screen.new(45, 22) + ns = api.nvim_create_namespace('') + X = api.nvim_get_vvar('maxcol') + end) + it('validation', function() - local X = api.nvim_get_vvar('maxcol') insert([[ aaa bbb @@ -902,6 +887,10 @@ describe('API/win', function() pcall_err(api.nvim_win_text_height, 0, { end_row = 2, end_vcol = X + 1 }) ) eq( + "Invalid 'max_height': out of range", + pcall_err(api.nvim_win_text_height, 0, { max_height = 0 }) + ) + eq( "'start_vcol' is higher than 'end_vcol'", pcall_err( api.nvim_win_text_height, @@ -912,8 +901,6 @@ describe('API/win', function() end) it('with two diff windows', function() - local X = api.nvim_get_vvar('maxcol') - local screen = Screen.new(45, 22) exec([[ set diffopt+=context:2 number let expr = 'printf("%08d", v:val) .. repeat("!", v:val)' @@ -923,8 +910,7 @@ describe('API/win', function() windo diffthis ]]) feed('24gg') - screen:expect { - grid = [[ + screen:expect([[ {7: }{8: }{23:----------------}│{7: }{8: 1 }{22:00000001! }| {7: }{8: }{23:----------------}│{7: }{8: 2 }{22:00000002!! }| {7: }{8: 1 }00000003!!! │{7: }{8: 3 }00000003!!! | @@ -947,80 +933,155 @@ describe('API/win', function() {7: }{8: 41 }{22:00000050!!!!!!!!}│{7: }{8: }{23:----------------}| {2:[No Name] [+] }{3:[No Name] [+] }| | - ]], - } + ]]) screen:try_resize(45, 3) - screen:expect { - grid = [[ + screen:expect([[ {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| {2:[No Name] [+] }{3:[No Name] [+] }| | - ]], - } - eq({ all = 20, fill = 5 }, api.nvim_win_text_height(1000, {})) - eq({ all = 20, fill = 5 }, api.nvim_win_text_height(1001, {})) - eq({ all = 20, fill = 5 }, api.nvim_win_text_height(1000, { start_row = 0 })) - eq({ all = 20, fill = 5 }, api.nvim_win_text_height(1001, { start_row = 0 })) - eq({ all = 15, fill = 0 }, api.nvim_win_text_height(1000, { end_row = -1 })) - eq({ all = 15, fill = 0 }, api.nvim_win_text_height(1000, { end_row = 40 })) - eq({ all = 20, fill = 5 }, api.nvim_win_text_height(1001, { end_row = -1 })) - eq({ all = 20, fill = 5 }, api.nvim_win_text_height(1001, { end_row = 40 })) - eq({ all = 10, fill = 5 }, api.nvim_win_text_height(1000, { start_row = 23 })) - eq({ all = 13, fill = 3 }, api.nvim_win_text_height(1001, { start_row = 18 })) - eq({ all = 11, fill = 0 }, api.nvim_win_text_height(1000, { end_row = 23 })) - eq({ all = 11, fill = 5 }, api.nvim_win_text_height(1001, { end_row = 18 })) - eq({ all = 11, fill = 0 }, api.nvim_win_text_height(1000, { start_row = 3, end_row = 39 })) - eq({ all = 11, fill = 3 }, api.nvim_win_text_height(1001, { start_row = 1, end_row = 34 })) - eq({ all = 9, fill = 0 }, api.nvim_win_text_height(1000, { start_row = 4, end_row = 38 })) - eq({ all = 9, fill = 3 }, api.nvim_win_text_height(1001, { start_row = 2, end_row = 33 })) - eq({ all = 9, fill = 0 }, api.nvim_win_text_height(1000, { start_row = 5, end_row = 37 })) - eq({ all = 9, fill = 3 }, api.nvim_win_text_height(1001, { start_row = 3, end_row = 32 })) - eq({ all = 9, fill = 0 }, api.nvim_win_text_height(1000, { start_row = 17, end_row = 25 })) - eq({ all = 9, fill = 3 }, api.nvim_win_text_height(1001, { start_row = 15, end_row = 20 })) - eq({ all = 7, fill = 0 }, api.nvim_win_text_height(1000, { start_row = 18, end_row = 24 })) - eq({ all = 7, fill = 3 }, api.nvim_win_text_height(1001, { start_row = 16, end_row = 19 })) - eq({ all = 6, fill = 5 }, api.nvim_win_text_height(1000, { start_row = -1 })) - eq({ all = 5, fill = 5 }, api.nvim_win_text_height(1000, { start_row = -1, start_vcol = X })) - eq( - { all = 0, fill = 0 }, + ]]) + eq({ all = 20, fill = 5, end_row = 40, end_vcol = 53 }, api.nvim_win_text_height(1000, {})) + eq({ all = 20, fill = 5, end_row = 40, end_vcol = 58 }, api.nvim_win_text_height(1001, {})) + eq( + { all = 20, fill = 5, end_row = 40, end_vcol = 53 }, + api.nvim_win_text_height(1000, { start_row = 0 }) + ) + eq( + { all = 20, fill = 5, end_row = 40, end_vcol = 58 }, + api.nvim_win_text_height(1001, { start_row = 0 }) + ) + eq( + { all = 15, fill = 0, end_row = 40, end_vcol = 53 }, + api.nvim_win_text_height(1000, { end_row = -1 }) + ) + eq( + { all = 15, fill = 0, end_row = 40, end_vcol = 53 }, + api.nvim_win_text_height(1000, { end_row = 40 }) + ) + eq( + { all = 20, fill = 5, end_row = 40, end_vcol = 58 }, + api.nvim_win_text_height(1001, { end_row = -1 }) + ) + eq( + { all = 20, fill = 5, end_row = 40, end_vcol = 58 }, + api.nvim_win_text_height(1001, { end_row = 40 }) + ) + eq( + { all = 10, fill = 5, end_row = 40, end_vcol = 53 }, + api.nvim_win_text_height(1000, { start_row = 23 }) + ) + eq( + { all = 13, fill = 3, end_row = 40, end_vcol = 58 }, + api.nvim_win_text_height(1001, { start_row = 18 }) + ) + eq( + { all = 11, fill = 0, end_row = 23, end_vcol = 36 }, + api.nvim_win_text_height(1000, { end_row = 23 }) + ) + eq( + { all = 11, fill = 5, end_row = 18, end_vcol = 36 }, + api.nvim_win_text_height(1001, { end_row = 18 }) + ) + eq( + { all = 11, fill = 0, end_row = 39, end_vcol = 52 }, + api.nvim_win_text_height(1000, { start_row = 3, end_row = 39 }) + ) + eq( + { all = 11, fill = 3, end_row = 34, end_vcol = 52 }, + api.nvim_win_text_height(1001, { start_row = 1, end_row = 34 }) + ) + eq( + { all = 9, fill = 0, end_row = 25, end_vcol = 0 }, + api.nvim_win_text_height(1000, { start_row = 4, end_row = 38 }) + ) + eq( + { all = 9, fill = 3, end_row = 20, end_vcol = 0 }, + api.nvim_win_text_height(1001, { start_row = 2, end_row = 33 }) + ) + eq( + { all = 9, fill = 0, end_row = 25, end_vcol = 0 }, + api.nvim_win_text_height(1000, { start_row = 5, end_row = 37 }) + ) + eq( + { all = 9, fill = 3, end_row = 20, end_vcol = 0 }, + api.nvim_win_text_height(1001, { start_row = 3, end_row = 32 }) + ) + eq( + { all = 9, fill = 0, end_row = 25, end_vcol = 0 }, + api.nvim_win_text_height(1000, { start_row = 17, end_row = 25 }) + ) + eq( + { all = 9, fill = 3, end_row = 20, end_vcol = 0 }, + api.nvim_win_text_height(1001, { start_row = 15, end_row = 20 }) + ) + eq( + { all = 7, fill = 0, end_row = 24, end_vcol = 37 }, + api.nvim_win_text_height(1000, { start_row = 18, end_row = 24 }) + ) + eq( + { all = 7, fill = 3, end_row = 19, end_vcol = 37 }, + api.nvim_win_text_height(1001, { start_row = 16, end_row = 19 }) + ) + eq( + { all = 6, fill = 5, end_row = 40, end_vcol = 53 }, + api.nvim_win_text_height(1000, { start_row = -1 }) + ) + eq( + { all = 5, fill = 5, end_row = 40, end_vcol = 53 }, + api.nvim_win_text_height(1000, { start_row = -1, start_vcol = X }) + ) + eq( + { all = 0, fill = 0, end_row = 40, end_vcol = 53 }, api.nvim_win_text_height(1000, { start_row = -1, start_vcol = X, end_row = -1 }) ) eq( - { all = 0, fill = 0 }, + { all = 0, fill = 0, end_row = 40, end_vcol = 53 }, api.nvim_win_text_height( 1000, { start_row = -1, start_vcol = X, end_row = -1, end_vcol = X } ) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 40, end_vcol = 53 }, api.nvim_win_text_height( 1000, { start_row = -1, start_vcol = 0, end_row = -1, end_vcol = X } ) ) - eq({ all = 3, fill = 2 }, api.nvim_win_text_height(1001, { end_row = 0 })) - eq({ all = 2, fill = 2 }, api.nvim_win_text_height(1001, { end_row = 0, end_vcol = 0 })) eq( - { all = 2, fill = 2 }, + { all = 3, fill = 2, end_row = 0, end_vcol = 11 }, + api.nvim_win_text_height(1001, { end_row = 0 }) + ) + eq( + { all = 2, fill = 2, end_row = 0, end_vcol = 0 }, + api.nvim_win_text_height(1001, { end_row = 0, end_vcol = 0 }) + ) + eq( + { all = 2, fill = 2, end_row = 0, end_vcol = 0 }, api.nvim_win_text_height(1001, { start_row = 0, end_row = 0, end_vcol = 0 }) ) eq( - { all = 0, fill = 0 }, + { all = 0, fill = 0, end_row = 0, end_vcol = 0 }, api.nvim_win_text_height(1001, { start_row = 0, start_vcol = 0, end_row = 0, end_vcol = 0 }) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 0, end_vcol = 11 }, api.nvim_win_text_height(1001, { start_row = 0, start_vcol = 0, end_row = 0, end_vcol = X }) ) - eq({ all = 11, fill = 5 }, api.nvim_win_text_height(1001, { end_row = 18 })) eq( - { all = 9, fill = 3 }, + { all = 11, fill = 5, end_row = 18, end_vcol = 36 }, + api.nvim_win_text_height(1001, { end_row = 18 }) + ) + eq( + { all = 9, fill = 3, end_row = 18, end_vcol = 36 }, api.nvim_win_text_height(1001, { start_row = 0, start_vcol = 0, end_row = 18 }) ) - eq({ all = 10, fill = 5 }, api.nvim_win_text_height(1001, { end_row = 18, end_vcol = 0 })) eq( - { all = 8, fill = 3 }, + { all = 10, fill = 5, end_row = 18, end_vcol = 0 }, + api.nvim_win_text_height(1001, { end_row = 18, end_vcol = 0 }) + ) + eq( + { all = 8, fill = 3, end_row = 18, end_vcol = 0 }, api.nvim_win_text_height( 1001, { start_row = 0, start_vcol = 0, end_row = 18, end_vcol = 0 } @@ -1029,13 +1090,10 @@ describe('API/win', function() end) it('with wrapped lines', function() - local X = api.nvim_get_vvar('maxcol') - local screen = Screen.new(45, 22) exec([[ set number cpoptions+=n call setline(1, repeat([repeat('foobar-', 36)], 3)) ]]) - local ns = api.nvim_create_namespace('') api.nvim_buf_set_extmark( 0, ns, @@ -1050,8 +1108,7 @@ describe('API/win', function() 200, { virt_text = { { ('!'):rep(75), 'Search' } }, virt_text_pos = 'inline' } ) - screen:expect { - grid = [[ + screen:expect([[ {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| @@ -1074,142 +1131,187 @@ describe('API/win', function() {10:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar- | | - ]], - } + ]]) screen:try_resize(45, 2) - screen:expect { - grid = [[ + screen:expect([[ {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| | - ]], - } - eq({ all = 21, fill = 0 }, api.nvim_win_text_height(0, {})) - eq({ all = 6, fill = 0 }, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 })) - eq({ all = 7, fill = 0 }, api.nvim_win_text_height(0, { start_row = 1, end_row = 1 })) - eq({ all = 8, fill = 0 }, api.nvim_win_text_height(0, { start_row = 2, end_row = 2 })) + ]]) + eq({ all = 21, fill = 0, end_row = 2, end_vcol = 327 }, api.nvim_win_text_height(0, {})) + eq( + { all = 6, fill = 0, end_row = 0, end_vcol = 252 }, + api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }) + ) eq( - { all = 0, fill = 0 }, + { all = 7, fill = 0, end_row = 1, end_vcol = 267 }, + api.nvim_win_text_height(0, { start_row = 1, end_row = 1 }) + ) + eq( + { all = 8, fill = 0, end_row = 2, end_vcol = 327 }, + api.nvim_win_text_height(0, { start_row = 2, end_row = 2 }) + ) + eq( + { all = 0, fill = 0, end_row = 1, end_vcol = 0 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 0 }) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 1, end_vcol = 41 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 41 }) ) eq( - { all = 2, fill = 0 }, + { all = 2, fill = 0, end_row = 1, end_vcol = 42 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 42 }) ) eq( - { all = 2, fill = 0 }, + { all = 2, fill = 0, end_row = 1, end_vcol = 86 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 86 }) ) eq( - { all = 3, fill = 0 }, + { all = 3, fill = 0, end_row = 1, end_vcol = 87 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 87 }) ) eq( - { all = 6, fill = 0 }, + { all = 6, fill = 0, end_row = 1, end_vcol = 266 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 266 }) ) eq( - { all = 7, fill = 0 }, + { all = 7, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 267 }) ) eq( - { all = 7, fill = 0 }, + { all = 7, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 311 }) ) eq( - { all = 7, fill = 0 }, + { all = 7, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = 312 }) ) eq( - { all = 7, fill = 0 }, + { all = 7, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 0, end_row = 1, end_vcol = X }) ) eq( - { all = 7, fill = 0 }, + { all = 7, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 40, end_row = 1, end_vcol = X }) ) eq( - { all = 6, fill = 0 }, + { all = 6, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 41, end_row = 1, end_vcol = X }) ) eq( - { all = 6, fill = 0 }, + { all = 6, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 85, end_row = 1, end_vcol = X }) ) eq( - { all = 5, fill = 0 }, + { all = 5, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 86, end_row = 1, end_vcol = X }) ) eq( - { all = 2, fill = 0 }, + { all = 2, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 265, end_row = 1, end_vcol = X }) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 266, end_row = 1, end_vcol = X }) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 310, end_row = 1, end_vcol = X }) ) eq( - { all = 0, fill = 0 }, + { all = 0, fill = 0, end_row = 1, end_vcol = 267 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 311, end_row = 1, end_vcol = X }) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 1, end_vcol = 131 }, api.nvim_win_text_height(0, { start_row = 1, start_vcol = 86, end_row = 1, end_vcol = 131 }) ) eq( - { all = 1, fill = 0 }, + { all = 1, fill = 0, end_row = 1, end_vcol = 266 }, api.nvim_win_text_height( 0, { start_row = 1, start_vcol = 221, end_row = 1, end_vcol = 266 } ) ) - eq({ all = 18, fill = 0 }, api.nvim_win_text_height(0, { start_row = 0, start_vcol = 131 })) - eq({ all = 19, fill = 0 }, api.nvim_win_text_height(0, { start_row = 0, start_vcol = 130 })) - eq({ all = 20, fill = 0 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 311 })) - eq({ all = 21, fill = 0 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 312 })) eq( - { all = 17, fill = 0 }, + { all = 18, fill = 0, end_row = 2, end_vcol = 327 }, + api.nvim_win_text_height(0, { start_row = 0, start_vcol = 131 }) + ) + eq( + { all = 19, fill = 0, end_row = 2, end_vcol = 327 }, + api.nvim_win_text_height(0, { start_row = 0, start_vcol = 130 }) + ) + eq( + { all = 20, fill = 0, end_row = 2, end_vcol = 311 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 311 }) + ) + eq( + { all = 21, fill = 0, end_row = 2, end_vcol = 312 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 312 }) + ) + eq( + { all = 17, fill = 0, end_row = 2, end_vcol = 311 }, api.nvim_win_text_height( 0, { start_row = 0, start_vcol = 131, end_row = 2, end_vcol = 311 } ) ) eq( - { all = 19, fill = 0 }, + { all = 19, fill = 0, end_row = 2, end_vcol = 312 }, api.nvim_win_text_height( 0, { start_row = 0, start_vcol = 130, end_row = 2, end_vcol = 312 } ) ) - eq({ all = 16, fill = 0 }, api.nvim_win_text_height(0, { start_row = 0, start_vcol = 221 })) - eq({ all = 17, fill = 0 }, api.nvim_win_text_height(0, { start_row = 0, start_vcol = 220 })) - eq({ all = 14, fill = 0 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 41 })) - eq({ all = 15, fill = 0 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 42 })) eq( - { all = 9, fill = 0 }, + { all = 16, fill = 0, end_row = 2, end_vcol = 327 }, + api.nvim_win_text_height(0, { start_row = 0, start_vcol = 221 }) + ) + eq( + { all = 17, fill = 0, end_row = 2, end_vcol = 327 }, + api.nvim_win_text_height(0, { start_row = 0, start_vcol = 220 }) + ) + eq( + { all = 14, fill = 0, end_row = 2, end_vcol = 41 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 41 }) + ) + eq( + { all = 15, fill = 0, end_row = 2, end_vcol = 42 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 42 }) + ) + eq( + { all = 9, fill = 0, end_row = 2, end_vcol = 41 }, api.nvim_win_text_height(0, { start_row = 0, start_vcol = 221, end_row = 2, end_vcol = 41 }) ) eq( - { all = 11, fill = 0 }, + { all = 11, fill = 0, end_row = 2, end_vcol = 42 }, api.nvim_win_text_height(0, { start_row = 0, start_vcol = 220, end_row = 2, end_vcol = 42 }) ) + exec('call setline(1, "foo")') + eq( + { all = 1, fill = 0, end_row = 0, end_vcol = 3 }, + api.nvim_win_text_height(0, { max_height = 1 }) + ) + eq( + { all = 8, fill = 0, end_row = 1, end_vcol = 41 }, + api.nvim_win_text_height(0, { max_height = 2 }) + ) + eq( + { all = 2, fill = 0, end_row = 1, end_vcol = 1 }, + api.nvim_win_text_height(0, { max_height = 2, end_row = 1, end_vcol = 1 }) + ) + eq( + { all = 8, fill = 0, end_row = 1, end_vcol = 41 }, + api.nvim_win_text_height(0, { max_height = 2, end_row = 2, end_vcol = 1 }) + ) end) it('with virtual lines around a fold', function() - local X = api.nvim_get_vvar('maxcol') - local screen = Screen.new(45, 10) + screen:try_resize(45, 10) exec([[ call setline(1, range(1, 8)) 3,6fold ]]) - local ns = api.nvim_create_namespace('TEST') api.nvim_buf_set_extmark( 0, ns, @@ -1236,21 +1338,85 @@ describe('API/win', function() {1:~ }| | ]]) - eq({ all = 8, fill = 3 }, api.nvim_win_text_height(0, {})) - eq({ all = 5, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2 })) - eq({ all = 5, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = X })) - eq({ all = 5, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 90 })) - eq({ all = 5, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 46 })) - eq({ all = 5, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 45 })) - eq({ all = 5, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 1 })) - eq({ all = 4, fill = 2 }, api.nvim_win_text_height(0, { end_row = 2, end_vcol = 0 })) - eq({ all = 6, fill = 3 }, api.nvim_win_text_height(0, { start_row = 2 })) - eq({ all = 4, fill = 1 }, api.nvim_win_text_height(0, { start_row = 2, start_vcol = 0 })) - eq({ all = 4, fill = 1 }, api.nvim_win_text_height(0, { start_row = 2, start_vcol = 44 })) - eq({ all = 3, fill = 1 }, api.nvim_win_text_height(0, { start_row = 2, start_vcol = 45 })) - eq({ all = 3, fill = 1 }, api.nvim_win_text_height(0, { start_row = 2, start_vcol = 89 })) - eq({ all = 3, fill = 1 }, api.nvim_win_text_height(0, { start_row = 2, start_vcol = 90 })) - eq({ all = 3, fill = 1 }, api.nvim_win_text_height(0, { start_row = 2, start_vcol = X })) + eq({ all = 8, fill = 3, end_row = 7, end_vcol = 1 }, api.nvim_win_text_height(0, {})) + eq( + { all = 5, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2 }) + ) + eq( + { all = 5, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = X }) + ) + eq( + { all = 5, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 90 }) + ) + eq( + { all = 5, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 46 }) + ) + eq( + { all = 5, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 45 }) + ) + eq( + { all = 5, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 1 }) + ) + eq( + { all = 4, fill = 2, end_row = 2, end_vcol = 0 }, + api.nvim_win_text_height(0, { end_row = 2, end_vcol = 0 }) + ) + eq( + { all = 6, fill = 3, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2 }) + ) + eq( + { all = 4, fill = 1, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2, start_vcol = 0 }) + ) + eq( + { all = 4, fill = 1, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2, start_vcol = 44 }) + ) + eq( + { all = 3, fill = 1, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2, start_vcol = 45 }) + ) + eq( + { all = 3, fill = 1, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2, start_vcol = 89 }) + ) + eq( + { all = 3, fill = 1, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2, start_vcol = 90 }) + ) + eq( + { all = 3, fill = 1, end_row = 7, end_vcol = 1 }, + api.nvim_win_text_height(0, { start_row = 2, start_vcol = X }) + ) + end) + + it('with virt_lines above max_height row', function() + screen:try_resize(45, 10) + exec('call setline(1, range(1, 7) + ["foo"->repeat(20)])') + api.nvim_buf_set_extmark(0, ns, 6, 0, { virt_lines = { { { 'VIRT LINE 1' } } } }) + screen:expect([[ + ^1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + VIRT LINE 1 | + foofoofoofoofoofoofoofoofoofoofoofoofoofoo{1:@@@}| + | + ]]) + eq( + { all = 10, fill = 1, end_row = 7, end_vcol = 45 }, + api.nvim_win_text_height(0, { max_height = api.nvim_win_get_height(0) }) + ) end) end)