neovim

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

fold_spec.lua (9421B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 
      4 local clear = n.clear
      5 local insert = n.insert
      6 local exec = n.exec
      7 local feed = n.feed
      8 local expect = n.expect
      9 local command = n.command
     10 local fn = n.fn
     11 local eq = t.eq
     12 local neq = t.neq
     13 
     14 describe('Folding', function()
     15  local tempfname = 'Xtest-fold.txt'
     16 
     17  setup(clear)
     18  before_each(function()
     19    command('bwipe! | new')
     20  end)
     21  after_each(function()
     22    os.remove(tempfname)
     23  end)
     24 
     25  it('manual folding adjusts with filter', function()
     26    insert([[
     27    1
     28    2
     29    3
     30    4
     31    5
     32    6
     33    7
     34    8
     35    9
     36    10
     37    11
     38    12
     39    13
     40    14
     41    15
     42    16
     43    17
     44    18
     45    19
     46    20]])
     47    command('4,$fold')
     48    command('%foldopen')
     49    command('10,$fold')
     50    command('%foldopen')
     51    command('1,8! cat')
     52    feed('5ggzdzMGdd')
     53    expect([[
     54    1
     55    2
     56    3
     57    4
     58    5
     59    6
     60    7
     61    8
     62    9]])
     63  end)
     64 
     65  describe('adjusting folds after :move', function()
     66    local function manually_fold_indent()
     67      -- setting foldmethod twice is a trick to get vim to set the folds for me
     68      command('setlocal foldmethod=indent')
     69      command('setlocal foldmethod=manual')
     70      -- Ensure that all folds will get closed (makes it easier to test the
     71      -- length of folds).
     72      command('setlocal foldminlines=0')
     73      -- Start with all folds open (so :move ranges aren't affected by closed
     74      -- folds).
     75      command('%foldopen!')
     76    end
     77 
     78    local function get_folds()
     79      local rettab = {}
     80      for i = 1, fn.line('$') do
     81        table.insert(rettab, fn.foldlevel(i))
     82      end
     83      return rettab
     84    end
     85 
     86    local function test_move_indent(insert_string, move_command)
     87      -- This test is easy because we just need to ensure that the resulting
     88      -- fold is the same as calculated when creating folds from scratch.
     89      insert(insert_string)
     90      command(move_command)
     91      local after_move_folds = get_folds()
     92      -- Doesn't change anything, but does call foldUpdateAll()
     93      command('setlocal foldminlines=0')
     94      eq(after_move_folds, get_folds())
     95      -- Set up the buffer with insert_string for the manual fold testing.
     96      command('enew!')
     97      insert(insert_string)
     98      manually_fold_indent()
     99      command(move_command)
    100    end
    101 
    102    it('neither closes nor corrupts folds', function()
    103      test_move_indent(
    104        [[
    105 a
    106 a
    107 a
    108 a
    109 a
    110 a
    111 a
    112 a
    113 a
    114 	a
    115 a
    116 a
    117 a
    118 a
    119 a
    120 a
    121 a
    122 a]],
    123        '7,12m0'
    124      )
    125      expect([[
    126 a
    127 a
    128 a
    129 	a
    130 a
    131 a
    132 a
    133 a
    134 a
    135 a
    136 a
    137 a
    138 a
    139 a
    140 a
    141 a
    142 a
    143 a]])
    144      -- lines are not closed, folds are correct
    145      for i = 1, fn.line('$') do
    146        eq(-1, fn.foldclosed(i))
    147        if i == 1 or i == 7 or i == 13 then
    148          eq(0, fn.foldlevel(i))
    149        elseif i == 4 then
    150          eq(2, fn.foldlevel(i))
    151        else
    152          eq(1, fn.foldlevel(i))
    153        end
    154      end
    155      -- folds are not corrupted
    156      feed('zM')
    157      eq(6, fn.foldclosedend(2))
    158      eq(12, fn.foldclosedend(8))
    159      eq(18, fn.foldclosedend(14))
    160    end)
    161 
    162    it("doesn't split a fold when the move is within it", function()
    163      test_move_indent(
    164        [[
    165 a
    166 a
    167 a
    168 	a
    169 	a
    170 	a
    171 	a
    172 a
    173 a
    174 a]],
    175        '5m6'
    176      )
    177      eq({ 0, 1, 1, 2, 2, 2, 2, 1, 1, 0 }, get_folds())
    178    end)
    179 
    180    it('truncates folds that end in the moved range', function()
    181      test_move_indent(
    182        [[
    183 a
    184 a
    185 	a
    186 	a
    187 	a
    188 a
    189 a]],
    190        '4,5m6'
    191      )
    192      eq({ 0, 1, 2, 0, 0, 0, 0 }, get_folds())
    193    end)
    194 
    195    it('moves folds that start between moved range and destination', function()
    196      test_move_indent(
    197        [[
    198 a
    199 a
    200 a
    201 a
    202 a
    203 a
    204 a
    205 a
    206 	a
    207 a
    208 a
    209 a
    210 a]],
    211        '3,4m$'
    212      )
    213      eq({ 0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0 }, get_folds())
    214    end)
    215 
    216    it('does not affect folds outside changed lines', function()
    217      test_move_indent(
    218        [[
    219 a
    220 a
    221 a
    222 a
    223 a
    224 a
    225 a
    226 a
    227 a]],
    228        '4m5'
    229      )
    230      eq({ 1, 1, 1, 0, 0, 0, 1, 1, 1 }, get_folds())
    231    end)
    232 
    233    it('moves and truncates folds that start in moved range', function()
    234      test_move_indent(
    235        [[
    236 a
    237 a
    238 	a
    239 	a
    240 	a
    241 a
    242 a
    243 a
    244 a
    245 a]],
    246        '1,3m7'
    247      )
    248      eq({ 0, 0, 0, 0, 0, 1, 2, 0, 0, 0 }, get_folds())
    249    end)
    250 
    251    it('breaks a fold when moving text into it', function()
    252      test_move_indent(
    253        [[
    254 a
    255 a
    256 	a
    257 	a
    258 	a
    259 a
    260 a]],
    261        '$m4'
    262      )
    263      eq({ 0, 1, 2, 2, 0, 0, 0 }, get_folds())
    264    end)
    265 
    266    it('adjusts correctly when moving a range backwards', function()
    267      test_move_indent(
    268        [[
    269 a
    270 a
    271 	a
    272 	a
    273 a]],
    274        '2,3m0'
    275      )
    276      eq({ 1, 2, 0, 0, 0 }, get_folds())
    277    end)
    278 
    279    it('handles shifting all remaining folds', function()
    280      test_move_indent(
    281        [[
    282 a
    283 	a
    284 	a
    285 	a
    286 a
    287 	a
    288 	a
    289 	a
    290 a
    291 	a
    292 	a
    293 	a
    294 	a
    295 a
    296 a]],
    297        '13m7'
    298      )
    299      eq({ 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0 }, get_folds())
    300    end)
    301  end)
    302 
    303  it('updates correctly on :read', function()
    304    -- luacheck: ignore 621
    305    t.write_file(
    306      tempfname,
    307      [[
    308    a
    309 
    310 
    311    	a]]
    312    )
    313    insert([[
    314    	a
    315    	a
    316    	a
    317    	a
    318    ]])
    319    command('setlocal foldmethod=indent')
    320    command('2')
    321    command('%foldopen')
    322    command('read ' .. tempfname)
    323    -- Just to check we have the correct file text.
    324    expect([[
    325    	a
    326    	a
    327    a
    328 
    329 
    330    	a
    331    	a
    332    	a
    333    ]])
    334    for i = 1, 2 do
    335      eq(1, fn.foldlevel(i))
    336    end
    337    for i = 3, 5 do
    338      eq(0, fn.foldlevel(i))
    339    end
    340    for i = 6, 8 do
    341      eq(1, fn.foldlevel(i))
    342    end
    343  end)
    344 
    345  it('combines folds when removing separating space', function()
    346    -- luacheck: ignore 621
    347    insert([[
    348    	a
    349    	a
    350    a
    351    a
    352    a
    353    	a
    354    	a
    355    	a
    356    ]])
    357    command('setlocal foldmethod=indent')
    358    command('3,5d')
    359    eq(5, fn.foldclosedend(1))
    360  end)
    361 
    362  it("doesn't combine folds that have a specified end", function()
    363    insert([[
    364    {{{
    365    }}}
    366 
    367 
    368 
    369    {{{
    370 
    371    }}}
    372    ]])
    373    command('setlocal foldmethod=marker')
    374    command('3,5d')
    375    command('%foldclose')
    376    eq(2, fn.foldclosedend(1))
    377  end)
    378 
    379  it('splits folds according to >N and <N with foldexpr', function()
    380    n.source([[
    381    function TestFoldExpr(lnum)
    382      let thisline = getline(a:lnum)
    383      if thisline == 'a'
    384        return 1
    385      elseif thisline == 'b'
    386        return 0
    387      elseif thisline == 'c'
    388        return '<1'
    389      elseif thisline == 'd'
    390        return '>1'
    391      endif
    392      return 0
    393    endfunction
    394    ]])
    395    t.write_file(
    396      tempfname,
    397      [[
    398    b
    399    b
    400    a
    401    a
    402    d
    403    a
    404    a
    405    c]]
    406    )
    407    insert([[
    408    a
    409    a
    410    a
    411    a
    412    a
    413    a
    414    ]])
    415    command('setlocal foldmethod=expr foldexpr=TestFoldExpr(v:lnum)')
    416    command('2')
    417    command('foldopen')
    418    command('read ' .. tempfname)
    419    command('%foldclose')
    420    eq(2, fn.foldclosedend(1))
    421    eq(0, fn.foldlevel(3))
    422    eq(0, fn.foldlevel(4))
    423    eq(6, fn.foldclosedend(5))
    424    eq(10, fn.foldclosedend(7))
    425    eq(14, fn.foldclosedend(11))
    426  end)
    427 
    428  it('fdm=expr works correctly with :move #18668', function()
    429    exec([[
    430      set foldmethod=expr foldexpr=indent(v:lnum)
    431      let content = ['', '', 'Line1', '  Line2', '  Line3',
    432            \ 'Line4', '  Line5', '  Line6',
    433            \ 'Line7', '  Line8', '  Line9']
    434      call append(0, content)
    435      normal! zM
    436      call cursor(4, 1)
    437      move 2
    438      move 1
    439    ]])
    440    expect([[
    441 
    442      Line2
    443      Line3
    444 
    445    Line1
    446    Line4
    447      Line5
    448      Line6
    449    Line7
    450      Line8
    451      Line9
    452    ]])
    453    eq(0, fn.foldlevel(1))
    454    eq(3, fn.foldclosedend(2))
    455    eq(0, fn.foldlevel(4))
    456    eq(0, fn.foldlevel(5))
    457    eq(0, fn.foldlevel(6))
    458    eq(8, fn.foldclosedend(7))
    459    eq(0, fn.foldlevel(9))
    460    eq(11, fn.foldclosedend(10))
    461    eq(0, fn.foldlevel(12))
    462  end)
    463 
    464  it('no folds remain if :delete makes buffer empty #19671', function()
    465    command('setlocal foldmethod=manual')
    466    fn.setline(1, { 'foo', 'bar', 'baz' })
    467    command('2,3fold')
    468    command('%delete')
    469    eq(0, fn.foldlevel(1))
    470  end)
    471 
    472  it('multibyte fold markers work #20438', function()
    473    command('setlocal foldmethod=marker foldmarker=«,» commentstring=/*%s*/')
    474    insert([[
    475      bbbbb
    476      bbbbb
    477      bbbbb]])
    478    feed('zfgg')
    479    expect([[
    480      bbbbb/*«*/
    481      bbbbb
    482      bbbbb/*»*/]])
    483    eq(1, fn.foldlevel(1))
    484  end)
    485 
    486  it('fdm=indent updates correctly with visual blockwise insertion #22898', function()
    487    insert([[
    488    a
    489    b
    490    ]])
    491    command('setlocal foldmethod=indent shiftwidth=2')
    492    feed('gg0<C-v>jI  <Esc>') -- indent both lines using visual blockwise mode
    493    eq(1, fn.foldlevel(1))
    494    eq(1, fn.foldlevel(2))
    495  end)
    496 
    497  it("fdm=indent doesn't open folds when inserting lower foldlevel line", function()
    498    insert([[
    499        insert an unindented line under this line
    500        keep the lines under this line folded
    501          keep this line folded 1
    502          keep this line folded 2
    503 
    504      .
    505    ]])
    506    command('set foldmethod=indent shiftwidth=2 noautoindent')
    507    eq(1, fn.foldlevel(1))
    508    eq(1, fn.foldlevel(2))
    509    eq(2, fn.foldlevel(3))
    510    eq(2, fn.foldlevel(4))
    511 
    512    feed('zo') -- open the outer fold
    513    neq(-1, fn.foldclosed(3)) -- make sure the inner fold is not open
    514 
    515    feed('gg0oa<Esc>') -- insert unindented line
    516 
    517    eq(1, fn.foldlevel(1)) --|  insert an unindented line under this line
    518    eq(0, fn.foldlevel(2)) --|a
    519    eq(1, fn.foldlevel(3)) --|  keep the lines under this line folded
    520    eq(2, fn.foldlevel(4)) --|    keep this line folded 1
    521    eq(2, fn.foldlevel(5)) --|    keep this line folded 2
    522 
    523    neq(-1, fn.foldclosed(4)) -- make sure the inner fold is still not open
    524  end)
    525 end)