neovim

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

folding_range_spec.lua (34962B)


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