neovim

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

man_spec.lua (10108B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 local Screen = require('test.functional.ui.screen')
      4 
      5 local command, feed = n.command, n.feed
      6 local dedent = t.dedent
      7 local clear = n.clear
      8 local exec_lua = n.exec_lua
      9 local fn = n.fn
     10 local nvim_prog = n.nvim_prog
     11 local matches = t.matches
     12 local tmpname = t.tmpname
     13 local eq = t.eq
     14 local pesc = vim.pesc
     15 local skip = t.skip
     16 local is_ci = t.is_ci
     17 
     18 -- Collects all names passed to find_path() after attempting ":Man foo".
     19 local function get_search_history(name)
     20  return exec_lua(function()
     21    local args = vim.split(name, ' ')
     22    local man = require('man')
     23    local res = {}
     24    --- @diagnostic disable-next-line:duplicate-set-field
     25    man._find_path = function(name0, sect)
     26      table.insert(res, { sect, name0 })
     27      return nil
     28    end
     29    local err = man.open_page(-1, { tab = 0 }, args)
     30    assert(err and err:match('no manual entry'))
     31    return res
     32  end)
     33 end
     34 
     35 clear()
     36 if fn.executable('man') == 0 then
     37  pending('missing "man" command', function() end)
     38  return
     39 end
     40 
     41 describe(':Man', function()
     42  before_each(function()
     43    clear()
     44  end)
     45 
     46  describe('man.lua: highlight_line()', function()
     47    local screen --- @type test.functional.ui.screen
     48 
     49    before_each(function()
     50      command('syntax on')
     51      command('set filetype=man')
     52      command('syntax off') -- Ignore syntax groups
     53      screen = Screen.new(52, 5)
     54      screen:set_default_attr_ids({
     55        b = { bold = true },
     56        i = { italic = true },
     57        u = { underline = true },
     58        bi = { bold = true, italic = true },
     59        biu = { bold = true, italic = true, underline = true },
     60        c = { foreground = Screen.colors.Blue }, -- control chars
     61        eob = { bold = true, foreground = Screen.colors.Blue }, -- empty line '~'s
     62      })
     63    end)
     64 
     65    it('clears backspaces from text and adds highlights', function()
     66      feed(
     67        dedent(
     68          [[
     69        ithis i<C-v><C-h>is<C-v><C-h>s a<C-v><C-h>a test
     70        with _<C-v><C-h>o_<C-v><C-h>v_<C-v><C-h>e_<C-v><C-h>r_<C-v><C-h>s_<C-v><C-h>t_<C-v><C-h>r_<C-v><C-h>u_<C-v><C-h>c_<C-v><C-h>k text<ESC>]]
     71        )
     72      )
     73 
     74      screen:expect {
     75        grid = [[
     76        this i{c:^H}is{c:^H}s a{c:^H}a test                             |
     77        with _{c:^H}o_{c:^H}v_{c:^H}e_{c:^H}r_{c:^H}s_{c:^H}t_{c:^H}r_{c:^H}u_{c:^H}c_{c:^H}k tex^t  |
     78        {eob:~                                                   }|*2
     79                                                            |
     80      ]],
     81      }
     82 
     83      exec_lua [[require'man'.init_pager()]]
     84 
     85      screen:expect([[
     86      ^this {b:is} {b:a} test                                      |
     87      with {i:overstruck} text                                |
     88      {eob:~                                                   }|*2
     89                                                          |
     90      ]])
     91    end)
     92 
     93    it('clears escape sequences from text and adds highlights', function()
     94      feed(
     95        dedent(
     96          [[
     97        ithis <C-v><ESC>[1mis <C-v><ESC>[3ma <C-v><ESC>[4mtest<C-v><ESC>[0m
     98        <C-v><ESC>[4mwith<C-v><ESC>[24m <C-v><ESC>[4mescaped<C-v><ESC>[24m <C-v><ESC>[4mtext<C-v><ESC>[24m<ESC>]]
     99        )
    100      )
    101 
    102      screen:expect {
    103        grid = [=[
    104        this {c:^[}[1mis {c:^[}[3ma {c:^[}[4mtest{c:^[}[0m                  |
    105        {c:^[}[4mwith{c:^[}[24m {c:^[}[4mescaped{c:^[}[24m {c:^[}[4mtext{c:^[}[24^m  |
    106        {eob:~                                                   }|*2
    107                                                            |
    108      ]=],
    109      }
    110 
    111      exec_lua [[require'man'.init_pager()]]
    112 
    113      screen:expect([[
    114      ^this {b:is }{bi:a }{biu:test}                                      |
    115      {u:with} {u:escaped} {u:text}                                   |
    116      {eob:~                                                   }|*2
    117                                                          |
    118      ]])
    119    end)
    120 
    121    it('clears OSC 8 hyperlink markup from text', function()
    122      feed(
    123        dedent(
    124          [[
    125        ithis <C-v><ESC>]8;;http://example.com<C-v><ESC>\Link Title<C-v><ESC>]8;;<C-v><ESC>\<ESC>]]
    126        )
    127      )
    128 
    129      screen:expect {
    130        grid = [=[
    131        this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ |
    132        {eob:~                                                   }|*3
    133                                                            |
    134      ]=],
    135      }
    136 
    137      exec_lua [[require'man'.init_pager()]]
    138 
    139      screen:expect([[
    140      ^this Link Title                                     |
    141      {eob:~                                                   }|*3
    142                                                          |
    143      ]])
    144    end)
    145 
    146    it('highlights multibyte text', function()
    147      feed(
    148        dedent(
    149          [[
    150        ithis i<C-v><C-h>is<C-v><C-h>s あ<C-v><C-h>あ test
    151        with _<C-v><C-h>ö_<C-v><C-h>v_<C-v><C-h>e_<C-v><C-h>r_<C-v><C-h>s_<C-v><C-h>t_<C-v><C-h>r_<C-v><C-h>u_<C-v><C-h>̃_<C-v><C-h>c_<C-v><C-h>k te<C-v><ESC>[3mxt¶<C-v><ESC>[0m<ESC>]]
    152        )
    153      )
    154      exec_lua [[require'man'.init_pager()]]
    155 
    156      screen:expect([[
    157      ^this {b:is} {b:} test                                     |
    158      with {i:överstrũck} te{i:xt}                               |
    159      {eob:~                                                   }|*2
    160                                                          |
    161      ]])
    162    end)
    163 
    164    it('highlights underscores based on context', function()
    165      feed(
    166        dedent(
    167          [[
    168        i_<C-v><C-h>_b<C-v><C-h>be<C-v><C-h>eg<C-v><C-h>gi<C-v><C-h>in<C-v><C-h>ns<C-v><C-h>s
    169        m<C-v><C-h>mi<C-v><C-h>id<C-v><C-h>d_<C-v><C-h>_d<C-v><C-h>dl<C-v><C-h>le<C-v><C-h>e
    170        _<C-v><C-h>m_<C-v><C-h>i_<C-v><C-h>d_<C-v><C-h>__<C-v><C-h>d_<C-v><C-h>l_<C-v><C-h>e<ESC>]]
    171        )
    172      )
    173      exec_lua [[require'man'.init_pager()]]
    174 
    175      screen:expect([[
    176      {b:^_begins}                                             |
    177      {b:mid_dle}                                             |
    178      {i:mid_dle}                                             |
    179      {eob:~                                                   }|
    180                                                          |
    181      ]])
    182    end)
    183 
    184    it('highlights various bullet formats', function()
    185      feed(dedent([[
    186        i· ·<C-v><C-h>·
    187        +<C-v><C-h>o
    188        +<C-v><C-h>+<C-v><C-h>o<C-v><C-h>o double<ESC>]]))
    189      exec_lua [[require'man'.init_pager()]]
    190 
    191      screen:expect([[
    192      ^· {b:·}                                                 |
    193      {b:·}                                                   |
    194      {b:·} double                                            |
    195      {eob:~                                                   }|
    196                                                          |
    197      ]])
    198    end)
    199 
    200    it('handles : characters in input', function()
    201      feed(dedent([[
    202        i<C-v><C-[>[40m    0  <C-v><C-[>[41m    1  <C-v><C-[>[42m    2  <C-v><C-[>[43m    3
    203        <C-v><C-[>[44m    4  <C-v><C-[>[45m    5  <C-v><C-[>[46m    6  <C-v><C-[>[47m    7  <C-v><C-[>[100m    8  <C-v><C-[>[101m    9
    204        <C-v><C-[>[102m   10  <C-v><C-[>[103m   11  <C-v><C-[>[104m   12  <C-v><C-[>[105m   13  <C-v><C-[>[106m   14  <C-v><C-[>[107m   15
    205        <C-v><C-[>[48:5:16m   16  <ESC>]]))
    206      exec_lua [[require'man'.init_pager()]]
    207 
    208      screen:expect([[
    209       ^    0      1      2      3                          |
    210           4      5      6      7      8      9            |
    211          10     11     12     13     14     15            |
    212          16                                               |
    213                                                           |
    214      ]])
    215    end)
    216  end)
    217 
    218  it('q quits in "$MANPAGER mode" (:Man!) #18281', function()
    219    -- This will hang if #18281 regresses.
    220    local args = {
    221      nvim_prog,
    222      '--headless',
    223      '+autocmd VimLeave * echo "quit works!!"',
    224      '+Man!',
    225      '+tag ls',
    226      '+call nvim_input("q")',
    227    }
    228    matches('quit works!!', fn.system(args, { 'manpage contents' }))
    229  end)
    230 
    231  it('raw manpage into (:Man!) creates a new buffer #30132', function()
    232    local args = {
    233      nvim_prog,
    234      '--headless',
    235      '+Man! foo',
    236      '+echo bufname()',
    237      '+enew',
    238      '+Man! foo',
    239      '+echo bufname()',
    240      '+enew',
    241      '+Man! foo',
    242      '+echo bufname()',
    243      '+q',
    244    }
    245    local out = fn.system(args, { 'manpage contents' })
    246    assert(out and out:match('man://%?new=%d'))
    247  end)
    248 
    249  it('reports non-existent man pages for absolute paths', function()
    250    skip(is_ci('cirrus'))
    251    local actual_file = tmpname()
    252    -- actual_file must be an absolute path to an existent file for us to test against it
    253    matches('^/.+', actual_file)
    254    local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' }
    255    matches(
    256      ('Error in command line:\r\n' .. 'man.lua: no manual entry for %s'):format(pesc(actual_file)),
    257      fn.system(args, { '' })
    258    )
    259    os.remove(actual_file)
    260  end)
    261 
    262  it('tries variants with spaces, underscores #22503', function()
    263    eq({
    264      { vim.NIL, 'NAME WITH SPACES' },
    265      { vim.NIL, 'NAME_WITH_SPACES' },
    266    }, get_search_history('NAME WITH SPACES'))
    267    eq({
    268      { '3', 'some other man' },
    269      { '3', 'some_other_man' },
    270    }, get_search_history('3 some other man'))
    271    eq({
    272      { '3x', 'some other man' },
    273      { '3x', 'some_other_man' },
    274    }, get_search_history('3X some other man'))
    275    eq({
    276      { '3tcl', 'some other man' },
    277      { '3tcl', 'some_other_man' },
    278    }, get_search_history('3tcl some other man'))
    279    eq({
    280      { 'n', 'some other man' },
    281      { 'n', 'some_other_man' },
    282    }, get_search_history('n some other man'))
    283    eq({
    284      { vim.NIL, '123some other man' },
    285      { vim.NIL, '123some_other_man' },
    286    }, get_search_history('123some other man'))
    287    eq({
    288      { '1', 'other_man' },
    289      { '1', 'other_man' },
    290    }, get_search_history('other_man(1)'))
    291  end)
    292 
    293  it('can complete', function()
    294    eq(
    295      true,
    296      exec_lua(function()
    297        return #require('man').man_complete('f', 'Man f') > 0
    298      end)
    299    )
    300  end)
    301 end)