neovim

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

wildmode_spec.lua (21119B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 local Screen = require('test.functional.ui.screen')
      4 
      5 local clear, feed, command = n.clear, n.feed, n.command
      6 local fn = n.fn
      7 local api = n.api
      8 local eq = t.eq
      9 local eval = n.eval
     10 local retry = t.retry
     11 local testprg = n.testprg
     12 local is_os = t.is_os
     13 
     14 describe("'wildmenu'", function()
     15  local screen
     16  before_each(function()
     17    clear()
     18    screen = Screen.new(25, 5)
     19    screen:add_extra_attr_ids {
     20      [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
     21    }
     22  end)
     23 
     24  -- oldtest: Test_wildmenu_screendump()
     25  it('works', function()
     26    screen:add_extra_attr_ids {
     27      [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
     28    }
     29    -- Test simple wildmenu
     30    feed(':sign <Tab>')
     31    screen:expect {
     32      grid = [[
     33                               |
     34      {1:~                        }|*2
     35      {100:define}{3:  jump  list  >    }|
     36      :sign define^             |
     37    ]],
     38    }
     39 
     40    feed('<Tab>')
     41    screen:expect {
     42      grid = [[
     43                               |
     44      {1:~                        }|*2
     45      {3:define  }{100:jump}{3:  list  >    }|
     46      :sign jump^               |
     47    ]],
     48    }
     49 
     50    feed('<Tab>')
     51    screen:expect {
     52      grid = [[
     53                               |
     54      {1:~                        }|*2
     55      {3:define  jump  }{100:list}{3:  >    }|
     56      :sign list^               |
     57    ]],
     58    }
     59 
     60    -- Looped back to the original value
     61    feed('<Tab><Tab><Tab><Tab>')
     62    screen:expect {
     63      grid = [[
     64                               |
     65      {1:~                        }|*2
     66      {3:define  jump  list  >    }|
     67      :sign ^                   |
     68    ]],
     69    }
     70 
     71    -- Test that the wild menu is cleared properly
     72    feed('<Space>')
     73    screen:expect {
     74      grid = [[
     75                               |
     76      {1:~                        }|*3
     77      :sign  ^                  |
     78    ]],
     79    }
     80 
     81    -- Test that a different wildchar still works
     82    feed('<Esc>')
     83    command('set wildchar=<Esc>')
     84    feed(':sign <Esc>')
     85    screen:expect {
     86      grid = [[
     87                               |
     88      {1:~                        }|*2
     89      {100:define}{3:  jump  list  >    }|
     90      :sign define^             |
     91    ]],
     92    }
     93 
     94    -- Double-<Esc> is a hard-coded method to escape while wildchar=<Esc>. Make
     95    -- sure clean up is properly done in edge case like this.
     96    feed('<Esc>')
     97    screen:expect {
     98      grid = [[
     99      ^                         |
    100      {1:~                        }|*3
    101                               |
    102    ]],
    103    }
    104  end)
    105 
    106  it('C-E to cancel wildmenu completion restore original input', function()
    107    feed(':sign <tab>')
    108    screen:expect([[
    109                               |
    110      {1:~                        }|*2
    111      {100:define}{3:  jump  list  >    }|
    112      :sign define^             |
    113    ]])
    114    feed('<C-E>')
    115    screen:expect([[
    116                               |
    117      {1:~                        }|*3
    118      :sign ^                   |
    119    ]])
    120  end)
    121 
    122  it('C-Y to apply selection and end wildmenu completion', function()
    123    feed(':sign <tab>')
    124    screen:expect([[
    125                               |
    126      {1:~                        }|*2
    127      {100:define}{3:  jump  list  >    }|
    128      :sign define^             |
    129    ]])
    130    feed('<tab><C-Y>')
    131    screen:expect([[
    132                               |
    133      {1:~                        }|*3
    134      :sign jump^               |
    135    ]])
    136  end)
    137 
    138  it(':sign <tab> shows wildmenu completions', function()
    139    command('set wildmenu wildmode=full')
    140    feed(':sign <tab>')
    141    screen:expect([[
    142                               |
    143      {1:~                        }|*2
    144      {100:define}{3:  jump  list  >    }|
    145      :sign define^             |
    146    ]])
    147  end)
    148 
    149  it(':sign <tab> <space> hides wildmenu #8453', function()
    150    command('set wildmode=full')
    151    -- only a regression if status-line open
    152    command('set laststatus=2')
    153    command('set wildmenu')
    154    feed(':sign <tab>')
    155    screen:expect([[
    156                               |
    157      {1:~                        }|*2
    158      {100:define}{3:  jump  list  >    }|
    159      :sign define^             |
    160    ]])
    161    feed('<space>')
    162    screen:expect([[
    163                               |
    164      {1:~                        }|*2
    165      {3:[No Name]                }|
    166      :sign define ^            |
    167    ]])
    168  end)
    169 
    170  it('does not crash after cycling back to original text', function()
    171    command('set wildmode=full')
    172    feed(':j<Tab><Tab><Tab>')
    173    screen:expect([[
    174                               |
    175      {1:~                        }|*2
    176      {3:join  jumps              }|
    177      :j^                       |
    178    ]])
    179    -- This would cause nvim to crash before #6650
    180    feed('<BS><Tab>')
    181    screen:expect([[
    182                               |
    183      {1:~                        }|*2
    184      {100:!}{3:  #  &  <  =  >  @  >   }|
    185      :!^                       |
    186    ]])
    187  end)
    188 
    189  it('is preserved during :terminal activity', function()
    190    command('set wildmenu wildmode=full')
    191    command('set scrollback=4')
    192    feed((':terminal "%s" REP 5000 !terminal_output!<cr>'):format(testprg('shell-test')))
    193    feed('G') -- Follow :terminal output.
    194    feed([[:sign <Tab>]]) -- Invoke wildmenu.
    195    screen:add_extra_attr_ids {
    196      [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow },
    197      [101] = {
    198        bold = true,
    199        foreground = Screen.colors.White,
    200        background = Screen.colors.DarkGreen,
    201      },
    202    }
    203    -- NB: in earlier versions terminal output was redrawn during cmdline mode.
    204    -- For now just assert that the screen remains unchanged.
    205    screen:expect { any = '{100:define}{101:  jump  list  >    }|\n:sign define^             |' }
    206    screen:expect_unchanged()
    207 
    208    -- cmdline CTRL-D display should also be preserved.
    209    feed([[<C-U>]])
    210    feed([[sign <C-D>]]) -- Invoke cmdline CTRL-D.
    211    screen:expect {
    212      grid = [[
    213      :sign                    |
    214      define    place          |
    215      jump      undefine       |
    216      list      unplace        |
    217      :sign ^                   |
    218    ]],
    219    }
    220    screen:expect_unchanged()
    221 
    222    -- Exiting cmdline should show the buffer.
    223    feed([[<C-\><C-N>]])
    224    screen:expect { any = [[!terminal_output!]] }
    225  end)
    226 
    227  it('ignores :redrawstatus called from a timer #7108', function()
    228    command('set wildmenu wildmode=full')
    229    command([[call timer_start(10, {->execute('redrawstatus')}, {'repeat':-1})]])
    230    feed([[<C-\><C-N>]])
    231    feed([[:sign <Tab>]]) -- Invoke wildmenu.
    232    screen:expect {
    233      grid = [[
    234                               |
    235      {1:~                        }|*2
    236      {100:define}{3:  jump  list  >    }|
    237      :sign define^             |
    238    ]],
    239    }
    240    screen:expect_unchanged()
    241  end)
    242 
    243  it('with laststatus=0, :vsplit, :term #2255', function()
    244    if not is_os('win') then
    245      command('set shell=sh') -- Need a predictable "$" prompt.
    246      command('let $PS1 = "$"')
    247    end
    248    command('set laststatus=0')
    249    command('vsplit')
    250    command('term')
    251 
    252    -- Check for a shell prompt to verify that the terminal loaded.
    253    retry(nil, nil, function()
    254      if is_os('win') then
    255        eq('Microsoft', eval("matchstr(join(getline(1, '$')), 'Microsoft')"))
    256      else
    257        eq('$', eval([[matchstr(getline(1), '\$')]]))
    258      end
    259    end)
    260 
    261    feed([[<C-\><C-N>]])
    262    feed([[:<Tab>]]) -- Invoke wildmenu.
    263    screen:add_extra_attr_ids {
    264      [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow },
    265      [101] = {
    266        bold = true,
    267        foreground = Screen.colors.White,
    268        background = Screen.colors.DarkGreen,
    269      },
    270    }
    271    -- Check only the last 2 lines, because the shell output is
    272    -- system-dependent.
    273    screen:expect { any = '{100:!}{101:  #  &  <  =  >  @  >   }|\n:!^' }
    274    -- Because this test verifies a _lack_ of activity, we must wait the full timeout.
    275    -- So make it reasonable.
    276    screen:expect_unchanged(false, 1000)
    277  end)
    278 
    279  it('wildmode=list,full and messages interaction #10092', function()
    280    -- Need more than 5 rows, else tabline is covered and will be redrawn.
    281    screen:try_resize(25, 7)
    282 
    283    command('set wildmenu wildmode=list,full')
    284    command('set showtabline=2')
    285    feed(':set wildm<tab>')
    286    screen:expect([[
    287      {5: [No Name] }{2:              }|
    288                               |
    289      {1:~                        }|
    290      {3:                         }|
    291      :set wildm               |
    292      wildmenu  wildmode       |
    293      :set wildm^               |
    294    ]])
    295    feed('<tab>') -- trigger wildmode full
    296    screen:expect([[
    297      {5: [No Name] }{2:              }|
    298                               |
    299      {3:                         }|
    300      :set wildm               |
    301      wildmenu  wildmode       |
    302      {100:wildmenu}{3:  wildmode       }|
    303      :set wildmenu^            |
    304    ]])
    305    feed('<Esc>')
    306    screen:expect([[
    307      {5: [No Name] }{2:              }|
    308      ^                         |
    309      {1:~                        }|*4
    310                               |
    311    ]])
    312  end)
    313 
    314  it('wildmode=longest,list', function()
    315    -- Need more than 5 rows, else tabline is covered and will be redrawn.
    316    screen:try_resize(25, 7)
    317 
    318    command('set wildmenu wildmode=longest,list')
    319 
    320    -- give wildmode-longest something to expand to
    321    feed(':sign u<tab>')
    322    screen:expect([[
    323                               |
    324      {1:~                        }|*5
    325      :sign un^                 |
    326    ]])
    327    feed('<tab>') -- trigger wildmode list
    328    screen:expect([[
    329                               |
    330      {1:~                        }|*2
    331      {3:                         }|
    332      :sign un                 |
    333      undefine  unplace        |
    334      :sign un^                 |
    335    ]])
    336    feed('<Esc>')
    337    screen:expect([[
    338      ^                         |
    339      {1:~                        }|*5
    340                               |
    341    ]])
    342 
    343    -- give wildmode-longest something it cannot expand, use list
    344    feed(':sign un<tab>')
    345    screen:expect([[
    346                               |
    347      {1:~                        }|*2
    348      {3:                         }|
    349      :sign un                 |
    350      undefine  unplace        |
    351      :sign un^                 |
    352    ]])
    353    feed('<tab>')
    354    screen:expect_unchanged()
    355    feed('<Esc>')
    356    screen:expect([[
    357      ^                         |
    358      {1:~                        }|*5
    359                               |
    360    ]])
    361  end)
    362 
    363  it('wildmode=list,longest', function()
    364    -- Need more than 5 rows, else tabline is covered and will be redrawn.
    365    screen:try_resize(25, 7)
    366 
    367    command('set wildmenu wildmode=list,longest')
    368    feed(':sign u<tab>')
    369    screen:expect([[
    370                               |
    371      {1:~                        }|*2
    372      {3:                         }|
    373      :sign u                  |
    374      undefine  unplace        |
    375      :sign u^                  |
    376    ]])
    377    feed('<tab>') -- trigger wildmode longest
    378    screen:expect([[
    379                               |
    380      {1:~                        }|*2
    381      {3:                         }|
    382      :sign u                  |
    383      undefine  unplace        |
    384      :sign un^                 |
    385    ]])
    386    feed('<Esc>')
    387    screen:expect([[
    388      ^                         |
    389      {1:~                        }|*5
    390                               |
    391    ]])
    392  end)
    393 
    394  it('multiple <C-D> renders correctly', function()
    395    screen:try_resize(25, 7)
    396 
    397    command('set laststatus=2')
    398    feed(':set wildm')
    399    feed('<c-d>')
    400    screen:expect([[
    401                               |
    402      {1:~                        }|*2
    403      {3:                         }|
    404      :set wildm               |
    405      wildmenu  wildmode       |
    406      :set wildm^               |
    407    ]])
    408    feed('<c-d>')
    409    screen:expect([[
    410                               |
    411      {3:                         }|
    412      :set wildm               |
    413      wildmenu  wildmode       |
    414      :set wildm               |
    415      wildmenu  wildmode       |
    416      :set wildm^               |
    417    ]])
    418    feed('<Esc>')
    419    screen:expect([[
    420      ^                         |
    421      {1:~                        }|*4
    422      {3:[No Name]                }|
    423                               |
    424    ]])
    425  end)
    426 
    427  it("<C-D> doesn't make statuslines disappear with 'nowildmenu' #36053", function()
    428    screen:try_resize(60, 10)
    429    command('set laststatus=2 nowildmenu')
    430    feed(':sign <C-D>')
    431    screen:expect([[
    432                                                                  |
    433      {1:~                                                           }|*5
    434      {3:                                                            }|
    435      :sign                                                       |
    436      define    jump      list      place     undefine  unplace   |
    437      :sign ^                                                      |
    438    ]])
    439    feed('<Esc>')
    440    screen:expect([[
    441      ^                                                            |
    442      {1:~                                                           }|*7
    443      {3:[No Name]                                                   }|
    444                                                                  |
    445    ]])
    446    command('mode')
    447    screen:expect_unchanged()
    448    feed('ifoobar<Esc>')
    449    screen:expect([[
    450      fooba^r                                                      |
    451      {1:~                                                           }|*7
    452      {3:[No Name] [+]                                               }|
    453                                                                  |
    454    ]])
    455  end)
    456 
    457  it('works with c_CTRL_Z standard mapping', function()
    458    screen:add_extra_attr_ids {
    459      [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
    460    }
    461 
    462    -- Wildcharm? where we are going we aint't no need no wildcharm.
    463    eq(0, api.nvim_get_option_value('wildcharm', {}))
    464    -- Don't mess the defaults yet (neovim is about backwards compatibility)
    465    eq(9, api.nvim_get_option_value('wildchar', {}))
    466    -- Lol what is cnoremap? Some say it can define mappings.
    467    command 'set wildchar=0'
    468    eq(0, api.nvim_get_option_value('wildchar', {}))
    469 
    470    command 'cnoremap <f2> <c-z>'
    471    feed(':syntax <f2>')
    472    screen:expect {
    473      grid = [[
    474                               |
    475      {1:~                        }|*2
    476      {100:case}{3:  clear  cluster  >  }|
    477      :syntax case^             |
    478    ]],
    479    }
    480    feed '<esc>'
    481 
    482    command 'set wildmode=longest:full,full'
    483    -- this will get cleaner once we have native lua expr mappings:
    484    command [[cnoremap <expr> <tab> luaeval("not rawset(_G, 'coin', not coin).coin") ? "<c-z>" : "c"]]
    485 
    486    feed ':syntax <tab>'
    487    screen:expect {
    488      grid = [[
    489                               |
    490      {1:~                        }|*3
    491      :syntax c^                |
    492    ]],
    493    }
    494 
    495    feed '<tab>'
    496    screen:expect {
    497      grid = [[
    498                               |
    499      {1:~                        }|*2
    500      {3:case  clear  cluster  >  }|
    501      :syntax c^                |
    502    ]],
    503    }
    504 
    505    feed '<tab>'
    506    screen:expect {
    507      grid = [[
    508                               |
    509      {1:~                        }|*3
    510      :syntax cc^               |
    511    ]],
    512    }
    513  end)
    514 end)
    515 
    516 describe('command line completion', function()
    517  local screen
    518  before_each(function()
    519    clear()
    520    screen = Screen.new(40, 5)
    521    screen:add_extra_attr_ids {
    522      [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
    523    }
    524  end)
    525  after_each(function()
    526    os.remove('Xtest-functional-viml-compl-dir')
    527  end)
    528 
    529  it('lists directories with empty PATH', function()
    530    local tmp = fn.tempname()
    531    command('e ' .. tmp)
    532    command('cd %:h')
    533    command("call mkdir('Xtest-functional-viml-compl-dir')")
    534    command('let $PATH=""')
    535    feed(':!<tab><bs>')
    536    screen:expect([[
    537                                              |
    538      {1:~                                       }|*3
    539      :!Xtest-functional-viml-compl-dir^       |
    540    ]])
    541  end)
    542 
    543  it('completes env var names #9681', function()
    544    command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"')
    545    command('set wildmenu wildmode=full')
    546    feed(':!echo $XTEST_<tab>')
    547    screen:expect([[
    548                                              |
    549      {1:~                                       }|*2
    550      {100:XTEST_1}{3:  XTEST_2                        }|
    551      :!echo $XTEST_1^                         |
    552    ]])
    553  end)
    554 
    555  it('completes (multibyte) env var names #9655', function()
    556    clear({ env = {
    557      ['XTEST_1AaあB'] = 'foo',
    558      ['XTEST_2'] = 'bar',
    559    } })
    560    screen:attach()
    561    command('set wildmenu wildmode=full')
    562    feed(':!echo $XTEST_<tab>')
    563    screen:expect([[
    564                                              |
    565      {1:~                                       }|*2
    566      {100:XTEST_1AaあB}{3:  XTEST_2                   }|
    567      :!echo $XTEST_1AaあB^                    |
    568    ]])
    569  end)
    570 
    571  it('does not leak memory with <S-Tab> with wildmenu and only one match #19874', function()
    572    api.nvim_set_option_value('wildmenu', true, {})
    573    api.nvim_set_option_value('wildmode', 'full', {})
    574    api.nvim_set_option_value('wildoptions', 'pum', {})
    575 
    576    feed(':sign unpla<S-Tab>')
    577    screen:expect([[
    578                                              |
    579      {1:~                                       }|*3
    580      :sign unplace^                           |
    581    ]])
    582 
    583    feed('<Space>buff<Tab>')
    584    screen:expect([[
    585                                              |
    586      {1:~                                       }|*3
    587      :sign unplace buffer=^                   |
    588    ]])
    589  end)
    590 
    591  it('does not show matches with <S-Tab> without wildmenu with wildmode=full', function()
    592    api.nvim_set_option_value('wildmenu', false, {})
    593    api.nvim_set_option_value('wildmode', 'full', {})
    594 
    595    feed(':sign <S-Tab>')
    596    screen:expect([[
    597                                              |
    598      {1:~                                       }|*3
    599      :sign unplace^                           |
    600    ]])
    601  end)
    602 
    603  it('shows matches with <S-Tab> without wildmenu with wildmode=list', function()
    604    api.nvim_set_option_value('wildmenu', false, {})
    605    api.nvim_set_option_value('wildmode', 'list', {})
    606 
    607    feed(':sign <S-Tab>')
    608    screen:expect([[
    609      {3:                                        }|
    610      :sign define                            |
    611      define    list      undefine            |
    612      jump      place     unplace             |
    613      :sign unplace^                           |
    614    ]])
    615  end)
    616 end)
    617 
    618 describe('ui/ext_wildmenu', function()
    619  local screen
    620 
    621  before_each(function()
    622    clear()
    623    screen = Screen.new(25, 5, { rgb = true, ext_wildmenu = true })
    624  end)
    625 
    626  local function test_ext_wildmenu_sign_cmd()
    627    local expected = {
    628      'define',
    629      'jump',
    630      'list',
    631      'place',
    632      'undefine',
    633      'unplace',
    634    }
    635 
    636    command('set wildmode=full')
    637    command('set wildmenu')
    638    feed(':sign <tab>')
    639    screen:expect {
    640      grid = [[
    641                               |
    642      {1:~                        }|*3
    643      :sign define^             |
    644    ]],
    645      wildmenu_items = expected,
    646      wildmenu_pos = 0,
    647    }
    648 
    649    feed('<tab>')
    650    screen:expect {
    651      grid = [[
    652                               |
    653      {1:~                        }|*3
    654      :sign jump^               |
    655    ]],
    656      wildmenu_items = expected,
    657      wildmenu_pos = 1,
    658    }
    659 
    660    feed('<left><left>')
    661    screen:expect {
    662      grid = [[
    663                               |
    664      {1:~                        }|*3
    665      :sign ^                   |
    666    ]],
    667      wildmenu_items = expected,
    668      wildmenu_pos = -1,
    669    }
    670 
    671    feed('<right>')
    672    screen:expect {
    673      grid = [[
    674                               |
    675      {1:~                        }|*3
    676      :sign define^             |
    677    ]],
    678      wildmenu_items = expected,
    679      wildmenu_pos = 0,
    680    }
    681 
    682    feed('a')
    683    screen:expect([[
    684                               |
    685      {1:~                        }|*3
    686      :sign definea^            |
    687    ]])
    688 
    689    feed('<Esc>')
    690    command('set wildmode=longest,full')
    691    feed(':sign u<tab>')
    692    screen:expect([[
    693                               |
    694      {1:~                        }|*3
    695      :sign un^                 |
    696    ]])
    697 
    698    feed('<tab>')
    699    local s_undefine_unplace_0 = {
    700      grid = [[
    701                               |
    702      {1:~                        }|*3
    703      :sign undefine^           |
    704    ]],
    705      wildmenu_items = { 'undefine', 'unplace' },
    706      wildmenu_pos = 0,
    707    }
    708    screen:expect(s_undefine_unplace_0)
    709 
    710    feed('<Esc>')
    711    screen:expect([[
    712      ^                         |
    713      {1:~                        }|*3
    714                               |
    715    ]])
    716 
    717    feed(':sign un<tab>')
    718    screen:expect(s_undefine_unplace_0)
    719  end
    720 
    721  describe('works with :sign <tab>', function()
    722    it('with wildoptions=pum', function()
    723      command('set wildoptions=pum')
    724      test_ext_wildmenu_sign_cmd()
    725    end)
    726 
    727    it('with wildoptions=', function()
    728      command('set wildoptions=')
    729      test_ext_wildmenu_sign_cmd()
    730    end)
    731  end)
    732 end)