neovim

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

commit 118e7e7111a94340e2709fe68ef9d9ee4f0713b0
parent c10e36fc016cb265026a772571ce0a405df2ab71
Author: vanaigr <vanaigranov@gmail.com>
Date:   Sun,  3 Aug 2025 21:39:31 -0500

test: add treesitter long lines benchmark

Diffstat:
Mtest/benchmark/decor_spec.lua | 45++++++++++++++++++++++++++++++++++++++++-----
Mtest/benchmark/treesitter_spec.lua | 143++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 182 insertions(+), 6 deletions(-)

diff --git a/test/benchmark/decor_spec.lua b/test/benchmark/decor_spec.lua @@ -8,7 +8,7 @@ describe('decor perf', function() it('can handle long lines', function() Screen.new(100, 101) - local result = exec_lua [==[ + local result = exec_lua(function() local ephemeral_pattern = { { 0, 4, 'Comment', 11 }, { 0, 3, 'Keyword', 12 }, @@ -61,7 +61,7 @@ describe('decor perf', function() return true end, on_line = function() - add_pattern(ephemeral_pattern, true) + add_pattern(ephemeral_pattern, true) end, }) @@ -69,16 +69,16 @@ describe('decor perf', function() local total = {} local provider = {} - for i = 1, 100 do + for _ = 1, 100 do local tic = vim.uv.hrtime() - vim.cmd'redraw!' + vim.cmd 'redraw!' local toc = vim.uv.hrtime() table.insert(total, toc - tic) table.insert(provider, pe - ps) end return { total, provider } - ]==] + end) local total, provider = unpack(result) table.sort(total) @@ -137,4 +137,39 @@ describe('decor perf', function() ) print('\nTotal ' .. res) end) + + it('can handle long lines with treesitter highlighting', function() + Screen.new(100, 51) + + local result = exec_lua(function() + local long_line = 'local a = { ' .. ('a = 5, '):rep(2000) .. '}' + vim.api.nvim_buf_set_lines(0, 0, 0, false, { long_line }) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.treesitter.start(0, 'lua') + + local total = {} + for _ = 1, 50 do + local tic = vim.uv.hrtime() + vim.cmd 'redraw!' + local toc = vim.uv.hrtime() + table.insert(total, toc - tic) + end + + return { total } + end) + + local total = unpack(result) + table.sort(total) + + local ms = 1 / 1000000 + local res = string.format( + 'min, 25%%, median, 75%%, max:\n\t%0.1fms,\t%0.1fms,\t%0.1fms,\t%0.1fms,\t%0.1fms', + total[1] * ms, + total[1 + math.floor(#total * 0.25)] * ms, + total[1 + math.floor(#total * 0.5)] * ms, + total[1 + math.floor(#total * 0.75)] * ms, + total[#total] * ms + ) + print('\nTotal ' .. res) + end) end) diff --git a/test/benchmark/treesitter_spec.lua b/test/benchmark/treesitter_spec.lua @@ -1,10 +1,11 @@ local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') local clear = n.clear local exec_lua = n.exec_lua describe('treesitter perf', function() - setup(function() + before_each(function() clear() end) @@ -47,4 +48,144 @@ describe('treesitter perf', function() return vim.uv.hrtime() - start ]] end) + + local function test_long_line(_pos, _wrap, _line, grid) + local screen = Screen.new(20, 11) + + local result = exec_lua(function(...) + local pos, wrap, line = ... + + vim.api.nvim_buf_set_lines(0, 0, 0, false, { line }) + vim.api.nvim_win_set_cursor(0, pos) + vim.api.nvim_set_option_value('wrap', wrap, { win = 0 }) + + vim.treesitter.start(0, 'lua') + + local total = {} + for _ = 1, 100 do + local tic = vim.uv.hrtime() + vim.cmd 'redraw!' + local toc = vim.uv.hrtime() + table.insert(total, toc - tic) + end + + return { total } + end, _pos, _wrap, _line) + + screen:expect({ grid = grid or '' }) + + local total = unpack(result) + table.sort(total) + + local ms = 1 / 1000000 + local res = string.format( + 'min, 25%%, median, 75%%, max:\n\t%0.2fms,\t%0.2fms,\t%0.2fms,\t%0.2fms,\t%0.2fms', + total[1] * ms, + total[1 + math.floor(#total * 0.25)] * ms, + total[1 + math.floor(#total * 0.5)] * ms, + total[1 + math.floor(#total * 0.75)] * ms, + total[#total] * ms + ) + print('\nTotal ' .. res) + end + + local long_line = 'local a = { ' .. ('a = 5, '):rep(500) .. '}' + it('can redraw the beginning of a long line with wrapping', function() + local grid = [[ + {15:^local} {25:a} {15:=} {16:{} {25:a} {15:=} {26:5}{16:,} {25:a}| + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} | + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,}| + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}| + {16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} | + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=}| + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} | + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a}| + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} | + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,}| + | + ]] + test_long_line({ 1, 0 }, true, long_line, grid) + end) + + it('can redraw the middle of a long line with wrapping', function() + local grid = [[ + {1:<<<}{26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} | + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,}| + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}| + {16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} | + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=}| + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} | + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a}| + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} | + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,}| + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a}^ {15:=} {26:5}| + | + ]] + test_long_line({ 1, math.floor(#long_line / 2) }, true, long_line, grid) + end) + + it('can redraw the end of a long line with wrapping', function() + local grid = [[ + {1:<<<}{25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=}| + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} | + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a}| + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} | + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,}| + {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}| + {16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} | + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=}| + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {25:a} | + {15:=} {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {16:^}} | + | + ]] + test_long_line({ 1, #long_line - 1 }, true, long_line, grid) + end) + + it('can redraw the beginning of a long line without wrapping', function() + local grid = [[ + {15:^local} {25:a} {15:=} {16:{} {25:a} {15:=} {26:5}{16:,} {25:a}| + | + {1:~ }|*8 + | + ]] + test_long_line({ 1, 0 }, false, long_line, grid) + end) + + it('can redraw the middle of a long line without wrapping', function() + local grid = [[ + {16:,} {25:a} {15:=} {26:5}{16:,} {25:a}^ {15:=} {26:5}{16:,} {25:a} {15:=} | + | + {1:~ }|*8 + | + ]] + test_long_line({ 1, math.floor(#long_line / 2) }, false, long_line, grid) + end) + + it('can redraw the end of a long line without wrapping', function() + local grid = [[ + {26:5}{16:,} {25:a} {15:=} {26:5}{16:,} {16:^}} | + | + {1:~ }|*8 + | + ]] + test_long_line({ 1, #long_line - 1 }, false, long_line, grid) + end) + + local long_line_mb = 'local a = { ' .. ('À = 5, '):rep(500) .. '}' + it('can redraw the middle of a long line with multibyte characters', function() + local grid = [[ + {1:<<<}{26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} | + {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,}| + {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}| + {16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} | + {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=}| + {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} | + {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À}| + {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} | + {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,}| + {25:À} {15:=} {26:5}{16:,} {25:À} {15:=} {26:5}{16:,} {25:À}^ {15:=} {26:5}| + | + ]] + test_long_line({ 1, math.floor(#long_line_mb / 2) }, true, long_line_mb, grid) + end) end)