folding_range_spec.lua 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local t_lsp = require('test.functional.plugin.lsp.testutil')
  5. local eq = t.eq
  6. local tempname = t.tmpname
  7. local clear_notrace = t_lsp.clear_notrace
  8. local create_server_definition = t_lsp.create_server_definition
  9. local api = n.api
  10. local exec_lua = n.exec_lua
  11. local insert = n.insert
  12. local command = n.command
  13. local feed = n.feed
  14. describe('vim.lsp.folding_range', function()
  15. local text = [[// foldLevel() {{{2
  16. /// @return fold level at line number "lnum" in the current window.
  17. static int foldLevel(linenr_T lnum)
  18. {
  19. // While updating the folds lines between invalid_top and invalid_bot have
  20. // an undefined fold level. Otherwise update the folds first.
  21. if (invalid_top == 0) {
  22. checkupdate(curwin);
  23. } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {
  24. return prev_lnum_lvl;
  25. } else if (lnum >= invalid_top && lnum <= invalid_bot) {
  26. return -1;
  27. }
  28. // Return quickly when there is no folding at all in this window.
  29. if (!hasAnyFolding(curwin)) {
  30. return 0;
  31. }
  32. return foldLevelWin(curwin, lnum);
  33. }]]
  34. local result = {
  35. {
  36. endLine = 19,
  37. kind = 'region',
  38. startCharacter = 1,
  39. startLine = 3,
  40. },
  41. {
  42. endCharacter = 2,
  43. endLine = 7,
  44. kind = 'region',
  45. startCharacter = 25,
  46. startLine = 6,
  47. },
  48. {
  49. endCharacter = 2,
  50. endLine = 9,
  51. kind = 'region',
  52. startCharacter = 55,
  53. startLine = 8,
  54. },
  55. {
  56. endCharacter = 2,
  57. endLine = 11,
  58. kind = 'region',
  59. startCharacter = 58,
  60. startLine = 10,
  61. },
  62. {
  63. endCharacter = 2,
  64. endLine = 16,
  65. kind = 'region',
  66. startCharacter = 31,
  67. startLine = 15,
  68. },
  69. {
  70. endCharacter = 68,
  71. endLine = 1,
  72. kind = 'comment',
  73. startCharacter = 2,
  74. startLine = 0,
  75. },
  76. {
  77. endCharacter = 64,
  78. endLine = 5,
  79. kind = 'comment',
  80. startCharacter = 4,
  81. startLine = 4,
  82. },
  83. }
  84. local bufnr ---@type integer
  85. local client_id ---@type integer
  86. clear_notrace()
  87. before_each(function()
  88. clear_notrace()
  89. exec_lua(create_server_definition)
  90. bufnr = n.api.nvim_get_current_buf()
  91. client_id = exec_lua(function()
  92. _G.server = _G._create_server({
  93. capabilities = {
  94. foldingRangeProvider = true,
  95. },
  96. handlers = {
  97. ['textDocument/foldingRange'] = function(_, _, callback)
  98. callback(nil, result)
  99. end,
  100. },
  101. })
  102. vim.api.nvim_win_set_buf(0, bufnr)
  103. return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
  104. end)
  105. command('set foldmethod=expr foldcolumn=1 foldlevel=999')
  106. insert(text)
  107. end)
  108. after_each(function()
  109. api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
  110. end)
  111. describe('setup()', function()
  112. ---@type integer
  113. local bufnr_set_expr
  114. ---@type integer
  115. local bufnr_never_set_expr
  116. local function buf_autocmd_num(bufnr_to_check)
  117. return exec_lua(function()
  118. return #vim.api.nvim_get_autocmds({ buffer = bufnr_to_check, event = 'LspNotify' })
  119. end)
  120. end
  121. before_each(function()
  122. command([[setlocal foldexpr=v:lua.vim.lsp.foldexpr()]])
  123. exec_lua(function()
  124. bufnr_set_expr = vim.api.nvim_create_buf(true, false)
  125. vim.api.nvim_set_current_buf(bufnr_set_expr)
  126. end)
  127. insert(text)
  128. command('write ' .. tempname(false))
  129. command([[setlocal foldexpr=v:lua.vim.lsp.foldexpr()]])
  130. exec_lua(function()
  131. bufnr_never_set_expr = vim.api.nvim_create_buf(true, false)
  132. vim.api.nvim_set_current_buf(bufnr_never_set_expr)
  133. end)
  134. insert(text)
  135. api.nvim_win_set_buf(0, bufnr_set_expr)
  136. end)
  137. it('only create event hooks where foldexpr has been set', function()
  138. eq(1, buf_autocmd_num(bufnr))
  139. eq(1, buf_autocmd_num(bufnr_set_expr))
  140. eq(0, buf_autocmd_num(bufnr_never_set_expr))
  141. end)
  142. it('does not create duplicate event hooks after reloaded', function()
  143. command('edit')
  144. eq(1, buf_autocmd_num(bufnr_set_expr))
  145. end)
  146. it('cleans up event hooks when buffer is unloaded', function()
  147. command('bdelete')
  148. eq(0, buf_autocmd_num(bufnr_set_expr))
  149. end)
  150. end)
  151. describe('expr()', function()
  152. --- @type test.functional.ui.screen
  153. local screen
  154. before_each(function()
  155. screen = Screen.new(80, 45)
  156. screen:set_default_attr_ids({
  157. [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
  158. [2] = { bold = true, foreground = Screen.colors.Blue1 },
  159. [3] = { bold = true, reverse = true },
  160. [4] = { reverse = true },
  161. })
  162. command([[set foldexpr=v:lua.vim.lsp.foldexpr()]])
  163. command([[split]])
  164. end)
  165. it('can compute fold levels', function()
  166. ---@type table<integer, string>
  167. local foldlevels = {}
  168. for i = 1, 21 do
  169. foldlevels[i] = exec_lua('return vim.lsp.foldexpr(' .. i .. ')')
  170. end
  171. eq({
  172. [1] = '>1',
  173. [2] = '<1',
  174. [3] = '0',
  175. [4] = '>1',
  176. [5] = '>2',
  177. [6] = '<2',
  178. [7] = '>2',
  179. [8] = '<2',
  180. [9] = '>2',
  181. [10] = '<2',
  182. [11] = '>2',
  183. [12] = '<2',
  184. [13] = '1',
  185. [14] = '1',
  186. [15] = '1',
  187. [16] = '>2',
  188. [17] = '<2',
  189. [18] = '1',
  190. [19] = '1',
  191. [20] = '<1',
  192. [21] = '0',
  193. }, foldlevels)
  194. end)
  195. it('updates folds in all windows', function()
  196. screen:expect({
  197. grid = [[
  198. {1:-}// foldLevel() {{{2 |
  199. {1:│}/// @return fold level at line number "lnum" in the current window. |
  200. {1: }static int foldLevel(linenr_T lnum) |
  201. {1:-}{ |
  202. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  203. {1:2} // an undefined fold level. Otherwise update the folds first. |
  204. {1:-} if (invalid_top == 0) { |
  205. {1:2} checkupdate(curwin); |
  206. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  207. {1:2} return prev_lnum_lvl; |
  208. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  209. {1:2} return -1; |
  210. {1:│} } |
  211. {1:│} |
  212. {1:│} // Return quickly when there is no folding at all in this window. |
  213. {1:-} if (!hasAnyFolding(curwin)) { |
  214. {1:2} return 0; |
  215. {1:│} } |
  216. {1:│} |
  217. {1:│} return foldLevelWin(curwin, lnum); |
  218. {1: }^} |
  219. {3:[No Name] [+] }|
  220. {1:-}// foldLevel() {{{2 |
  221. {1:│}/// @return fold level at line number "lnum" in the current window. |
  222. {1: }static int foldLevel(linenr_T lnum) |
  223. {1:-}{ |
  224. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  225. {1:2} // an undefined fold level. Otherwise update the folds first. |
  226. {1:-} if (invalid_top == 0) { |
  227. {1:2} checkupdate(curwin); |
  228. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  229. {1:2} return prev_lnum_lvl; |
  230. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  231. {1:2} return -1; |
  232. {1:│} } |
  233. {1:│} |
  234. {1:│} // Return quickly when there is no folding at all in this window. |
  235. {1:-} if (!hasAnyFolding(curwin)) { |
  236. {1:2} return 0; |
  237. {1:│} } |
  238. {1:│} |
  239. {1:│} return foldLevelWin(curwin, lnum); |
  240. {1: }} |
  241. {4:[No Name] [+] }|
  242. |
  243. ]],
  244. })
  245. end)
  246. it('persists wherever foldexpr is set', function()
  247. command([[setlocal foldexpr=]])
  248. feed('<C-w><C-w>zx')
  249. screen:expect({
  250. grid = [[
  251. {1: }// foldLevel() {{{2 |
  252. {1: }/// @return fold level at line number "lnum" in the current window. |
  253. {1: }static int foldLevel(linenr_T lnum) |
  254. {1: }{ |
  255. {1: } // While updating the folds lines between invalid_top and invalid_bot have |
  256. {1: } // an undefined fold level. Otherwise update the folds first. |
  257. {1: } if (invalid_top == 0) { |
  258. {1: } checkupdate(curwin); |
  259. {1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  260. {1: } return prev_lnum_lvl; |
  261. {1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  262. {1: } return -1; |
  263. {1: } } |
  264. {1: } |
  265. {1: } // Return quickly when there is no folding at all in this window. |
  266. {1: } if (!hasAnyFolding(curwin)) { |
  267. {1: } return 0; |
  268. {1: } } |
  269. {1: } |
  270. {1: } return foldLevelWin(curwin, lnum); |
  271. {1: }} |
  272. {4:[No Name] [+] }|
  273. {1:-}// foldLevel() {{{2 |
  274. {1:│}/// @return fold level at line number "lnum" in the current window. |
  275. {1: }static int foldLevel(linenr_T lnum) |
  276. {1:-}{ |
  277. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  278. {1:2} // an undefined fold level. Otherwise update the folds first. |
  279. {1:-} if (invalid_top == 0) { |
  280. {1:2} checkupdate(curwin); |
  281. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  282. {1:2} return prev_lnum_lvl; |
  283. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  284. {1:2} return -1; |
  285. {1:│} } |
  286. {1:│} |
  287. {1:│} // Return quickly when there is no folding at all in this window. |
  288. {1:-} if (!hasAnyFolding(curwin)) { |
  289. {1:2} return 0; |
  290. {1:│} } |
  291. {1:│} |
  292. {1:│} return foldLevelWin(curwin, lnum); |
  293. {1: }^} |
  294. {3:[No Name] [+] }|
  295. |
  296. ]],
  297. })
  298. end)
  299. it('synchronizes changed rows with their previous foldlevels', function()
  300. command('1,2d')
  301. screen:expect({
  302. grid = [[
  303. {1: }^static int foldLevel(linenr_T lnum) |
  304. {1:-}{ |
  305. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  306. {1:2} // an undefined fold level. Otherwise update the folds first. |
  307. {1:-} if (invalid_top == 0) { |
  308. {1:2} checkupdate(curwin); |
  309. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  310. {1:2} return prev_lnum_lvl; |
  311. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  312. {1:2} return -1; |
  313. {1:│} } |
  314. {1:│} |
  315. {1:│} // Return quickly when there is no folding at all in this window. |
  316. {1:-} if (!hasAnyFolding(curwin)) { |
  317. {1:2} return 0; |
  318. {1:│} } |
  319. {1:│} |
  320. {1:│} return foldLevelWin(curwin, lnum); |
  321. {1: }} |
  322. {2:~ }|*2
  323. {3:[No Name] [+] }|
  324. {1: }static int foldLevel(linenr_T lnum) |
  325. {1:-}{ |
  326. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  327. {1:2} // an undefined fold level. Otherwise update the folds first. |
  328. {1:-} if (invalid_top == 0) { |
  329. {1:2} checkupdate(curwin); |
  330. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  331. {1:2} return prev_lnum_lvl; |
  332. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  333. {1:2} return -1; |
  334. {1:│} } |
  335. {1:│} |
  336. {1:│} // Return quickly when there is no folding at all in this window. |
  337. {1:-} if (!hasAnyFolding(curwin)) { |
  338. {1:2} return 0; |
  339. {1:│} } |
  340. {1:│} |
  341. {1:│} return foldLevelWin(curwin, lnum); |
  342. {1: }} |
  343. {2:~ }|*2
  344. {4:[No Name] [+] }|
  345. |
  346. ]],
  347. })
  348. end)
  349. it('clears folds when sole client detaches', function()
  350. exec_lua(function()
  351. vim.lsp.buf_detach_client(bufnr, client_id)
  352. end)
  353. screen:expect({
  354. grid = [[
  355. {1: }// foldLevel() {{{2 |
  356. {1: }/// @return fold level at line number "lnum" in the current window. |
  357. {1: }static int foldLevel(linenr_T lnum) |
  358. {1: }{ |
  359. {1: } // While updating the folds lines between invalid_top and invalid_bot have |
  360. {1: } // an undefined fold level. Otherwise update the folds first. |
  361. {1: } if (invalid_top == 0) { |
  362. {1: } checkupdate(curwin); |
  363. {1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  364. {1: } return prev_lnum_lvl; |
  365. {1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  366. {1: } return -1; |
  367. {1: } } |
  368. {1: } |
  369. {1: } // Return quickly when there is no folding at all in this window. |
  370. {1: } if (!hasAnyFolding(curwin)) { |
  371. {1: } return 0; |
  372. {1: } } |
  373. {1: } |
  374. {1: } return foldLevelWin(curwin, lnum); |
  375. {1: }^} |
  376. {3:[No Name] [+] }|
  377. {1: }// foldLevel() {{{2 |
  378. {1: }/// @return fold level at line number "lnum" in the current window. |
  379. {1: }static int foldLevel(linenr_T lnum) |
  380. {1: }{ |
  381. {1: } // While updating the folds lines between invalid_top and invalid_bot have |
  382. {1: } // an undefined fold level. Otherwise update the folds first. |
  383. {1: } if (invalid_top == 0) { |
  384. {1: } checkupdate(curwin); |
  385. {1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  386. {1: } return prev_lnum_lvl; |
  387. {1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  388. {1: } return -1; |
  389. {1: } } |
  390. {1: } |
  391. {1: } // Return quickly when there is no folding at all in this window. |
  392. {1: } if (!hasAnyFolding(curwin)) { |
  393. {1: } return 0; |
  394. {1: } } |
  395. {1: } |
  396. {1: } return foldLevelWin(curwin, lnum); |
  397. {1: }} |
  398. {4:[No Name] [+] }|
  399. |
  400. ]],
  401. })
  402. end)
  403. it('remains valid after the client re-attaches.', function()
  404. exec_lua(function()
  405. vim.lsp.buf_detach_client(bufnr, client_id)
  406. vim.lsp.buf_attach_client(bufnr, client_id)
  407. end)
  408. screen:expect({
  409. grid = [[
  410. {1:-}// foldLevel() {{{2 |
  411. {1:│}/// @return fold level at line number "lnum" in the current window. |
  412. {1: }static int foldLevel(linenr_T lnum) |
  413. {1:-}{ |
  414. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  415. {1:2} // an undefined fold level. Otherwise update the folds first. |
  416. {1:-} if (invalid_top == 0) { |
  417. {1:2} checkupdate(curwin); |
  418. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  419. {1:2} return prev_lnum_lvl; |
  420. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  421. {1:2} return -1; |
  422. {1:│} } |
  423. {1:│} |
  424. {1:│} // Return quickly when there is no folding at all in this window. |
  425. {1:-} if (!hasAnyFolding(curwin)) { |
  426. {1:2} return 0; |
  427. {1:│} } |
  428. {1:│} |
  429. {1:│} return foldLevelWin(curwin, lnum); |
  430. {1: }^} |
  431. {3:[No Name] [+] }|
  432. {1:-}// foldLevel() {{{2 |
  433. {1:│}/// @return fold level at line number "lnum" in the current window. |
  434. {1: }static int foldLevel(linenr_T lnum) |
  435. {1:-}{ |
  436. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  437. {1:2} // an undefined fold level. Otherwise update the folds first. |
  438. {1:-} if (invalid_top == 0) { |
  439. {1:2} checkupdate(curwin); |
  440. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  441. {1:2} return prev_lnum_lvl; |
  442. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  443. {1:2} return -1; |
  444. {1:│} } |
  445. {1:│} |
  446. {1:│} // Return quickly when there is no folding at all in this window. |
  447. {1:-} if (!hasAnyFolding(curwin)) { |
  448. {1:2} return 0; |
  449. {1:│} } |
  450. {1:│} |
  451. {1:│} return foldLevelWin(curwin, lnum); |
  452. {1: }} |
  453. {4:[No Name] [+] }|
  454. |
  455. ]],
  456. })
  457. end)
  458. end)
  459. describe('foldtext()', function()
  460. --- @type test.functional.ui.screen
  461. local screen
  462. before_each(function()
  463. screen = Screen.new(80, 23)
  464. screen:set_default_attr_ids({
  465. [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
  466. [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
  467. [3] = { bold = true, foreground = Screen.colors.Blue1 },
  468. [4] = { bold = true, reverse = true },
  469. [5] = { reverse = true },
  470. })
  471. command(
  472. [[set foldexpr=v:lua.vim.lsp.foldexpr() foldtext=v:lua.vim.lsp.foldtext() foldlevel=1]]
  473. )
  474. end)
  475. it('shows the first folded line if `collapsedText` does not exist', function()
  476. screen:expect({
  477. grid = [[
  478. {1:-}// foldLevel() {{{2 |
  479. {1:│}/// @return fold level at line number "lnum" in the current window. |
  480. {1: }static int foldLevel(linenr_T lnum) |
  481. {1:-}{ |
  482. {1:+}{2: // While updating the folds lines between invalid_top and invalid_bot have···}|
  483. {1:+}{2: if (invalid_top == 0) {······················································}|
  484. {1:+}{2: } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {························}|
  485. {1:+}{2: } else if (lnum >= invalid_top && lnum <= invalid_bot) {·····················}|
  486. {1:│} } |
  487. {1:│} |
  488. {1:│} // Return quickly when there is no folding at all in this window. |
  489. {1:+}{2: if (!hasAnyFolding(curwin)) {················································}|
  490. {1:│} } |
  491. {1:│} |
  492. {1:│} return foldLevelWin(curwin, lnum); |
  493. {1: }^} |
  494. {3:~ }|*6
  495. |
  496. ]],
  497. })
  498. end)
  499. end)
  500. describe('foldclose()', function()
  501. --- @type test.functional.ui.screen
  502. local screen
  503. before_each(function()
  504. screen = Screen.new(80, 23)
  505. screen:set_default_attr_ids({
  506. [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
  507. [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
  508. [3] = { bold = true, foreground = Screen.colors.Blue1 },
  509. [4] = { bold = true, reverse = true },
  510. [5] = { reverse = true },
  511. })
  512. command([[set foldexpr=v:lua.vim.lsp.foldexpr()]])
  513. end)
  514. it('closes all folds of one kind immediately', function()
  515. exec_lua(function()
  516. vim.lsp.foldclose('comment')
  517. end)
  518. screen:expect({
  519. grid = [[
  520. {1:+}{2:+-- 2 lines: foldLevel()······················································}|
  521. {1: }static int foldLevel(linenr_T lnum) |
  522. {1:-}{ |
  523. {1:+}{2:+--- 2 lines: While updating the folds lines between invalid_top and invalid_b}|
  524. {1:-} if (invalid_top == 0) { |
  525. {1:2} checkupdate(curwin); |
  526. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  527. {1:2} return prev_lnum_lvl; |
  528. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  529. {1:2} return -1; |
  530. {1:│} } |
  531. {1:│} |
  532. {1:│} // Return quickly when there is no folding at all in this window. |
  533. {1:-} if (!hasAnyFolding(curwin)) { |
  534. {1:2} return 0; |
  535. {1:│} } |
  536. {1:│} |
  537. {1:│} return foldLevelWin(curwin, lnum); |
  538. {1: }^} |
  539. {3:~ }|*3
  540. |
  541. ]],
  542. })
  543. end)
  544. it('closes the smallest fold first', function()
  545. exec_lua(function()
  546. vim.lsp.foldclose('region')
  547. end)
  548. screen:expect({
  549. grid = [[
  550. {1:-}// foldLevel() {{{2 |
  551. {1:│}/// @return fold level at line number "lnum" in the current window. |
  552. {1: }static int foldLevel(linenr_T lnum) |
  553. {1:+}{2:+-- 17 lines: {································································}|
  554. {1: }^} |
  555. {3:~ }|*17
  556. |
  557. ]],
  558. })
  559. command('4foldopen')
  560. screen:expect({
  561. grid = [[
  562. {1:-}// foldLevel() {{{2 |
  563. {1:│}/// @return fold level at line number "lnum" in the current window. |
  564. {1: }static int foldLevel(linenr_T lnum) |
  565. {1:-}{ |
  566. {1:-} // While updating the folds lines between invalid_top and invalid_bot have |
  567. {1:2} // an undefined fold level. Otherwise update the folds first. |
  568. {1:+}{2:+--- 2 lines: if (invalid_top == 0) {·········································}|
  569. {1:+}{2:+--- 2 lines: } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {···········}|
  570. {1:+}{2:+--- 2 lines: } else if (lnum >= invalid_top && lnum <= invalid_bot) {········}|
  571. {1:│} } |
  572. {1:│} |
  573. {1:│} // Return quickly when there is no folding at all in this window. |
  574. {1:+}{2:+--- 2 lines: if (!hasAnyFolding(curwin)) {···································}|
  575. {1:│} } |
  576. {1:│} |
  577. {1:│} return foldLevelWin(curwin, lnum); |
  578. {1: }^} |
  579. {3:~ }|*5
  580. |
  581. ]],
  582. })
  583. end)
  584. it('is defered when the buffer is not up-to-date', function()
  585. exec_lua(function()
  586. vim.lsp.foldclose('comment')
  587. vim.lsp.util.buf_versions[bufnr] = 0
  588. end)
  589. screen:expect({
  590. grid = [[
  591. {1:+}{2:+-- 2 lines: foldLevel()······················································}|
  592. {1: }static int foldLevel(linenr_T lnum) |
  593. {1:-}{ |
  594. {1:+}{2:+--- 2 lines: While updating the folds lines between invalid_top and invalid_b}|
  595. {1:-} if (invalid_top == 0) { |
  596. {1:2} checkupdate(curwin); |
  597. {1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
  598. {1:2} return prev_lnum_lvl; |
  599. {1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
  600. {1:2} return -1; |
  601. {1:│} } |
  602. {1:│} |
  603. {1:│} // Return quickly when there is no folding at all in this window. |
  604. {1:-} if (!hasAnyFolding(curwin)) { |
  605. {1:2} return 0; |
  606. {1:│} } |
  607. {1:│} |
  608. {1:│} return foldLevelWin(curwin, lnum); |
  609. {1: }^} |
  610. {3:~ }|*3
  611. |
  612. ]],
  613. })
  614. end)
  615. end)
  616. end)