aboutsummaryrefslogtreecommitdiff
path: root/test/functional/treesitter/fold_spec.lua
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/treesitter/fold_spec.lua')
-rw-r--r--test/functional/treesitter/fold_spec.lua553
1 files changed, 378 insertions, 175 deletions
diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua
index a8abbc002b..9428432f66 100644
--- a/test/functional/treesitter/fold_spec.lua
+++ b/test/functional/treesitter/fold_spec.lua
@@ -5,6 +5,7 @@ local insert = helpers.insert
local exec_lua = helpers.exec_lua
local command = helpers.command
local feed = helpers.feed
+local poke_eventloop = helpers.poke_eventloop
local Screen = require('test.functional.ui.screen')
before_each(clear)
@@ -12,6 +13,11 @@ before_each(clear)
describe('treesitter foldexpr', function()
clear()
+ before_each(function()
+ -- open folds to avoid deleting entire folded region
+ exec_lua([[vim.opt.foldlevel = 9]])
+ end)
+
local test_text = [[
void ui_refresh(void)
{
@@ -33,6 +39,12 @@ void ui_refresh(void)
}
}]]
+ local function parse(lang)
+ exec_lua(
+ ([[vim.treesitter.get_parser(0, %s):parse()]]):format(lang and '"' .. lang .. '"' or 'nil')
+ )
+ end
+
local function get_fold_levels()
return exec_lua([[
local res = {}
@@ -43,10 +55,10 @@ void ui_refresh(void)
]])
end
- it("can compute fold levels", function()
+ it('can compute fold levels', function()
insert(test_text)
- exec_lua([[vim.treesitter.get_parser(0, "c")]])
+ parse('c')
eq({
[1] = '>1',
@@ -67,16 +79,17 @@ void ui_refresh(void)
[16] = '3',
[17] = '3',
[18] = '2',
- [19] = '1' }, get_fold_levels())
-
+ [19] = '1',
+ }, get_fold_levels())
end)
- it("recomputes fold levels after lines are added/removed", function()
+ it('recomputes fold levels after lines are added/removed', function()
insert(test_text)
- exec_lua([[vim.treesitter.get_parser(0, "c")]])
+ parse('c')
command('1,2d')
+ poke_eventloop()
eq({
[1] = '0',
@@ -95,9 +108,11 @@ void ui_refresh(void)
[14] = '2',
[15] = '2',
[16] = '1',
- [17] = '0' }, get_fold_levels())
+ [17] = '0',
+ }, get_fold_levels())
command('1put!')
+ poke_eventloop()
eq({
[1] = '>1',
@@ -118,26 +133,295 @@ void ui_refresh(void)
[16] = '3',
[17] = '3',
[18] = '2',
- [19] = '1' }, get_fold_levels())
+ [19] = '1',
+ }, get_fold_levels())
+ end)
+
+ it('handles changes close to start/end of folds', function()
+ insert([[
+# h1
+t1
+# h2
+t2]])
+
+ exec_lua([[vim.treesitter.query.set('markdown', 'folds', '(section) @fold')]])
+ parse('markdown')
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>1',
+ [4] = '1',
+ }, get_fold_levels())
+
+ feed('2ggo<Esc>')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ [4] = '>1',
+ [5] = '1',
+ }, get_fold_levels())
+
+ feed('dd')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>1',
+ [4] = '1',
+ }, get_fold_levels())
+
+ feed('2ggdd')
+ poke_eventloop()
+
+ eq({
+ [1] = '0',
+ [2] = '>1',
+ [3] = '1',
+ }, get_fold_levels())
+
+ feed('u')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>1',
+ [4] = '1',
+ }, get_fold_levels())
+
+ feed('3ggdd')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ }, get_fold_levels())
+
+ feed('u')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>1',
+ [4] = '1',
+ }, get_fold_levels())
+
+ feed('3ggI#<Esc>')
+ parse()
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>2',
+ [4] = '2',
+ }, get_fold_levels())
+
+ feed('x')
+ parse()
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>1',
+ [4] = '1',
+ }, get_fold_levels())
end)
- it("updates folds in all windows", function()
+ it('handles changes that trigger multiple on_bytes', function()
+ insert([[
+function f()
+ asdf()
+ asdf()
+end
+-- comment]])
+
+ exec_lua(
+ [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (parameters) (arguments)] @fold')]]
+ )
+ parse('lua')
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ [4] = '1',
+ [5] = '0',
+ }, get_fold_levels())
+
+ command('1,4join')
+ poke_eventloop()
+
+ eq({
+ [1] = '0',
+ [2] = '0',
+ }, get_fold_levels())
+
+ feed('u')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ [4] = '1',
+ [5] = '0',
+ }, get_fold_levels())
+ end)
+
+ it('handles multiple folds that overlap at the end and start', function()
+ insert([[
+function f()
+ g(
+ function()
+ asdf()
+ end, function()
+ end
+ )
+end]])
+
+ exec_lua(
+ [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (function_definition) (parameters) (arguments)] @fold')]]
+ )
+ parse('lua')
+
+ -- If fold1.stop = fold2.start, then move fold1's stop up so that fold2.start gets proper level.
+ eq({
+ [1] = '>1',
+ [2] = '>2',
+ [3] = '>3',
+ [4] = '3',
+ [5] = '>3',
+ [6] = '3',
+ [7] = '2',
+ [8] = '1',
+ }, get_fold_levels())
+
+ command('1,8join')
+ feed('u')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '>2',
+ [3] = '>3',
+ [4] = '3',
+ [5] = '>3',
+ [6] = '3',
+ [7] = '2',
+ [8] = '1',
+ }, get_fold_levels())
+ end)
+
+ it('handles multiple folds that start at the same line', function()
+ insert([[
+function f(a)
+ if #(g({
+ k = v,
+ })) > 0 then
+ return
+ end
+end]])
+
+ exec_lua(
+ [[vim.treesitter.query.set('lua', 'folds', '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold')]]
+ )
+ parse('lua')
+
+ eq({
+ [1] = '>1',
+ [2] = '>3',
+ [3] = '3',
+ [4] = '3',
+ [5] = '2',
+ [6] = '2',
+ [7] = '1',
+ }, get_fold_levels())
+
+ command('2,6join')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ }, get_fold_levels())
+
+ feed('u')
+ poke_eventloop()
+
+ eq({
+ [1] = '>1',
+ [2] = '>3',
+ [3] = '3',
+ [4] = '3',
+ [5] = '2',
+ [6] = '2',
+ [7] = '1',
+ }, get_fold_levels())
+ end)
+
+ it('takes account of relevant options', function()
+ insert([[
+# h1
+t1
+## h2
+t2
+### h3
+t3]])
+
+ exec_lua([[vim.treesitter.query.set('markdown', 'folds', '(section) @fold')]])
+ parse('markdown')
+
+ command([[set foldminlines=2]])
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '>2',
+ [4] = '2',
+ [5] = '2',
+ [6] = '2',
+ }, get_fold_levels())
+
+ command([[set foldminlines=1 foldnestmax=1]])
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ [4] = '1',
+ [5] = '1',
+ [6] = '1',
+ }, get_fold_levels())
+ end)
+
+ it('updates folds in all windows', function()
local screen = Screen.new(60, 48)
screen:attach()
screen:set_default_attr_ids({
- [1] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue};
- [2] = {bold = true, foreground = Screen.colors.Blue1};
- [3] = {bold = true, reverse = true};
- [4] = {reverse = true};
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { bold = true, foreground = Screen.colors.Blue1 },
+ [3] = { bold = true, reverse = true },
+ [4] = { reverse = true },
})
- exec_lua([[vim.treesitter.get_parser(0, "c")]])
- command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=9]])
+ parse('c')
+ command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1]])
command('split')
insert(test_text)
- screen:expect{grid=[[
+ screen:expect {
+ grid = [[
{1:-}void ui_refresh(void) |
{1:│}{ |
{1:│} int width = INT_MAX, height = INT_MAX; |
@@ -157,10 +441,7 @@ void ui_refresh(void)
{1:3} } |
{1:2} } |
{1:│}^} |
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
+ {2:~ }|*4
{3:[No Name] [+] }|
{1:-}void ui_refresh(void) |
{1:│}{ |
@@ -181,16 +462,16 @@ void ui_refresh(void)
{1:3} } |
{1:2} } |
{1:│}} |
- {2:~ }|
- {2:~ }|
- {2:~ }|
+ {2:~ }|*3
{4:[No Name] [+] }|
|
- ]]}
+ ]],
+ }
command('1,2d')
- screen:expect{grid=[[
+ screen:expect {
+ grid = [[
{1: } ^int width = INT_MAX, height = INT_MAX; |
{1: } bool ext_widgets[kUIExtCount]; |
{1:-} for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
@@ -208,12 +489,7 @@ void ui_refresh(void)
{1:2} } |
{1:│} } |
{1: }} |
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
+ {2:~ }|*6
{3:[No Name] [+] }|
{1: } int width = INT_MAX, height = INT_MAX; |
{1: } bool ext_widgets[kUIExtCount]; |
@@ -232,19 +508,16 @@ void ui_refresh(void)
{1:2} } |
{1:│} } |
{1: }} |
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
+ {2:~ }|*5
{4:[No Name] [+] }|
|
- ]]}
-
+ ]],
+ }
feed([[O<C-u><C-r>"<BS><Esc>]])
- screen:expect{grid=[[
+ screen:expect {
+ grid = [[
{1:-}void ui_refresh(void) |
{1:│}^{ |
{1:│} int width = INT_MAX, height = INT_MAX; |
@@ -264,10 +537,7 @@ void ui_refresh(void)
{1:3} } |
{1:2} } |
{1:│}} |
- {2:~ }|
- {2:~ }|
- {2:~ }|
- {2:~ }|
+ {2:~ }|*4
{3:[No Name] [+] }|
{1:-}void ui_refresh(void) |
{1:│}{ |
@@ -288,21 +558,21 @@ void ui_refresh(void)
{1:3} } |
{1:2} } |
{1:│}} |
- {2:~ }|
- {2:~ }|
- {2:~ }|
+ {2:~ }|*3
{4:[No Name] [+] }|
|
- ]]}
-
+ ]],
+ }
end)
it("doesn't open folds in diff mode", function()
local screen = Screen.new(60, 36)
screen:attach()
- exec_lua([[vim.treesitter.get_parser(0, "c")]])
- command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=9]])
+ parse('c')
+ command(
+ [[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=9]]
+ )
insert(test_text)
command('16d')
@@ -312,7 +582,8 @@ void ui_refresh(void)
command('windo diffthis')
feed('do')
- screen:expect{grid=[[
+ screen:expect {
+ grid = [[
{1:+ }{2:+-- 9 lines: void ui_refresh(void)·······················}|
{1: } for (size_t i = 0; i < ui_count; i++) { |
{1: } UI *ui = uis[i]; |
@@ -324,12 +595,7 @@ void ui_refresh(void)
{1: } } |
{1: } } |
{1: }} |
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
+ {3:~ }|*6
{4:[No Name] [+] }|
{1:+ }{2:+-- 9 lines: void ui_refresh(void)·······················}|
{1: } for (size_t i = 0; i < ui_count; i++) { |
@@ -342,133 +608,70 @@ void ui_refresh(void)
{1: } ^} |
{1: } } |
{1: }} |
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
+ {3:~ }|*5
{5:[No Name] [+] }|
|
- ]], attr_ids={
- [1] = {background = Screen.colors.Grey, foreground = Screen.colors.Blue4};
- [2] = {background = Screen.colors.LightGrey, foreground = Screen.colors.Blue4};
- [3] = {foreground = Screen.colors.Blue, bold = true};
- [4] = {reverse = true};
- [5] = {reverse = true, bold = true};
- }}
- end)
-
-end)
-
-describe('treesitter foldtext', function()
- local test_text = [[
-void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *))
-{
- int width = INT_MAX, height = INT_MAX;
- bool ext_widgets[kUIExtCount];
- for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
- ext_widgets[i] = true;
- }
-
- bool inclusive = ui_override();
- for (size_t i = 0; i < ui_count; i++) {
- UI *ui = uis[i];
- width = MIN(ui->width, width);
- height = MIN(ui->height, height);
- foo = BAR(ui->bazaar, bazaar);
- for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
+ ]],
+ attr_ids = {
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.Blue4 },
+ [2] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Blue4 },
+ [3] = { foreground = Screen.colors.Blue, bold = true },
+ [4] = { reverse = true },
+ [5] = { reverse = true, bold = true },
+ },
}
- }
-}]]
- local screen
+ end)
- before_each(function()
- screen = Screen.new(60, 5)
+ it("doesn't open folds that are not touched", function()
+ local screen = Screen.new(40, 8)
screen:set_default_attr_ids({
- [0] = {foreground = Screen.colors.Blue, bold = true},
- [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
- [2] = {bold = true, background = Screen.colors.LightGray, foreground = Screen.colors.SeaGreen};
- [3] = {foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGray};
- [4] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGray};
- [5] = {bold = true, background = Screen.colors.LightGray, foreground = Screen.colors.Brown};
- [6] = {background = Screen.colors.Red1};
- [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Red};
- [8] = {foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red};
- [9] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.Red};
- [10] = {bold = true};
+ [1] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray },
+ [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray },
+ [3] = { foreground = Screen.colors.Blue1, bold = true },
+ [4] = { bold = true },
})
screen:attach()
- end)
- it('displays highlighted content', function()
- command([[set foldmethod=manual foldtext=v:lua.vim.treesitter.foldtext() updatetime=50]])
- insert(test_text)
- exec_lua([[vim.treesitter.get_parser(0, "c")]])
-
- feed('ggVGzf')
- screen:expect{grid=[[
- {2:^void}{1: }{3:qsort}{4:(}{2:void}{1: }{5:*}{3:base}{4:,}{1: }{2:size_t}{1: }{3:nel}{4:,}{1: }{2:size_t}{1: }{3:width}{4:,}{1: }{2:int}{1: }{4:(}{5:*}{3:compa}|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]]}
- end)
-
- it('handles deep nested captures', function()
- command([[set foldmethod=manual foldtext=v:lua.vim.treesitter.foldtext() updatetime=50]])
insert([[
-function FoldInfo.new()
- return setmetatable({
- start_counts = {},
- stop_counts = {},
- levels0 = {},
- levels = {},
- }, FoldInfo)
-end]])
- exec_lua([[vim.treesitter.get_parser(0, "lua")]])
-
- feed('ggjVGkzfgg')
- screen:expect{grid=[[
- ^function FoldInfo.new() |
- {1: }{5:return}{1: }{4:setmetatable({}{1:·····································}|
- end |
- {0:~ }|
- |
- ]]}
-
- command('hi! Visual guibg=Red')
- feed('GVgg')
- screen:expect{grid=[[
- ^f{6:unction FoldInfo.new()} |
- {7: }{8:return}{7: }{9:setmetatable({}{7:·····································}|
- {6:end} |
- {0:~ }|
- {10:-- VISUAL LINE --} |
- ]]}
-
- feed('10l<C-V>')
- screen:expect{grid=[[
- {6:function F}^oldInfo.new() |
- {7: }{8:return}{7: }{9:se}{4:tmetatable({}{1:·····································}|
- {6:end} |
- {0:~ }|
- {10:-- VISUAL BLOCK --} |
- ]]}
- end)
-
- it('falls back to default', function()
- command([[set foldmethod=manual foldtext=v:lua.vim.treesitter.foldtext()]])
- insert(test_text)
+# h1
+t1
+# h2
+t2]])
+ exec_lua([[vim.treesitter.query.set('markdown', 'folds', '(section) @fold')]])
+ parse('markdown')
+ command(
+ [[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=0]]
+ )
+
+ feed('ggzojo')
+ poke_eventloop()
+
+ screen:expect {
+ grid = [[
+ {1:-}# h1 |
+ {1:│}t1 |
+ {1:│}^ |
+ {1:+}{2:+-- 2 lines: # h2·····················}|
+ {3:~ }|*3
+ {4:-- INSERT --} |
+ ]],
+ }
- feed('ggVGzf')
- screen:expect{grid=[[
- {1:^+-- 19 lines: void qsort(void *base, size_t nel, size_t widt}|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]]}
+ feed('<Esc>u')
+ -- TODO(tomtomjhj): `u` spuriously opens the fold (#26499).
+ feed('zMggzo')
+
+ feed('dd')
+ poke_eventloop()
+
+ screen:expect {
+ grid = [[
+ {1:-}^t1 |
+ {1:-}# h2 |
+ {1:│}t2 |
+ {3:~ }|*4
+ 1 line less; before #2 {MATCH:.*}|
+ ]],
+ }
end)
end)