aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin/man_spec.lua
blob: 5bfa566729914078b69a1efe102bb335c8213218 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local command, rawfeed = helpers.command, helpers.rawfeed
local clear = helpers.clear
local exec_lua = helpers.exec_lua
local fn = helpers.fn
local nvim_prog = helpers.nvim_prog
local matches = helpers.matches
local write_file = helpers.write_file
local tmpname = helpers.tmpname
local eq = helpers.eq
local pesc = vim.pesc
local skip = helpers.skip
local is_ci = helpers.is_ci

-- Collects all names passed to find_path() after attempting ":Man foo".
local function get_search_history(name)
  local args = vim.split(name, ' ')
  local code = [[
    local args = ...
    local man = require('runtime.lua.man')
    local res = {}
    man.find_path = function(sect, name)
      table.insert(res, {sect, name})
      return nil
    end
    local ok, rv = pcall(man.open_page, -1, {tab = 0}, args)
    assert(not ok)
    assert(rv and rv:match('no manual entry'))
    return res
  ]]
  return exec_lua(code, args)
end

clear()
if fn.executable('man') == 0 then
  pending('missing "man" command', function() end)
  return
end

describe(':Man', function()
  before_each(function()
    clear()
  end)

  describe('man.lua: highlight_line()', function()
    local screen

    before_each(function()
      command('syntax on')
      command('set filetype=man')
      command('syntax off') -- Ignore syntax groups
      screen = Screen.new(52, 5)
      screen:set_default_attr_ids({
        b = { bold = true },
        i = { italic = true },
        u = { underline = true },
        bi = { bold = true, italic = true },
        biu = { bold = true, italic = true, underline = true },
        c = { foreground = Screen.colors.Blue }, -- control chars
        eob = { bold = true, foreground = Screen.colors.Blue }, -- empty line '~'s
      })
      screen:attach()
    end)

    it('clears backspaces from text and adds highlights', function()
      rawfeed(
        [[
        ithis i<C-v><C-h>is<C-v><C-h>s a<C-v><C-h>a test
        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>]]
      )

      screen:expect {
        grid = [[
        this i{c:^H}is{c:^H}s a{c:^H}a test                             |
        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  |
        {eob:~                                                   }|*2
                                                            |
      ]],
      }

      exec_lua [[require'man'.init_pager()]]

      screen:expect([[
      ^this {b:is} {b:a} test                                      |
      with {i:overstruck} text                                |
      {eob:~                                                   }|*2
                                                          |
      ]])
    end)

    it('clears escape sequences from text and adds highlights', function()
      rawfeed(
        [[
        ithis <C-v><ESC>[1mis <C-v><ESC>[3ma <C-v><ESC>[4mtest<C-v><ESC>[0m
        <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>]]
      )

      screen:expect {
        grid = [=[
        this {c:^[}[1mis {c:^[}[3ma {c:^[}[4mtest{c:^[}[0m                  |
        {c:^[}[4mwith{c:^[}[24m {c:^[}[4mescaped{c:^[}[24m {c:^[}[4mtext{c:^[}[24^m  |
        {eob:~                                                   }|*2
                                                            |
      ]=],
      }

      exec_lua [[require'man'.init_pager()]]

      screen:expect([[
      ^this {b:is }{bi:a }{biu:test}                                      |
      {u:with} {u:escaped} {u:text}                                   |
      {eob:~                                                   }|*2
                                                          |
      ]])
    end)

    it('highlights multibyte text', function()
      rawfeed(
        [[
        ithis i<C-v><C-h>is<C-v><C-h>s あ<C-v><C-h>あ test
        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>]]
      )
      exec_lua [[require'man'.init_pager()]]

      screen:expect([[
      ^this {b:is} {b:あ} test                                     |
      with {i:överstrũck} te{i:xt¶}                               |
      {eob:~                                                   }|*2
                                                          |
      ]])
    end)

    it('highlights underscores based on context', function()
      rawfeed(
        [[
        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
        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
        _<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>]]
      )
      exec_lua [[require'man'.init_pager()]]

      screen:expect([[
      {b:^_begins}                                             |
      {b:mid_dle}                                             |
      {i:mid_dle}                                             |
      {eob:~                                                   }|
                                                          |
      ]])
    end)

    it('highlights various bullet formats', function()
      rawfeed([[
        i· ·<C-v><C-h>·
        +<C-v><C-h>o
        +<C-v><C-h>+<C-v><C-h>o<C-v><C-h>o double<ESC>]])
      exec_lua [[require'man'.init_pager()]]

      screen:expect([[
      ^· {b:·}                                                 |
      {b:·}                                                   |
      {b:·} double                                            |
      {eob:~                                                   }|
                                                          |
      ]])
    end)

    it('handles : characters in input', function()
      rawfeed([[
        i<C-v><C-[>[40m    0  <C-v><C-[>[41m    1  <C-v><C-[>[42m    2  <C-v><C-[>[43m    3
        <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
        <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
        <C-v><C-[>[48:5:16m   16  <ESC>]])
      exec_lua [[require'man'.init_pager()]]

      screen:expect([[
       ^    0      1      2      3                          |
           4      5      6      7      8      9            |
          10     11     12     13     14     15            |
          16                                               |
                                                           |
      ]])
    end)
  end)

  it('q quits in "$MANPAGER mode" (:Man!) #18281', function()
    -- This will hang if #18281 regresses.
    local args = {
      nvim_prog,
      '--headless',
      '+autocmd VimLeave * echo "quit works!!"',
      '+Man!',
      '+call nvim_input("q")',
    }
    matches('quit works!!', fn.system(args, { 'manpage contents' }))
  end)

  it('reports non-existent man pages for absolute paths', function()
    skip(is_ci('cirrus'))
    local actual_file = tmpname()
    -- actual_file must be an absolute path to an existent file for us to test against it
    matches('^/.+', actual_file)
    write_file(actual_file, '')
    local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' }
    matches(
      ('Error detected while processing command line:\r\n' .. 'man.lua: "no manual entry for %s"'):format(
        pesc(actual_file)
      ),
      fn.system(args, { '' })
    )
    os.remove(actual_file)
  end)

  it('tries variants with spaces, underscores #22503', function()
    eq({
      { '', 'NAME WITH SPACES' },
      { '', 'NAME_WITH_SPACES' },
    }, get_search_history('NAME WITH SPACES'))
    eq({
      { '3', 'some other man' },
      { '3', 'some_other_man' },
    }, get_search_history('3 some other man'))
    eq({
      { '3x', 'some other man' },
      { '3x', 'some_other_man' },
    }, get_search_history('3X some other man'))
    eq({
      { '3tcl', 'some other man' },
      { '3tcl', 'some_other_man' },
    }, get_search_history('3tcl some other man'))
    eq({
      { 'n', 'some other man' },
      { 'n', 'some_other_man' },
    }, get_search_history('n some other man'))
    eq({
      { '', '123some other man' },
      { '', '123some_other_man' },
    }, get_search_history('123some other man'))
    eq({
      { '1', 'other_man' },
      { '1', 'other_man' },
    }, get_search_history('other_man(1)'))
  end)
end)