diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
| commit | 9be89f131f87608f224f0ee06d199fcd09d32176 (patch) | |
| tree | 11022dcfa9e08cb4ac5581b16734196128688d48 /test/functional/treesitter | |
| parent | ff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff) | |
| parent | 88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff) | |
| download | rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2 rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip | |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test/functional/treesitter')
| -rw-r--r-- | test/functional/treesitter/fold_spec.lua | 125 | ||||
| -rw-r--r-- | test/functional/treesitter/highlight_spec.lua | 429 | ||||
| -rw-r--r-- | test/functional/treesitter/inspect_tree_spec.lua | 81 | ||||
| -rw-r--r-- | test/functional/treesitter/language_spec.lua | 89 | ||||
| -rw-r--r-- | test/functional/treesitter/node_spec.lua | 103 | ||||
| -rw-r--r-- | test/functional/treesitter/parser_spec.lua | 487 | ||||
| -rw-r--r-- | test/functional/treesitter/query_spec.lua | 524 | ||||
| -rw-r--r-- | test/functional/treesitter/utils_spec.lua | 30 |
8 files changed, 1085 insertions, 783 deletions
diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index a7f278aa01..24b085920c 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -48,13 +48,13 @@ void ui_refresh(void) end local function get_fold_levels() - return exec_lua([[ - local res = {} - for i = 1, vim.api.nvim_buf_line_count(0) do - res[i] = vim.treesitter.foldexpr(i) - end - return res - ]]) + return exec_lua(function() + local res = {} + for i = 1, vim.api.nvim_buf_line_count(0) do + res[i] = vim.treesitter.foldexpr(i) + end + return res + end) end it('can compute fold levels', function() @@ -246,9 +246,13 @@ function f() end -- comment]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (parameters) (arguments)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(function_declaration) (parameters) (arguments)] @fold' + ) + end) parse('lua') eq({ @@ -290,9 +294,13 @@ function f() ) end]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (function_definition) (parameters) (arguments)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(function_declaration) (function_definition) (parameters) (arguments)] @fold' + ) + end) parse('lua') -- If fold1.stop = fold2.start, then move fold1's stop up so that fold2.start gets proper level. @@ -333,9 +341,13 @@ function f(a) end end]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold' + ) + end) parse('lua') eq({ @@ -408,15 +420,15 @@ t3]]) it('handles quantified patterns', function() insert([[ -import hello -import hello -import hello -import hello -import hello -import hello]]) - - exec_lua([[vim.treesitter.query.set('python', 'folds', '(import_statement)+ @fold')]]) - parse('python') +-- hello +-- hello +-- hello +-- hello +-- hello +-- hello]]) + + exec_lua([[vim.treesitter.query.set('lua', 'folds', '(comment)+ @fold')]]) + parse('lua') eq({ [1] = '>1', @@ -646,6 +658,67 @@ import hello]]) } end) + it('does not extend closed fold with `o`/`O`', function() + local screen = Screen.new(60, 24) + screen:attach() + + insert(test_text) + parse('c') + command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1]]) + + feed('5ggzco') + screen:expect({ + grid = [[ + {7:-}void ui_refresh(void) | + {7:│}{ | + {7:│} int width = INT_MAX, height = INT_MAX; | + {7:│} bool ext_widgets[kUIExtCount]; | + {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}| + {7:│}^ | + {7:│} | + {7:│} bool inclusive = ui_override(); | + {7:-} for (size_t i = 0; i < ui_count; i++) { | + {7:2} UI *ui = uis[i]; | + {7:2} width = MIN(ui->width, width); | + {7:2} height = MIN(ui->height, height); | + {7:2} foo = BAR(ui->bazaar, bazaar); | + {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {7:3} } | + {7:2} } | + {7:│}} | + {1:~ }|*5 + {5:-- INSERT --} | + ]], + }) + + feed('<Esc>O') + screen:expect({ + grid = [[ + {7:-}void ui_refresh(void) | + {7:│}{ | + {7:│} int width = INT_MAX, height = INT_MAX; | + {7:│} bool ext_widgets[kUIExtCount]; | + {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}| + {7:│}^ | + {7:│} |*2 + {7:│} bool inclusive = ui_override(); | + {7:-} for (size_t i = 0; i < ui_count; i++) { | + {7:2} UI *ui = uis[i]; | + {7:2} width = MIN(ui->width, width); | + {7:2} height = MIN(ui->height, height); | + {7:2} foo = BAR(ui->bazaar, bazaar); | + {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {7:3} } | + {7:2} } | + {7:│}} | + {1:~ }|*4 + {5:-- INSERT --} | + ]], + }) + end) + it("doesn't open folds that are not touched", function() local screen = Screen.new(40, 8) screen:set_default_attr_ids({ @@ -674,7 +747,7 @@ t2]]) grid = [[ {1:-}# h1 | {1:│}t1 | - {1:│}^ | + {1:-}^ | {1:+}{2:+-- 2 lines: # h2·····················}| {3:~ }|*3 {4:-- INSERT --} | diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 69984b3233..b5a6cb5c17 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -8,10 +8,9 @@ local exec_lua = n.exec_lua local feed = n.feed local command = n.command local api = n.api +local fn = n.fn local eq = t.eq -before_each(clear) - local hl_query_c = [[ (ERROR) @error @@ -65,6 +64,46 @@ static int nlua_schedule(lua_State *const lstate) return 0; }]] +local hl_grid_legacy_c = [[ + {2:^/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || lstate != lstate) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + } | + | + LuaRef cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }|*2 + | +]] + +local hl_grid_ts_c = [[ + {2:^/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | + || {6:lstate} != {6:lstate}) { | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }|*2 + | +]] + local test_text_c = [[ void ui_refresh(void) { @@ -117,9 +156,10 @@ local injection_grid_expected_c = [[ ]] describe('treesitter highlighting (C)', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() + clear() screen = Screen.new(65, 18) screen:attach() screen:set_default_attr_ids { @@ -136,16 +176,49 @@ describe('treesitter highlighting (C)', function() [11] = { foreground = Screen.colors.Cyan4 }, } - exec_lua([[ hl_query = ... ]], hl_query_c) command [[ hi link @error ErrorMsg ]] command [[ hi link @warning WarningMsg ]] end) + it('starting and stopping treesitter highlight works', function() + command('setfiletype c | syntax on') + fn.setreg('r', hl_text_c) + feed('i<C-R><C-O>r<Esc>gg') + -- legacy syntax highlighting is used by default + screen:expect(hl_grid_legacy_c) + + exec_lua(function() + vim.treesitter.query.set('c', 'highlights', hl_query_c) + vim.treesitter.start() + end) + -- treesitter highlighting is used + screen:expect(hl_grid_ts_c) + + exec_lua(function() + vim.treesitter.stop() + end) + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) + + exec_lua(function() + vim.treesitter.start() + end) + -- treesitter highlighting is used + screen:expect(hl_grid_ts_c) + + exec_lua(function() + vim.treesitter.stop() + end) + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) + end) + it('is updated with edits', function() insert(hl_text_c) + feed('gg') screen:expect { grid = [[ - /// Schedule Lua callback on main loop's event queue | + ^/// Schedule Lua callback on main loop's event queue | static int nlua_schedule(lua_State *const lstate) | { | if (lua_type(lstate, 1) != LUA_TFUNCTION | @@ -159,38 +232,18 @@ describe('treesitter highlighting (C)', function() multiqueue_put(main_loop.events, nlua_schedule_event, | 1, (void *)(ptrdiff_t)cb); | return 0; | - ^} | + } | {1:~ }|*2 | ]], } - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] - screen:expect { - grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }|*2 - | - ]], - } + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) + screen:expect(hl_grid_ts_c) feed('5Goc<esc>dd') @@ -316,10 +369,10 @@ describe('treesitter highlighting (C)', function() it('is updated with :sort', function() insert(test_text_c) - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = [[ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | @@ -422,19 +475,19 @@ describe('treesitter highlighting (C)', function() ]], } - exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.query.parse("c", "(declaration) @decl") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local query = vim.treesitter.query.parse('c', '(declaration) @decl') local nodes = {} for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do table.insert(nodes, node) end - parser:set_included_regions({nodes}) + parser:set_included_regions({ nodes }) - local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}}) - ]] + vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } }) + end) screen:expect { grid = [[ @@ -465,13 +518,15 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c", { - injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'} + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', { + injections = { + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))', + }, }) local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = injection_grid_expected_c } end) @@ -481,14 +536,16 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua [[ - vim.treesitter.language.register("c", "foo") - local parser = vim.treesitter.get_parser(0, "c", { - injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))'} + exec_lua(function() + vim.treesitter.language.register('c', 'foo') + local parser = vim.treesitter.get_parser(0, 'c', { + injections = { + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))', + }, }) local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = injection_grid_expected_c } end) @@ -502,13 +559,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua [[ - local injection_query = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - vim.treesitter.query.set("c", "highlights", hl_query) - vim.treesitter.query.set("c", "injections", injection_query) + exec_lua(function() + local injection_query = + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + vim.treesitter.query.set('c', 'highlights', hl_query_c) + vim.treesitter.query.set('c', 'injections', injection_query) - vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, "c")) - ]] + vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) + end) screen:expect { grid = [[ @@ -526,40 +584,21 @@ describe('treesitter highlighting (C)', function() it('supports highlighting with custom highlight groups', function() insert(hl_text_c) + feed('gg') - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) + end) - screen:expect { - grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }|*2 - | - ]], - } + screen:expect(hl_grid_ts_c) -- This will change ONLY the literal strings to look like comments -- The only literal string is the "vim.schedule: expected function" in this test. exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]] screen:expect { grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | + {2:^/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | { | {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | @@ -573,7 +612,7 @@ describe('treesitter highlighting (C)', function() multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | {4:return} {5:0}; | - ^} | + } | {1:~ }|*2 | ]], @@ -590,10 +629,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @constant (#set! "priority" 101))\n'}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { + queries = { + c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n', + }, + }) + end) -- expect everything to have Constant highlight screen:expect { grid = [[ @@ -640,11 +683,14 @@ describe('treesitter highlighting (C)', function() hi link @foo.bar Type hi link @foo String ]] - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c", {}) - local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', {}) + local highlighter = vim.treesitter.highlighter + highlighter.new( + parser, + { queries = { c = '(primitive_type) @foo.bar (string_literal) @foo' } } + ) + end) screen:expect { grid = [[ @@ -672,10 +718,12 @@ describe('treesitter highlighting (C)', function() insert(hl_text_c) -- conceal can be empty or a single cchar. - exec_lua [=[ + exec_lua(function() vim.opt.cole = 2 - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = [[ + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { + queries = { + c = [[ ("static" @keyword (#set! conceal "R")) @@ -688,8 +736,10 @@ describe('treesitter highlighting (C)', function() arguments: (argument_list) @arguments) (#eq? @function "multiqueue_put") (#set! @function conceal "V")) - ]]}}) - ]=] + ]], + }, + }) + end) screen:expect { grid = [[ @@ -746,11 +796,11 @@ describe('treesitter highlighting (C)', function() int z = 6; ]]) - exec_lua([[ + exec_lua(function() local query = '((declaration)+ @string)' vim.treesitter.query.set('c', 'highlights', query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - ]]) + end) screen:expect { grid = [[ @@ -776,14 +826,10 @@ describe('treesitter highlighting (C)', function() declarator: (pointer_declarator) @variable.parameter) ]] - exec_lua( - [[ - local query = ... + exec_lua(function() vim.treesitter.query.set('c', 'highlights', query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - ]], - query - ) + end) screen:expect { grid = [[ @@ -800,6 +846,7 @@ describe('treesitter highlighting (lua)', function() local screen before_each(function() + clear() screen = Screen.new(65, 18) screen:attach() screen:set_default_attr_ids { @@ -817,10 +864,10 @@ describe('treesitter highlighting (lua)', function() ffi.cdef("int (*fun)(int, char *);") ]] - exec_lua [[ + exec_lua(function() vim.bo.filetype = 'lua' vim.treesitter.start() - ]] + end) screen:expect { grid = [[ @@ -838,6 +885,7 @@ describe('treesitter highlighting (help)', function() local screen before_each(function() + clear() screen = Screen.new(40, 6) screen:attach() screen:set_default_attr_ids { @@ -846,9 +894,45 @@ describe('treesitter highlighting (help)', function() [3] = { bold = true, foreground = Screen.colors.Brown }, [4] = { foreground = Screen.colors.Cyan4 }, [5] = { foreground = Screen.colors.Magenta1 }, + title = { bold = true, foreground = Screen.colors.Magenta1 }, + h1_delim = { nocombine = true, underdouble = true }, + h2_delim = { nocombine = true, underline = true }, } end) + it('defaults in vimdoc/highlights.scm', function() + -- Avoid regressions when syncing upstream vimdoc queries. + + insert [[ + ============================================================================== + NVIM DOCUMENTATION + + ------------------------------------------------------------------------------ + ABOUT NVIM *tag-1* *tag-2* + + |news| News + |nvim| NVim + ]] + + feed('gg') + exec_lua(function() + vim.wo.wrap = false + vim.bo.filetype = 'help' + vim.treesitter.start() + end) + + screen:expect({ + grid = [[ + {h1_delim:^========================================}| + {title:NVIM DOCUMENTATION} | + | + {h2_delim:----------------------------------------}| + {title:ABOUT NVIM} | + | + ]], + }) + end) + it('correctly redraws added/removed injections', function() insert [[ >ruby @@ -857,10 +941,10 @@ describe('treesitter highlighting (help)', function() < ]] - exec_lua [[ + exec_lua(function() vim.bo.filetype = 'help' vim.treesitter.start() - ]] + end) screen:expect { grid = [[ @@ -912,15 +996,15 @@ describe('treesitter highlighting (help)', function() ]] ]=]) - exec_lua [[ - parser = vim.treesitter.get_parser(0, "lua", { + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua', { injections = { - lua = '(string content: (_) @injection.content (#set! injection.language lua))' - } + lua = '(string content: (_) @injection.content (#set! injection.language lua))', + }, }) vim.treesitter.highlighter.new(parser) - ]] + end) screen:expect { grid = [=[ @@ -936,9 +1020,10 @@ describe('treesitter highlighting (help)', function() end) describe('treesitter highlighting (nested injections)', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() + clear() screen = Screen.new(80, 7) screen:attach() screen:set_default_attr_ids { @@ -964,11 +1049,11 @@ vim.cmd([[ ]]) ]=] - exec_lua [[ + exec_lua(function() vim.opt.scrolloff = 0 vim.bo.filetype = 'lua' vim.treesitter.start() - ]] + end) -- invalidate the language tree feed('ggi--[[<ESC>04x') @@ -1006,41 +1091,93 @@ describe('treesitter highlighting (markdown)', function() local screen before_each(function() + clear() screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue1 }, - [2] = { bold = true, foreground = Screen.colors.Blue1 }, - [3] = { bold = true, foreground = Screen.colors.Brown }, - [4] = { foreground = Screen.colors.Cyan4 }, - [5] = { foreground = Screen.colors.Magenta1 }, - } + exec_lua(function() + vim.bo.filetype = 'markdown' + vim.treesitter.start() + end) end) it('supports hyperlinks', function() local url = 'https://example.com' insert(string.format('[This link text](%s) is a hyperlink.', url)) - exec_lua([[ - vim.bo.filetype = 'markdown' - vim.treesitter.start() - ]]) + screen:add_extra_attr_ids({ + [100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' }, + [101] = { + foreground = Screen.colors.SlateBlue, + url = 'https://example.com', + underline = true, + }, + }) + screen:expect({ + grid = [[ + {25:[}{100:This link text}{25:](}{101:https://example.com}{25:)} is| + a hyperlink^. | + {1:~ }|*3 + | + ]], + }) + end) - screen:expect { + it('works with spellchecked and smoothscrolled topline', function() + insert([[ +- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$. + +```c +printf('Hello World!'); +``` + ]]) + command('set spell smoothscroll') + feed('gg<C-E>') + screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } }) + screen:expect({ grid = [[ - {4:[}{6:This link text}{4:](}{7:https://example.com}{4:)} is| - a hyperlink^. | - {2:~ }|*3 - | - ]], - attr_ids = { - [1] = { foreground = Screen.colors.Blue1 }, - [2] = { bold = true, foreground = Screen.colors.Blue1 }, - [3] = { bold = true, foreground = Screen.colors.Brown }, - [4] = { foreground = Screen.colors.Cyan4 }, - [5] = { foreground = Screen.colors.Magenta }, - [6] = { foreground = Screen.colors.Cyan4, url = url }, - [7] = { underline = true, foreground = Screen.colors.SlateBlue }, - }, - } + {1:<<<}k^{2}}+\{100:lim}_{w \to 0}x$^. | + | + {18:```}{15:c} | + {25:printf}{16:(}{26:'Hello World!'}{16:);} | + {18:```} | + | + ]], + }) end) end) + +it('starting and stopping treesitter highlight in init.lua works #29541', function() + t.write_file( + 'Xinit.lua', + [[ + vim.bo.ft = 'c' + vim.treesitter.start() + vim.treesitter.stop() + ]] + ) + finally(function() + os.remove('Xinit.lua') + end) + clear({ args = { '-u', 'Xinit.lua' } }) + eq('', api.nvim_get_vvar('errmsg')) + + local screen = Screen.new(65, 18) + screen:attach() + screen:set_default_attr_ids { + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { foreground = Screen.colors.Blue1 }, + [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, + [4] = { bold = true, foreground = Screen.colors.Brown }, + [5] = { foreground = Screen.colors.Magenta }, + [6] = { foreground = Screen.colors.Red }, + [7] = { bold = true, foreground = Screen.colors.SlateBlue }, + [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [9] = { foreground = Screen.colors.Magenta, background = Screen.colors.Red }, + [10] = { foreground = Screen.colors.Red, background = Screen.colors.Red }, + [11] = { foreground = Screen.colors.Cyan4 }, + } + + fn.setreg('r', hl_text_c) + feed('i<C-R><C-O>r<Esc>gg') + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) +end) diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index f5acfe7c4a..1f7d15cc96 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -22,10 +22,10 @@ describe('vim.treesitter.inspect_tree', function() print() ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - ]]) + end) expect_tree [[ (chunk ; [0, 0] - [2, 0] @@ -37,22 +37,26 @@ describe('vim.treesitter.inspect_tree', function() it('can toggle to show anonymous nodes', function() insert([[ - print() + print('hello') ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - ]]) + end) feed('a') expect_tree [[ (chunk ; [0, 0] - [2, 0] - (function_call ; [0, 0] - [0, 7] + (function_call ; [0, 0] - [0, 14] name: (identifier) ; [0, 0] - [0, 5] - arguments: (arguments ; [0, 5] - [0, 7] + arguments: (arguments ; [0, 5] - [0, 14] "(" ; [0, 5] - [0, 6] - ")"))) ; [0, 6] - [0, 7] + (string ; [0, 6] - [0, 13] + start: "'" ; [0, 6] - [0, 7] + content: (string_content) ; [0, 7] - [0, 12] + end: "'") ; [0, 12] - [0, 13] + ")"))) ; [0, 13] - [0, 14] ]] end) @@ -63,11 +67,11 @@ describe('vim.treesitter.inspect_tree', function() ``` ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'markdown') vim.treesitter.get_parser():parse() vim.treesitter.inspect_tree() - ]]) + end) expect_tree [[ (document ; [0, 0] - [4, 0] @@ -92,11 +96,11 @@ describe('vim.treesitter.inspect_tree', function() ``` ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'markdown') vim.treesitter.get_parser():parse() vim.treesitter.inspect_tree() - ]]) + end) feed('I') expect_tree [[ @@ -114,4 +118,57 @@ describe('vim.treesitter.inspect_tree', function() (fenced_code_block_delimiter)))) ; [2, 0] - [2, 3] markdown ]] end) + + it('updates source and tree buffer windows and closes them correctly', function() + insert([[ + print() + ]]) + + -- setup two windows for the source buffer + exec_lua(function() + _G.source_win = vim.api.nvim_get_current_win() + vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left', + }) + end) + + -- setup three windows for the tree buffer + exec_lua(function() + vim.treesitter.start(0, 'lua') + vim.treesitter.inspect_tree() + _G.tree_win = vim.api.nvim_get_current_win() + _G.tree_win_copy_1 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left', + }) + _G.tree_win_copy_2 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left', + }) + end) + + -- close original source window + exec_lua('vim.api.nvim_win_close(source_win, false)') + + -- navigates correctly to the remaining source buffer window + feed('<CR>') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close original tree window + exec_lua(function() + vim.api.nvim_set_current_win(_G.tree_win_copy_1) + vim.api.nvim_win_close(_G.tree_win, false) + end) + + -- navigates correctly to the remaining source buffer window + feed('<CR>') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close source buffer window and all remaining tree windows + t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)') + + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_1)')) + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_2)')) + end) end) diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 40c974beee..e1e34fcecc 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -8,6 +8,7 @@ local exec_lua = n.exec_lua local pcall_err = t.pcall_err local matches = t.matches local insert = n.insert +local NIL = vim.NIL before_each(clear) @@ -15,10 +16,12 @@ describe('treesitter language API', function() -- error tests not requiring a parser library it('handles missing language', function() eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", + '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"', pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')") ) + eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })")) + -- actual message depends on platform matches( "Failed to load parser for language 'borklang': uv_dlopen: .+", @@ -28,37 +31,33 @@ describe('treesitter language API', function() ) ) - eq(false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang')")) + eq(NIL, exec_lua("return vim.treesitter.language.add('borklang')")) eq( false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang', { path = 'borkbork.so' })") ) - eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "parser = vim.treesitter.language.inspect('borklang')") - ) - matches( 'Failed to load parser: uv_dlsym: .+', pcall_err(exec_lua, 'vim.treesitter.language.add("c", { symbol_name = "borklang" })') ) end) - it('shows error for invalid language name', function() - eq( - ".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.language.add("/foo/")') - ) + it('does not load parser for invalid language name', function() + eq(NIL, exec_lua('vim.treesitter.language.add("/foo/")')) end) it('inspects language', function() - local keys, fields, symbols = unpack(exec_lua([[ + local keys, fields, symbols = unpack(exec_lua(function() local lang = vim.treesitter.language.inspect('c') local keys, symbols = {}, {} - for k,_ in pairs(lang) do - keys[k] = true + for k, v in pairs(lang) do + if type(v) == 'boolean' then + keys[k] = v + else + keys[k] = true + end end -- symbols array can have "holes" and is thus not a valid msgpack array @@ -66,10 +65,10 @@ describe('treesitter language API', function() for _, v in pairs(lang.symbols) do table.insert(symbols, v) end - return {keys, lang.fields, symbols} - ]])) + return { keys, lang.fields, symbols } + end)) - eq({ fields = true, symbols = true, _abi_version = true }, keys) + eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys) local fset = {} for _, f in pairs(fields) do @@ -101,9 +100,10 @@ describe('treesitter language API', function() command('set filetype=borklang') -- Should throw an error when filetype changes to borklang eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", + '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"', pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')") ) + eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })")) end ) @@ -113,12 +113,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - tree = langtree:tree_for_range({1, 3, 1, 3}) - ]]) - - eq('<node translation_unit>', exec_lua('return tostring(tree:root())')) + eq( + '<node translation_unit>', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local tree = langtree:tree_for_range({ 1, 3, 1, 3 }) + return tostring(tree:root()) + end) + ) end) it('retrieve the tree given a range when range is out of bounds relative to buffer', function() @@ -127,12 +129,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - tree = langtree:tree_for_range({10, 10, 10, 10}) - ]]) - - eq('<node translation_unit>', exec_lua('return tostring(tree:root())')) + eq( + '<node translation_unit>', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local tree = langtree:tree_for_range({ 10, 10, 10, 10 }) + return tostring(tree:root()) + end) + ) end) it('retrieve the node given a range', function() @@ -141,11 +145,24 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - node = langtree:named_node_for_range({1, 3, 1, 3}) - ]]) + eq( + '<node primitive_type>', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local node = langtree:named_node_for_range({ 1, 3, 1, 3 }) + return tostring(node) + end) + ) + end) + + it('retrieve an anonymous node given a range', function() + insert([[vim.fn.input()]]) + + exec_lua(function() + _G.langtree = vim.treesitter.get_parser(0, 'lua') + _G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 }) + end) - eq('<node primitive_type>', exec_lua('return tostring(node)')) + eq('.', exec_lua('return node:type()')) end) end) diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index 96579f296b..d07ed35368 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -18,43 +18,60 @@ describe('treesitter node API', function() it('double free tree', function() insert('F') - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.get_node():tree() vim.treesitter.get_node():tree() collectgarbage() - ]]) + end) assert_alive() end) it('double free tree 2', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local x = parser:parse()[1]:root():tree() - vim.api.nvim_buf_set_text(0, 0,0, 0,0, {'y'}) + vim.api.nvim_buf_set_text(0, 0, 0, 0, 0, { 'y' }) parser:parse() - vim.api.nvim_buf_set_text(0, 0,0, 0,1, {'z'}) + vim.api.nvim_buf_set_text(0, 0, 0, 0, 1, { 'z' }) parser:parse() collectgarbage() x:root() - ]]) + end) assert_alive() end) it('get_node() with lang given', function() -- this buffer doesn't have filetype set! insert('local foo = function() end') - exec_lua([[ - node = vim.treesitter.get_node({ + exec_lua(function() + _G.node = vim.treesitter.get_node({ bufnr = 0, - pos = { 0, 6 }, -- on "foo" + pos = { 0, 6 }, -- on "foo" lang = 'lua', }) - ]]) + end) eq('foo', lua_eval('vim.treesitter.get_node_text(node, 0)')) eq('identifier', lua_eval('node:type()')) end) + it('get_node() with anonymous nodes included', function() + insert([[print('test')]]) + + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'lua') + _G.tree = _G.parser:parse()[1] + _G.node = vim.treesitter.get_node({ + bufnr = 0, + pos = { 0, 6 }, -- on the first apostrophe + include_anonymous = true, + }) + end) + + eq("'", lua_eval('node:type()')) + eq(false, lua_eval('node:named()')) + end) + it('can move between siblings', function() insert([[ int main(int x, int y, int z) { @@ -62,16 +79,16 @@ describe('treesitter node API', function() } ]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.language.inspect('c') + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + _G.root = tree:root() + vim.treesitter.language.inspect('c') - function node_text(node) + function _G.node_text(node) return vim.treesitter.get_node_text(node, 0) end - ]]) + end) exec_lua 'node = root:descendant_for_range(0, 11, 0, 16)' eq('int x', lua_eval('node_text(node)')) @@ -101,13 +118,13 @@ describe('treesitter node API', function() int x = 3; }]]) - local len = exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - node = tree:root():child(0) - children = node:named_children() + local len = exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + local node = assert(tree:root():child(0)) + _G.children = node:named_children() - return #children - ]]) + return #_G.children + end) eq(3, len) eq('<node compound_statement>', lua_eval('tostring(children[3])')) @@ -119,11 +136,11 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - node = root:child(0):child(2) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.node = _G.root:child(0):child(2) + end) eq(lua_eval('tostring(root)'), lua_eval('tostring(node:root())')) end) @@ -134,11 +151,11 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - child = root:child(0):child(0) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.child = _G.root:child(0):child(0) + end) eq(28, lua_eval('root:byte_length()')) eq(3, lua_eval('child:byte_length()')) @@ -150,15 +167,15 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - main = root:child(0) - body = main:child(2) - statement = body:child(1) - declarator = statement:child(1) - value = declarator:child(1) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.main = _G.root:child(0) + _G.body = _G.main:child(2) + _G.statement = _G.body:child(1) + _G.declarator = _G.statement:child(1) + _G.value = _G.declarator:child(1) + end) eq(lua_eval('main:type()'), lua_eval('root:child_containing_descendant(value):type()')) eq(lua_eval('body:type()'), lua_eval('main:child_containing_descendant(value):type()')) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index dbd6bb3c23..c8829f4785 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -12,9 +12,9 @@ local feed = n.feed describe('treesitter parser API', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() vim.g.__ts_debug = 1 - ]] + end) end) it('parses buffer', function() @@ -23,12 +23,12 @@ describe('treesitter parser API', function() int x = 3; }]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.language.inspect('c') - ]]) + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c') + _G.tree = _G.parser:parse()[1] + _G.root = _G.tree:root() + _G.lang = vim.treesitter.language.inspect('c') + end) eq('<tree>', exec_lua('return tostring(tree)')) eq('<node translation_unit>', exec_lua('return tostring(root)')) @@ -59,11 +59,11 @@ describe('treesitter parser API', function() ) feed('2G7|ay') - exec_lua([[ - tree2 = parser:parse()[1] - root2 = tree2:root() - descendant2 = root2:descendant_for_range(1,2,1,13) - ]]) + exec_lua(function() + _G.tree2 = _G.parser:parse()[1] + _G.root2 = _G.tree2:root() + _G.descendant2 = _G.root2:descendant_for_range(1, 2, 1, 13) + end) eq(false, exec_lua('return tree2 == tree1')) eq(false, exec_lua('return root2 == root')) eq('<node declaration>', exec_lua('return tostring(descendant2)')) @@ -112,17 +112,17 @@ void ui_refresh(void) it('allows to iterate over nodes children', function() insert(test_text) - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') - func_node = parser:parse()[1]:root():child(0) + local func_node = parser:parse()[1]:root():child(0) - res = {} + local res = {} for node, field in func_node:iter_children() do table.insert(res, { node:type(), field }) end return res - ]]) + end) eq({ { 'primitive_type', 'type' }, @@ -135,9 +135,7 @@ void ui_refresh(void) insert(test_text) eq( - '.../treesitter.lua:0: There is no parser available for buffer 1 and one' - .. ' could not be created because lang could not be determined. Either' - .. ' pass lang or set the buffer filetype', + '.../treesitter.lua:0: Parser not found for buffer 1: language could not be determined', pcall_err(exec_lua, 'vim.treesitter.get_parser(0)') ) @@ -148,43 +146,43 @@ void ui_refresh(void) it('allows to get a child by field', function() insert(test_text) - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') - func_node = parser:parse()[1]:root():child(0) + _G.func_node = parser:parse()[1]:root():child(0) local res = {} - for _, node in ipairs(func_node:field("type")) do + for _, node in ipairs(_G.func_node:field('type')) do table.insert(res, { node:type(), node:range() }) end return res - ]]) + end) eq({ { 'primitive_type', 0, 0, 0, 4 } }, res) - local res_fail = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res_fail = exec_lua(function() + vim.treesitter.get_parser(0, 'c') - return #func_node:field("foo") == 0 - ]]) + return #_G.func_node:field('foo') == 0 + end) assert(res_fail) end) it('supports getting text of multiline node', function() insert(test_text) - local res = exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] return vim.treesitter.get_node_text(tree:root(), 0) - ]]) + end) eq(test_text, res) - local res2 = exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") + local res2 = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() return vim.treesitter.get_node_text(root:child(0):child(0), 0) - ]]) + end) eq('void', res2) end) @@ -196,7 +194,7 @@ end]] insert(text) eq( '', - exec_lua [[ + exec_lua(function() local fake_node = {} function fake_node:start() return 3, 0, 23 @@ -211,7 +209,7 @@ end]] return 3, 0, 3, 0 end return vim.treesitter.get_node_text(fake_node, 0) - ]] + end) ) end) @@ -221,7 +219,7 @@ end]] {} ```]] insert(text) - local result = exec_lua([[ + local result = exec_lua(function() local fake_node = {} function fake_node:start() return 1, 0, 7 @@ -233,38 +231,38 @@ end]] return 1, 0, 1, 0 end return vim.treesitter.get_node_text(fake_node, 0) == '' - ]]) + end) eq(true, result) end) it('allows to set simple ranges', function() insert(test_text) - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - return { parser:parse()[1]:root():range() } - ]] + local res = exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c') + return { _G.parser:parse()[1]:root():range() } + end) eq({ 0, 0, 19, 0 }, res) -- The following sets the included ranges for the current parser -- As stated here, this only includes the function (thus the whole buffer, without the last line) - local res2 = exec_lua [[ - local root = parser:parse()[1]:root() - parser:set_included_regions({{root:child(0)}}) - parser:invalidate() - return { parser:parse(true)[1]:root():range() } - ]] + local res2 = exec_lua(function() + local root = _G.parser:parse()[1]:root() + _G.parser:set_included_regions({ { root:child(0) } }) + _G.parser:invalidate() + return { _G.parser:parse(true)[1]:root():range() } + end) eq({ 0, 0, 18, 1 }, res2) eq({ { { 0, 0, 0, 18, 1, 512 } } }, exec_lua [[ return parser:included_regions() ]]) - local range_tbl = exec_lua [[ - parser:set_included_regions { { { 0, 0, 17, 1 } } } - parser:parse() - return parser:included_regions() - ]] + local range_tbl = exec_lua(function() + _G.parser:set_included_regions { { { 0, 0, 17, 1 } } } + _G.parser:parse() + return _G.parser:included_regions() + end) eq({ { { 0, 0, 0, 17, 1, 508 } } }, range_tbl) end) @@ -272,25 +270,25 @@ end]] it('allows to set complex ranges', function() insert(test_text) - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.query.parse("c", "(declaration) @decl") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local query = vim.treesitter.query.parse('c', '(declaration) @decl') - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, node) - end + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, node) + end - parser:set_included_regions({nodes}) + parser:set_included_regions({ nodes }) - local root = parser:parse(true)[1]:root() + local root = parser:parse(true)[1]:root() - local res = {} - for i=0,(root:named_child_count() - 1) do - table.insert(res, { root:named_child(i):range() }) - end - return res - ]] + local res = {} + for i = 0, (root:named_child_count() - 1) do + table.insert(res, { root:named_child(i):range() }) + end + return res + end) eq({ { 2, 2, 2, 40 }, @@ -304,10 +302,10 @@ end]] end) it('allows to create string parsers', function() - local ret = exec_lua [[ - local parser = vim.treesitter.get_string_parser("int foo = 42;", "c") + local ret = exec_lua(function() + local parser = vim.treesitter.get_string_parser('int foo = 42;', 'c') return { parser:parse()[1]:root():range() } - ]] + end) eq({ 0, 0, 0, 13 }, ret) end) @@ -318,33 +316,31 @@ end]] int bar = 13; ]] - local ret = exec_lua( - [[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") + local ret = exec_lua(function(str) + local parser = vim.treesitter.get_string_parser(str, 'c') - local nodes = {} - local query = vim.treesitter.query.parse("c", '((identifier) @id (#eq? @id "foo"))') + local nodes = {} + local query = vim.treesitter.query.parse('c', '((identifier) @id (#eq? @id "foo"))') - for _, node in query:iter_captures(parser:parse()[1]:root(), str) do - table.insert(nodes, { node:range() }) - end + for _, node in query:iter_captures(parser:parse()[1]:root(), str) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - txt - ) + return nodes + end, txt) eq({ { 0, 10, 0, 13 } }, ret) end) describe('when creating a language tree', function() local function get_ranges() - return exec_lua [[ + return exec_lua(function() local result = {} - parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end) + _G.parser:for_each_tree(function(tree) + table.insert(result, { tree:root():range() }) + end) return result - ]] + end) end before_each(function() @@ -360,16 +356,17 @@ int x = INT_MAX; describe('when parsing regions independently', function() it('should inject a language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(5, exec_lua('return #parser:children().c:trees()')) @@ -397,16 +394,17 @@ int x = INT_MAX; describe('when parsing regions combined', function() it('should inject a language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(2, exec_lua('return #parser:children().c:trees()')) @@ -447,16 +445,17 @@ int x = INT_MAX; describe('when using injection.self', function() it('should inject the source language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(5, exec_lua('return #parser:children().c:trees()')) @@ -484,16 +483,17 @@ int x = INT_MAX; describe('when using the offset directive', function() it('should shift the range by the directive amount', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq({ @@ -506,7 +506,7 @@ int x = INT_MAX; }, get_ranges()) end) it('should list all directives', function() - local res_list = exec_lua [[ + local res_list = exec_lua(function() local query = vim.treesitter.query local list = query.list_directives() @@ -514,7 +514,7 @@ int x = INT_MAX; table.sort(list) return list - ]] + end) eq({ 'gsub!', 'offset!', 'set!', 'trim!' }, res_list) end) @@ -530,18 +530,18 @@ int x = INT_MAX; end) it('should return the correct language tree', function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', { injections = { - c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))' - } + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))', + }, }) parser:parse(true) - local sub_tree = parser:language_for_range({1, 18, 1, 19}) + local sub_tree = parser:language_for_range({ 1, 18, 1, 19 }) return sub_tree == parser:children().c - ]]) + end) eq(true, result) end) @@ -555,23 +555,23 @@ print() end) it('ignores optional captures #23100', function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "lua", { + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua', { injections = { lua = ( - '(function_call ' .. - '(arguments ' .. - '(string)? @injection.content ' .. - '(number)? @injection.content ' .. - '(#offset! @injection.content 0 1 0 -1) ' .. - '(#set! injection.language "c")))' - ) - } + '(function_call ' + .. '(arguments ' + .. '(string)? @injection.content ' + .. '(number)? @injection.content ' + .. '(#offset! @injection.content 0 1 0 -1) ' + .. '(#set! injection.language "c")))' + ), + }, }) parser:parse(true) return parser:is_valid() - ]]) + end) eq(true, result) end) @@ -584,18 +584,14 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local result - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - result = metadata.key - end + local result = exec_lua(function() + local query = + vim.treesitter.query.parse('c', '((number_literal) @number (#set! "key" "value"))') + local parser = vim.treesitter.get_parser(0, 'c') - return result - ]]) + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() + return metadata.key + end) eq('value', result) end) @@ -606,19 +602,17 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local query = vim.treesitter.query - local value + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + '((number_literal) @number (#set! @number "key" "value"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - for _, nested_tbl in pairs(metadata) do - return nested_tbl.key - end - end - ]]) + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() + local _, nested_tbl = next(metadata) + return nested_tbl.key + end) eq('value', result) end) @@ -628,19 +622,17 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local query = vim.treesitter.query - local result - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))') - parser = vim.treesitter.get_parser(0, "c") + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - for _, nested_tbl in pairs(metadata) do - return nested_tbl - end - end - ]]) + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() + local _, nested_tbl = next(metadata) + return nested_tbl + end) local expected = { ['key'] = 'value', ['key2'] = 'value2', @@ -663,24 +655,21 @@ print() (function_definition) @function ]] - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'c') - ]]) + end) local function run_query() - return exec_lua( - [[ - local query = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser() - tree = parser:parse()[1] - res = {} - for id, node in query:iter_captures(tree:root()) do - table.insert(res, {query.captures[id], node:range()}) - end - return res - ]], - query0 - ) + return exec_lua(function() + local query = vim.treesitter.query.parse('c', query0) + local parser = vim.treesitter.get_parser() + local tree = parser:parse()[1] + local res = {} + for id, node in query:iter_captures(tree:root()) do + table.insert(res, { query.captures[id], node:range() }) + end + return res + end) end eq({ @@ -718,18 +707,15 @@ print() ]] ]==] - local r = exec_lua( - [[ - local parser = vim.treesitter.get_string_parser(..., 'lua') - parser:parse(true) - local ranges = {} - parser:for_each_tree(function(tstree, tree) - ranges[tree:lang()] = { tstree:root():range(true) } - end) - return ranges - ]], - source - ) + local r = exec_lua(function() + local parser = vim.treesitter.get_string_parser(source, 'lua') + parser:parse(true) + local ranges = {} + parser:for_each_tree(function(tstree, tree) + ranges[tree:lang()] = { tstree:root():range(true) } + end) + return ranges + end) eq({ lua = { 0, 6, 6, 16, 4, 438 }, @@ -741,19 +727,14 @@ print() -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure -- add_bytes() produces the same result. - local rb = exec_lua( - [[ - local r, source = ... - local add_bytes = require('vim.treesitter._range').add_bytes - for lang, range in pairs(r) do - r[lang] = {range[1], range[2], range[4], range[5]} - r[lang] = add_bytes(source, r[lang]) - end - return r - ]], - r, - source - ) + local rb = exec_lua(function() + local add_bytes = require('vim.treesitter._range').add_bytes + for lang, range in pairs(r) do + r[lang] = { range[1], range[2], range[4], range[5] } + r[lang] = add_bytes(source, r[lang]) + end + return r + end) eq(rb, r) end) @@ -766,25 +747,25 @@ print() ]] -- This is not a valid injection since (code) has children and include-children is not set - exec_lua [[ - parser1 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser1 = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content))', + }, }) - parser1:parse(true) - ]] + _G.parser1:parse(true) + end) eq(0, exec_lua('return #vim.tbl_keys(parser1:children())')) - exec_lua [[ - parser2 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser2 = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - parser2:parse(true) - ]] + _G.parser2:parse(true) + end) eq(1, exec_lua('return #vim.tbl_keys(parser2:children())')) eq({ { { 1, 0, 21, 2, 0, 42 } } }, exec_lua('return parser2:children().lua:included_regions()')) @@ -821,46 +802,46 @@ print() < ]]) - exec_lua [[ - parser = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - ]] + end) --- Do not parse injections by default eq( 0, - exec_lua [[ - parser:parse() - return #vim.tbl_keys(parser:children()) - ]] + exec_lua(function() + _G.parser:parse() + return #vim.tbl_keys(_G.parser:children()) + end) ) --- Only parse injections between lines 0, 2 eq( 1, - exec_lua [[ - parser:parse({0, 2}) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse({ 0, 2 }) + return #_G.parser:children().lua:trees() + end) ) eq( 2, - exec_lua [[ - parser:parse({2, 6}) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse({ 2, 6 }) + return #_G.parser:children().lua:trees() + end) ) eq( 7, - exec_lua [[ - parser:parse(true) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse(true) + return #_G.parser:children().lua:trees() + end) ) end) @@ -876,13 +857,13 @@ print() feed(':set ft=help<cr>') - exec_lua [[ - vim.treesitter.get_parser(0, "vimdoc", { + exec_lua(function() + vim.treesitter.get_parser(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - ]] + end) end) it('is valid excluding, invalid including children initially', function() diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index c3a376cd71..c97619c913 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -10,28 +10,26 @@ local pcall_err = t.pcall_err local api = n.api local fn = n.fn -local get_query_result_code = [[ - function get_query_result(query_text) - cquery = vim.treesitter.query.parse("c", query_text) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0) do - -- can't transmit node over RPC. just check the name, range, and text - local text = vim.treesitter.get_node_text(node, 0) - local range = {node:range()} - table.insert(res, { cquery.captures[cid], node:type(), range, text }) - end - return res +local function get_query_result(query_text) + local cquery = vim.treesitter.query.parse('c', query_text) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0) do + -- can't transmit node over RPC. just check the name, range, and text + local text = vim.treesitter.get_node_text(node, 0) + local range = { node:range() } + table.insert(res, { cquery.captures[cid], node:type(), range, text }) end -]] + return res +end describe('treesitter query API', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() vim.g.__ts_debug = 1 - ]] + end) end) local test_text = [[ @@ -71,9 +69,9 @@ void ui_refresh(void) it('supports runtime queries', function() ---@type string[] - local ret = exec_lua [[ - return vim.treesitter.query.get("c", "highlights").captures - ]] + local ret = exec_lua(function() + return vim.treesitter.query.get('c', 'highlights').captures + end) -- see $VIMRUNTIME/queries/c/highlights.scm eq('variable', ret[1]) @@ -84,22 +82,17 @@ void ui_refresh(void) local long_query = test_query:rep(100) ---@return number local function q(_n) - return exec_lua( - [[ - local query, n = ... - local before = vim.api.nvim__stats().ts_query_parse_count - collectgarbage("stop") - for i=1, n, 1 do - cquery = vim.treesitter.query.parse("c", ...) - end - collectgarbage("restart") - collectgarbage("collect") - local after = vim.api.nvim__stats().ts_query_parse_count - return after - before - ]], - long_query, - _n - ) + return exec_lua(function() + local before = vim.api.nvim__stats().ts_query_parse_count + collectgarbage('stop') + for _ = 1, _n, 1 do + vim.treesitter.query.parse('c', long_query, _n) + end + collectgarbage('restart') + collectgarbage('collect') + local after = vim.api.nvim__stats().ts_query_parse_count + return after - before + end) end eq(1, q(1)) @@ -110,20 +103,17 @@ void ui_refresh(void) it('supports query and iter by capture (iter_captures)', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - return res - ]], - test_query - ) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + return res + end) eq({ { '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool @@ -143,26 +133,23 @@ void ui_refresh(void) insert(test_text) ---@type table - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, { pattern, mrepr }) end - return res - ]], - test_query - ) + table.insert(res, { pattern, mrepr }) + end + return res + end) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -191,20 +178,20 @@ void ui_refresh(void) it('supports query and iter by capture for quantifiers', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + return res + end) eq({ { '@funccall', 'expression_statement', 11, 4, 11, 34 }, @@ -216,26 +203,26 @@ void ui_refresh(void) it('supports query and iter by match for quantifiers', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, {pattern, mrepr}) end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + table.insert(res, { pattern, mrepr }) + end + return res + end, '(expression_statement (assignment_expression (call_expression)))+ @funccall') eq({ { @@ -249,23 +236,78 @@ void ui_refresh(void) }, res) end) + it('returns quantified matches in order of range #29344', function() + insert([[ + int main() { + int a, b, c, d, e, f, g, h, i; + a = MIN(0, 1); + b = MIN(0, 1); + c = MIN(0, 1); + d = MIN(0, 1); + e = MIN(0, 1); + f = MIN(0, 1); + g = MIN(0, 1); + h = MIN(0, 1); + i = MIN(0, 1); + } + ]]) + + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + end + table.insert(res, { pattern, mrepr }) + end + return res + end) + + eq({ + { + 1, + { + { '@funccall', 'expression_statement', 2, 2, 2, 16 }, + { '@funccall', 'expression_statement', 3, 2, 3, 16 }, + { '@funccall', 'expression_statement', 4, 2, 4, 16 }, + { '@funccall', 'expression_statement', 5, 2, 5, 16 }, + { '@funccall', 'expression_statement', 6, 2, 6, 16 }, + { '@funccall', 'expression_statement', 7, 2, 7, 16 }, + { '@funccall', 'expression_statement', 8, 2, 8, 16 }, + { '@funccall', 'expression_statement', 9, 2, 9, 16 }, + { '@funccall', 'expression_statement', 10, 2, 10, 16 }, + }, + }, + }, res) + end) + it('can match special regex characters like \\ * + ( with `vim-match?`', function() insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') ---@type table - local res = exec_lua([[ - query = ( - '([_] @plus (#vim-match? @plus "^\\\\+$"))' .. - '([_] @times (#vim-match? @times "^\\\\*$"))' .. - '([_] @paren (#vim-match? @paren "^\\\\($"))' .. - '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' .. - '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))' + local res = exec_lua(function() + local query = ( + '([_] @plus (#vim-match? @plus "^\\\\+$"))' + .. '([_] @times (#vim-match? @times "^\\\\*$"))' + .. '([_] @paren (#vim-match? @paren "^\\\\($"))' + .. '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' + .. '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))' ) - cquery = vim.treesitter.query.parse("c", query) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do + local cquery = vim.treesitter.query.parse('c', query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -276,7 +318,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - ]]) + end) eq({ { 2, { { '@times', '*', 0, 4, 0, 5 } } }, @@ -307,10 +349,9 @@ void ui_refresh(void) return 0; } ]]) - exec_lua(get_query_result_code) local res0 = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]] ) eq({ @@ -319,7 +360,7 @@ void ui_refresh(void) }, res0) local res1 = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[ ((string_literal) @fizzbuzz-strings (#any-of? @fizzbuzz-strings "\"number= %d FizzBuzz\\n\"" @@ -340,16 +381,15 @@ void ui_refresh(void) int x = 123; enum C { y = 124 }; int main() { int z = 125; }]]) - exec_lua(get_query_result_code) local result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#has-ancestor? @literal "function_definition"))]] ) eq({ { 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' } }, result) result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#has-ancestor? @literal "function_definition" "enum_specifier"))]] ) eq({ @@ -358,7 +398,7 @@ void ui_refresh(void) }, result) result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#not-has-ancestor? @literal "enum_specifier"))]] ) eq({ @@ -370,12 +410,15 @@ void ui_refresh(void) it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function() insert('char* astring = "Hello World!";') - local res = exec_lua([[ - cquery = vim.treesitter.query.parse("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))') - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -386,7 +429,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - ]]) + end) eq({ { 1, { { '@quote', '"', 0, 16, 0, 17 } } }, @@ -406,70 +449,60 @@ void ui_refresh(void) local custom_query = '((identifier) @main (#is-main? @main))' do - local res = exec_lua( - [[ - local query = vim.treesitter.query - - local function is_main(match, pattern, bufnr, predicate) - local nodes = match[ predicate[2] ] - for _, node in ipairs(nodes) do - if vim.treesitter.get_node_text(node, bufnr) == 'main' then - return true - end + local res = exec_lua(function() + local query = vim.treesitter.query + + local function is_main(match, _pattern, bufnr, predicate) + local nodes = match[predicate[2]] + for _, node in ipairs(nodes) do + if vim.treesitter.get_node_text(node, bufnr) == 'main' then + return true end - return false end + return false + end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') - -- Time bomb: update this in 0.12 - if vim.fn.has('nvim-0.12') == 1 then - return 'Update this test to remove this message and { all = true } from add_predicate' - end - query.add_predicate("is-main?", is_main, { all = true }) + query.add_predicate('is-main?', is_main) - local query = query.parse("c", ...) + local query0 = query.parse('c', custom_query) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, {node:range()}) - end + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - custom_query - ) + return nodes + end) eq({ { 0, 4, 0, 8 } }, res) end -- Once with the old API. Remove this whole 'do' block in 0.12 do - local res = exec_lua( - [[ - local query = vim.treesitter.query + local res = exec_lua(function() + local query = vim.treesitter.query - local function is_main(match, pattern, bufnr, predicate) - local node = match[ predicate[2] ] + local function is_main(match, _pattern, bufnr, predicate) + local node = match[predicate[2]] - return vim.treesitter.get_node_text(node, bufnr) == 'main' - end + return vim.treesitter.get_node_text(node, bufnr) == 'main' + end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') - query.add_predicate("is-main?", is_main, true) + query.add_predicate('is-main?', is_main, { all = false, force = true }) - local query = query.parse("c", ...) + local query0 = query.parse('c', custom_query) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, {node:range()}) - end + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - custom_query - ) + return nodes + end) -- Remove this 'do' block in 0.12 eq(0, fn.has('nvim-0.12')) @@ -477,16 +510,16 @@ void ui_refresh(void) end do - local res = exec_lua [[ + local res = exec_lua(function() local query = vim.treesitter.query - local t = {} + local r = {} for _, v in ipairs(query.list_predicates()) do - t[v] = true + r[v] = true end - return t - ]] + return r + end) eq(true, res['is-main?']) end @@ -505,18 +538,15 @@ void ui_refresh(void) local function test(input, query) api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n')) - return exec_lua( - [[ - local parser = vim.treesitter.get_parser(0, "lua") - local query = vim.treesitter.query.parse("lua", ...) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - nodes[#nodes+1] = { node:range() } - end - return nodes - ]], - query - ) + return exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua') + local query0 = vim.treesitter.query.parse('lua', query) + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + nodes[#nodes + 1] = { node:range() } + end + return nodes + end) end eq( @@ -583,23 +613,21 @@ void ui_refresh(void) -- Comment ]]) - local query = [[ + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua') + local query = vim.treesitter.query.parse( + 'lua', + [[ (((comment (comment_content))+) @bar (#lua-match? @bar "Comment")) ]] - - local result = exec_lua( - [[ - local parser = vim.treesitter.get_parser(0, "lua") - local query = vim.treesitter.query.parse("lua", ...) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - nodes[#nodes+1] = { node:range() } - end - return nodes - ]], - query - ) + ) + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + nodes[#nodes + 1] = { node:range() } + end + return nodes + end) eq({ { 0, 2, 0, 12 }, @@ -613,23 +641,20 @@ void ui_refresh(void) eq(0, fn.has('nvim-0.12')) insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do - local mrepr = {} - for cid, node in pairs(match) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - table.insert(res, { pattern, mrepr }) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = false }) do + local mrepr = {} + for cid, node in pairs(match) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - return res - ]], - test_query - ) + table.insert(res, { pattern, mrepr }) + end + return res + end) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -661,23 +686,19 @@ void ui_refresh(void) int bar = 13; ]] - local ret = exec_lua( - [[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") + local ret = exec_lua(function() + local parser = vim.treesitter.get_string_parser(txt, 'c') - local nodes = {} - local query = vim.treesitter.query.parse("c", '((identifier) @foo)') - local first_child = parser:parse()[1]:root():child(1) + local nodes = {} + local query = vim.treesitter.query.parse('c', '((identifier) @foo)') + local first_child = assert(parser:parse()[1]:root():child(1)) - for _, node in query:iter_captures(first_child, str) do - table.insert(nodes, { node:range() }) - end + for _, node in query:iter_captures(first_child, txt) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - txt - ) + return nodes + end) eq({ { 1, 10, 1, 13 } }, ret) end) @@ -734,7 +755,10 @@ void ui_refresh(void) const char *sql = "SELECT * FROM Students WHERE name = 'Robert'); DROP TABLE Students;--"; ]]) - local query = [[ + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + [[ (declaration type: (_) declarator: (init_declarator @@ -745,20 +769,15 @@ void ui_refresh(void) (#set! injection.language "sql") (#contains? @_id "sql")) ]] - - local result = exec_lua( - [=[ - local query = vim.treesitter.query.parse("c", ...) - local parser = vim.treesitter.get_parser(0, "c") + ) + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() - local t = {} - for id, node, metadata in query:iter_captures(root, 0) do - t[query.captures[id]] = metadata + local res = {} + for id, _, metadata in query:iter_captures(root, 0) do + res[query.captures[id]] = metadata end - return t - ]=], - query - ) + return res + end) eq({ ['_id'] = { ['injection.language'] = 'sql' }, @@ -782,25 +801,22 @@ void ui_refresh(void) (#eq? @function.name "foo")) ]] - local result = exec_lua( - [[ - local query = vim.treesitter.query.parse("c", ...) - local match_preds = query.match_preds + local result = exec_lua(function() + local query0 = vim.treesitter.query.parse('c', query) + local match_preds = query0.match_preds local called = 0 - function query:match_preds(...) + function query0:match_preds(...) called = called + 1 return match_preds(self, ...) end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() local captures = {} - for id, node in query:iter_captures(root, 0) do + for id in query0:iter_captures(root, 0) do captures[#captures + 1] = id end return { called, captures } - ]], - query - ) + end) eq({ 2, { 1, 1, 2, 2 } }, result) end) diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua index bca0aca0cb..34bea349f6 100644 --- a/test/functional/treesitter/utils_spec.lua +++ b/test/functional/treesitter/utils_spec.lua @@ -17,26 +17,30 @@ describe('treesitter utils', function() int x = 3; }]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - ancestor = root:child(0) - child = ancestor:child(0) - ]]) - - eq(true, exec_lua('return vim.treesitter.is_ancestor(ancestor, child)')) - eq(false, exec_lua('return vim.treesitter.is_ancestor(child, ancestor)')) + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local root = tree:root() + _G.ancestor = assert(root:child(0)) + _G.child = assert(_G.ancestor:named_child(1)) + _G.child_sibling = assert(_G.ancestor:named_child(2)) + _G.grandchild = assert(_G.child:named_child(0)) + end) + + eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.child)')) + eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.grandchild)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.ancestor)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.child_sibling)')) end) it('can detect if a position is contained in a node', function() - exec_lua([[ - node = { + exec_lua(function() + _G.node = { range = function() return 0, 4, 0, 8 end, } - ]]) + end) eq(false, exec_lua('return vim.treesitter.is_in_node_range(node, 0, 3)')) for i = 4, 7 do |