neovim

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

test_match.vim (14701B)


      1 " Test for :match, :2match, :3match, clearmatches(), getmatches(), matchadd(),
      2 " matchaddpos(), matcharg(), matchdelete(), and setmatches().
      3 
      4 source screendump.vim
      5 source check.vim
      6 
      7 function Test_match()
      8  highlight MyGroup1 term=bold ctermbg=red guibg=red
      9  highlight MyGroup2 term=italic ctermbg=green guibg=green
     10  highlight MyGroup3 term=underline ctermbg=blue guibg=blue
     11 
     12  " --- Check that "matcharg()" returns the correct group and pattern if a match
     13  " --- is defined.
     14  match MyGroup1 /TODO/
     15  2match MyGroup2 /FIXME/
     16  3match MyGroup3 /XXX/
     17  call assert_equal(['MyGroup1', 'TODO'], matcharg(1))
     18  call assert_equal(['MyGroup2', 'FIXME'], 2->matcharg())
     19  call assert_equal(['MyGroup3', 'XXX'], matcharg(3))
     20 
     21  " --- Check that "matcharg()" returns an empty list if the argument is not 1,
     22  " --- 2 or 3 (only 0 and 4 are tested).
     23  call assert_equal([], matcharg(0))
     24  call assert_equal([], matcharg(4))
     25 
     26  " --- Check that "matcharg()" returns ['', ''] if a match is not defined.
     27  match
     28  2match
     29  3match
     30  call assert_equal(['', ''], matcharg(1))
     31  call assert_equal(['', ''], matcharg(2))
     32  call assert_equal(['', ''], matcharg(3))
     33 
     34  " --- Check that "matchadd()" and "getmatches()" agree on added matches and
     35  " --- that default values apply.
     36  let m1 = matchadd("MyGroup1", "TODO")
     37  let m2 = matchadd("MyGroup2", "FIXME", 42)
     38  let m3 = matchadd("MyGroup3", "XXX", 60, 17)
     39  let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1000},
     40        \    {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 1001},
     41        \    {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
     42  call assert_equal(ans, getmatches())
     43 
     44  " --- Check that "matchdelete()" deletes the matches defined in the previous
     45  " --- test correctly.
     46  call matchdelete(m1)
     47  eval m2->matchdelete()
     48  call matchdelete(m3)
     49  call assert_equal([], getmatches())
     50 
     51  " --- Check that "matchdelete()" returns 0 if successful and otherwise -1.
     52  let m = matchadd("MyGroup1", "TODO")
     53  call assert_equal(0, matchdelete(m))
     54  call assert_fails('call matchdelete(42)', 'E803:')
     55 
     56  " --- Check that "clearmatches()" clears all matches defined by ":match" and
     57  " --- "matchadd()".
     58  let m1 = matchadd("MyGroup1", "TODO")
     59  let m2 = "MyGroup2"->matchadd("FIXME", 42)
     60  let m3 = matchadd("MyGroup3", "XXX", 60, 17)
     61  match MyGroup1 /COFFEE/
     62  2match MyGroup2 /HUMPPA/
     63  3match MyGroup3 /VIM/
     64  call clearmatches()
     65  call assert_equal([], getmatches())
     66 
     67  " --- Check that "setmatches()" restores a list of matches saved by
     68  " --- "getmatches()" without changes. (Matches with equal priority must also
     69  " --- remain in the same order.)
     70  let m1 = matchadd("MyGroup1", "TODO")
     71  let m2 = matchadd("MyGroup2", "FIXME", 42)
     72  let m3 = matchadd("MyGroup3", "XXX", 60, 17)
     73  match MyGroup1 /COFFEE/
     74  2match MyGroup2 /HUMPPA/
     75  3match MyGroup3 /VIM/
     76  let ml = getmatches()
     77  call clearmatches()
     78  call setmatches(ml)
     79  call assert_equal(ml, getmatches())
     80  call clearmatches()
     81 
     82  " --- Check that "setmatches()" will not add two matches with the same ID. The
     83  " --- expected behaviour (for now) is to add the first match but not the
     84  " --- second and to return 0 (even though it is a matter of debate whether
     85  " --- this can be considered successful behaviour).
     86  let data = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1},
     87        \    {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}]
     88  call assert_fails('call setmatches(data)', 'E801:')
     89  call assert_equal([data[0]], getmatches())
     90  call clearmatches()
     91 
     92  " --- Check that "setmatches()" returns 0 if successful and otherwise -1.
     93  " --- (A range of valid and invalid input values are tried out to generate the
     94  " --- return values.)
     95  call assert_equal(0, setmatches([]))
     96  call assert_equal(0, setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}]))
     97  call clearmatches()
     98  call assert_fails('call setmatches(0)', 'E714:')
     99  call assert_fails('call setmatches([0])', 'E474:')
    100  call assert_fails("call setmatches([{'wrong key': 'wrong value'}])", 'E474:')
    101 
    102  call setline(1, 'abcdefghijklmnopq')
    103  call matchaddpos("MyGroup1", [[1, 5], [1, 8, 3]], 10, 3)
    104  1
    105  redraw!
    106  let v1 = screenattr(1, 1)
    107  let v5 = screenattr(1, 5)
    108  let v6 = screenattr(1, 6)
    109  let v8 = screenattr(1, 8)
    110  let v10 = screenattr(1, 10)
    111  let v11 = screenattr(1, 11)
    112  call assert_notequal(v1, v5)
    113  call assert_equal(v6, v1)
    114  call assert_equal(v8, v5)
    115  call assert_equal(v10, v5)
    116  call assert_equal(v11, v1)
    117  call assert_equal([{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}], getmatches())
    118  call clearmatches()
    119 
    120  call setline(1, 'abcdΣabcdef')
    121  eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]], 10, 42)
    122  1
    123  redraw!
    124  let v1 = screenattr(1, 1)
    125  let v4 = screenattr(1, 4)
    126  let v5 = screenattr(1, 5)
    127  let v6 = screenattr(1, 6)
    128  let v7 = screenattr(1, 7)
    129  let v8 = screenattr(1, 8)
    130  let v9 = screenattr(1, 9)
    131  let v10 = screenattr(1, 10)
    132  call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
    133  call assert_notequal(v1, v4)
    134  call assert_equal(v5, v4)
    135  call assert_equal(v6, v1)
    136  call assert_equal(v7, v1)
    137  call assert_equal(v8, v4)
    138  call assert_equal(v9, v4)
    139  call assert_equal(v10, v1)
    140 
    141  " Check, that setmatches() can correctly restore the matches from matchaddpos()
    142  call matchadd('MyGroup1', '\%2lmatchadd')
    143  let m=getmatches()
    144  call clearmatches()
    145  call setmatches(m)
    146  call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 1106}], getmatches())
    147 
    148  highlight MyGroup1 NONE
    149  highlight MyGroup2 NONE
    150  highlight MyGroup3 NONE
    151 endfunc
    152 
    153 func Test_match_error()
    154  call assert_fails('match Error', 'E475:')
    155  call assert_fails('match Error /', 'E475:')
    156  call assert_fails('4match Error /x/', 'E476:')
    157  call assert_fails('match Error /x/ x', 'E488:')
    158 endfunc
    159 
    160 func Test_matchadd_error()
    161  call clearmatches()
    162  " Nvim: not an error anymore:
    163  " call assert_fails("call matchadd('GroupDoesNotExist', 'X')", 'E28:')
    164  call matchadd('GroupDoesNotExist', 'X')
    165  call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 1206}], getmatches())
    166  call assert_fails("call matchadd('Search', '\\(')", 'E54:')
    167  call assert_fails("call matchadd('Search', 'XXX', 1, 123, 1)", 'E715:')
    168  call assert_fails("call matchadd('Error', 'XXX', 1, 3)", 'E798:')
    169  call assert_fails("call matchadd('Error', 'XXX', 1, 0)", 'E799:')
    170  call assert_fails("call matchadd('Error', 'XXX', [], 0)", 'E745:')
    171 endfunc
    172 
    173 func Test_matchaddpos()
    174  syntax on
    175  set hlsearch
    176 
    177  call setline(1, ['12345', 'NP'])
    178  call matchaddpos('Error', [[1,2], [1,6], [2,2]])
    179  redraw!
    180  call assert_notequal(screenattr(2,2), 0)
    181  call assert_equal(screenattr(2,2), screenattr(1,2))
    182  call assert_notequal(screenattr(2,2), screenattr(1,6))
    183  1
    184  call matchadd('Search', 'N\|\n')
    185  redraw!
    186  call assert_notequal(screenattr(2,1), 0)
    187  call assert_equal(screenattr(2,1), screenattr(1,6))
    188  exec "norm! i0\<Esc>"
    189  redraw!
    190  call assert_equal(screenattr(2,2), screenattr(1,6))
    191 
    192  " Check overlapping pos
    193  call clearmatches()
    194  call setline(1, ['1234567890', 'NH'])
    195  call matchaddpos('Error', [[1,1,5], [1,3,5], [2,2]])
    196  redraw!
    197  call assert_notequal(screenattr(2,2), 0)
    198  call assert_equal(screenattr(2,2), screenattr(1,5))
    199  call assert_equal(screenattr(2,2), screenattr(1,7))
    200  call assert_notequal(screenattr(2,2), screenattr(1,8))
    201 
    202  call clearmatches()
    203  call matchaddpos('Error', [[1], [2,2]])
    204  redraw!
    205  call assert_equal(screenattr(2,2), screenattr(1,1))
    206  call assert_equal(screenattr(2,2), screenattr(1,10))
    207  call assert_notequal(screenattr(2,2), screenattr(1,11))
    208 
    209  " Check overlapping pos
    210  call clearmatches()
    211  call setline(1, ['1234567890', 'NH'])
    212  call matchaddpos('Error', [[1,1,5], [1,3,5], [2,2]])
    213  redraw!
    214  call assert_notequal(screenattr(2,2), 0)
    215  call assert_equal(screenattr(2,2), screenattr(1,5))
    216  call assert_equal(screenattr(2,2), screenattr(1,7))
    217  call assert_notequal(screenattr(2,2), screenattr(1,8))
    218 
    219  nohl
    220  call clearmatches()
    221  syntax off
    222  set hlsearch&
    223 endfunc
    224 
    225 " Add 12 match positions (previously the limit was 8 positions).
    226 func Test_matchaddpos_dump()
    227  CheckScreendump
    228 
    229  let lines =<< trim END
    230      call setline(1, ['1234567890123']->repeat(14))
    231      call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]}))
    232  END
    233  call writefile(lines, 'Xmatchaddpos', 'D')
    234  let buf = RunVimInTerminal('-S Xmatchaddpos', #{rows: 14})
    235  call VerifyScreenDump(buf, 'Test_matchaddpos_1', {})
    236 
    237  call StopVimInTerminal(buf)
    238 endfunc
    239 
    240 func Test_matchaddpos_otherwin()
    241  syntax on
    242  new
    243  call setline(1, ['12345', 'NP'])
    244  let winid = win_getid()
    245 
    246  wincmd w
    247  call matchadd('Search', '4', 10, -1, {'window': winid})
    248  call matchaddpos('Error', [[1,2], [2,2]], 10, -1, {'window': winid})
    249  redraw!
    250  call assert_notequal(screenattr(1,2), 0)
    251  call assert_notequal(screenattr(1,4), 0)
    252  call assert_notequal(screenattr(2,2), 0)
    253  call assert_equal(screenattr(1,2), screenattr(2,2))
    254  call assert_notequal(screenattr(1,2), screenattr(1,4))
    255 
    256  let savematches = getmatches(winid)
    257  let expect = [
    258        \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 1000},
    259        \ {'group': 'Error', 'id': 1001, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]},
    260        \]
    261  call assert_equal(expect, savematches)
    262 
    263  eval winid->clearmatches()
    264  call assert_equal([], getmatches(winid))
    265 
    266  call setmatches(savematches, winid)
    267  call assert_equal(expect, savematches)
    268 
    269  wincmd w
    270  bwipe!
    271  call clearmatches()
    272  syntax off
    273 endfunc
    274 
    275 func Test_matchaddpos_using_negative_priority()
    276  set hlsearch
    277 
    278  call clearmatches()
    279 
    280  call setline(1, 'x')
    281  let @/='x'
    282  redraw!
    283  let search_attr = screenattr(1,1)
    284 
    285  let @/=''
    286  call matchaddpos('Error', [1], 10)
    287  redraw!
    288  let error_attr = screenattr(1,1)
    289 
    290  call setline(2, '-1 match priority')
    291  call matchaddpos('Error', [2], -1)
    292  redraw!
    293  let negative_match_priority_attr = screenattr(2,1)
    294 
    295  call assert_notequal(negative_match_priority_attr, search_attr, "Match with negative priority is incorrectly highlighted with Search highlight.")
    296  call assert_equal(negative_match_priority_attr, error_attr)
    297 
    298  nohl
    299  set hlsearch&
    300 endfunc
    301 
    302 func Test_matchaddpos_error()
    303  call assert_fails("call matchaddpos('Error', 1)", 'E686:')
    304  call assert_fails("call matchaddpos('Error', [1], 1, 1)", 'E798:')
    305  call assert_fails("call matchaddpos('Error', [1], 1, 2)", 'E798:')
    306  call assert_fails("call matchaddpos('Error', [1], 1, 0)", 'E799:')
    307  call assert_fails("call matchaddpos('Error', [1], 1, 123, 1)", 'E715:')
    308  call assert_fails("call matchaddpos('Error', [1], 1, 5, {'window':12345})", 'E957:')
    309  " Why doesn't the following error have an error code E...?
    310  " call assert_fails("call matchaddpos('Error', [{}])", 'E290:')
    311  call assert_fails("call matchaddpos('Error', [{}])", 'E5031:')
    312  call assert_equal(-1, matchaddpos('Error', v:_null_list))
    313  call assert_equal(-1, matchaddpos('Error', []))
    314  call assert_fails("call matchaddpos('Error', [1], [], 1)", 'E745:')
    315 endfunc
    316 
    317 func OtherWindowCommon()
    318  let lines =<< trim END
    319    call setline(1, 'Hello Vim world')
    320    let mid = matchadd('Error', 'world', 1)
    321    let winid = win_getid()
    322    new
    323  END
    324  call writefile(lines, 'XscriptMatchCommon')
    325  let buf = RunVimInTerminal('-S XscriptMatchCommon', #{rows: 12})
    326  call TermWait(buf)
    327  return buf
    328 endfunc
    329 
    330 func Test_matchdelete_other_window()
    331  CheckScreendump
    332 
    333  let buf = OtherWindowCommon()
    334  call term_sendkeys(buf, ":call matchdelete(mid, winid)\<CR>")
    335  call VerifyScreenDump(buf, 'Test_matchdelete_1', {})
    336 
    337  call StopVimInTerminal(buf)
    338  call delete('XscriptMatchCommon')
    339 endfunc
    340 
    341 func Test_matchdelete_error()
    342  call assert_fails("call matchdelete(0)", 'E802:')
    343  call assert_fails("call matchdelete(1, -1)", 'E957:')
    344 endfunc
    345 
    346 func Test_matchclear_other_window()
    347  CheckScreendump
    348  CheckRunVimInTerminal
    349  let buf = OtherWindowCommon()
    350  call term_sendkeys(buf, ":call clearmatches(winid)\<CR>")
    351  call VerifyScreenDump(buf, 'Test_matchclear_1', {})
    352 
    353  call StopVimInTerminal(buf)
    354  call delete('XscriptMatchCommon')
    355 endfunc
    356 
    357 func Test_matchadd_other_window()
    358  CheckScreendump
    359  CheckRunVimInTerminal
    360  let buf = OtherWindowCommon()
    361  call term_sendkeys(buf, ":call matchadd('Search', 'Hello', 1, -1, #{window: winid})\<CR>")
    362  call term_sendkeys(buf, ":\<CR>")
    363  call VerifyScreenDump(buf, 'Test_matchadd_1', {})
    364 
    365  call StopVimInTerminal(buf)
    366  call delete('XscriptMatchCommon')
    367 endfunc
    368 
    369 func Test_match_in_linebreak()
    370  CheckScreendump
    371  CheckRunVimInTerminal
    372 
    373  let lines =<< trim END
    374    set breakindent linebreak breakat+=]
    375    call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1)
    376    call matchaddpos('ErrorMsg', [[1, 51]])
    377  END
    378  call writefile(lines, 'XscriptMatchLinebreak', 'D')
    379  let buf = RunVimInTerminal('-S XscriptMatchLinebreak', #{rows: 10})
    380  call VerifyScreenDump(buf, 'Test_match_linebreak', {})
    381 
    382  call StopVimInTerminal(buf)
    383 endfunc
    384 
    385 func Test_match_with_incsearch()
    386  CheckScreendump
    387  CheckRunVimInTerminal
    388 
    389  let lines =<< trim END
    390    set incsearch
    391    call setline(1, range(20))
    392    call matchaddpos('ErrorMsg', [3])
    393  END
    394  call writefile(lines, 'XmatchWithIncsearch', 'D')
    395  let buf = RunVimInTerminal('-S XmatchWithIncsearch', #{rows: 6})
    396  call VerifyScreenDump(buf, 'Test_match_with_incsearch_1', {})
    397 
    398  call term_sendkeys(buf, ":s/0")
    399  call VerifyScreenDump(buf, 'Test_match_with_incsearch_2', {})
    400 
    401  call term_sendkeys(buf, "\<CR>")
    402  call StopVimInTerminal(buf)
    403 endfunc
    404 
    405 " Test for deleting matches outside of the screen redraw top/bottom lines
    406 " This should cause a redraw of those lines.
    407 func Test_matchdelete_redraw()
    408  new
    409  call setline(1, range(1, 500))
    410  call cursor(250, 1)
    411  let m1 = matchaddpos('Search', [[250]])
    412  let m2 = matchaddpos('Search', [[10], [450]])
    413  redraw!
    414  let m3 = matchaddpos('Search', [[240], [260]])
    415  call matchdelete(m2)
    416  let m = getmatches()
    417  call assert_equal(2, len(m))
    418  call assert_equal([250], m[0].pos1)
    419  redraw!
    420  call matchdelete(m1)
    421  call assert_equal(1, len(getmatches()))
    422  bw!
    423 endfunc
    424 
    425 func Test_match_tab_with_linebreak()
    426  CheckScreendump
    427  CheckRunVimInTerminal
    428 
    429  let lines =<< trim END
    430    set linebreak
    431    call setline(1, "\tix")
    432    call matchadd('ErrorMsg', '\t')
    433  END
    434  call writefile(lines, 'XscriptMatchTabLinebreak', 'D')
    435  let buf = RunVimInTerminal('-S XscriptMatchTabLinebreak', #{rows: 10})
    436  call VerifyScreenDump(buf, 'Test_match_tab_linebreak', {})
    437 
    438  call StopVimInTerminal(buf)
    439 endfunc
    440 
    441 " vim: shiftwidth=2 sts=2 expandtab