1" Test 'statusline'
2"
3" Not tested yet:
4"   %N
5
6source view_util.vim
7source check.vim
8source screendump.vim
9
10func s:get_statusline()
11  return ScreenLines(&lines - 1, &columns)[0]
12endfunc
13
14func StatuslineWithCaughtError()
15  let s:func_in_statusline_called = 1
16  try
17    call eval('unknown expression')
18  catch
19  endtry
20  return ''
21endfunc
22
23func StatuslineWithError()
24  let s:func_in_statusline_called = 1
25  call eval('unknown expression')
26  return ''
27endfunc
28
29" Function used to display syntax group.
30func SyntaxItem()
31  call assert_equal(s:expected_curbuf, g:actual_curbuf)
32  call assert_equal(s:expected_curwin, g:actual_curwin)
33  return synIDattr(synID(line("."), col("."),1), "name")
34endfunc
35
36func Test_caught_error_in_statusline()
37  let s:func_in_statusline_called = 0
38  set laststatus=2
39  let statusline = '%{StatuslineWithCaughtError()}'
40  let &statusline = statusline
41  redrawstatus
42  call assert_true(s:func_in_statusline_called)
43  call assert_equal(statusline, &statusline)
44  set statusline=
45endfunc
46
47func Test_statusline_will_be_disabled_with_error()
48  let s:func_in_statusline_called = 0
49  set laststatus=2
50  let statusline = '%{StatuslineWithError()}'
51  try
52    let &statusline = statusline
53    redrawstatus
54  catch
55  endtry
56  call assert_true(s:func_in_statusline_called)
57  call assert_equal('', &statusline)
58  set statusline=
59endfunc
60
61func Test_statusline()
62  CheckFeature quickfix
63
64  " %a: Argument list ({current} of {max})
65  set statusline=%a
66  call assert_match('^\s*$', s:get_statusline())
67  arglocal a1 a2
68  rewind
69  call assert_match('^ (1 of 2)\s*$', s:get_statusline())
70  next
71  call assert_match('^ (2 of 2)\s*$', s:get_statusline())
72  e Xstatusline
73  call assert_match('^ ((2) of 2)\s*$', s:get_statusline())
74
75  only
76  set laststatus=2
77  set splitbelow
78  call setline(1, range(1, 10000))
79
80  " %b: Value of character under cursor.
81  " %B: As above, in hexadecimal.
82  call cursor(9000, 1)
83  set statusline=%b,%B
84  call assert_match('^57,39\s*$', s:get_statusline())
85
86  " %o: Byte number in file of byte under cursor, first byte is 1.
87  " %O: As above, in hexadecimal.
88  set statusline=%o,%O
89  set fileformat=dos
90  call assert_match('^52888,CE98\s*$', s:get_statusline())
91  set fileformat=mac
92  call assert_match('^43889,AB71\s*$', s:get_statusline())
93  set fileformat=unix
94  call assert_match('^43889,AB71\s*$', s:get_statusline())
95  set fileformat&
96
97  " %f: Path to the file in the buffer, as typed or relative to current dir.
98  set statusline=%f
99  call assert_match('^Xstatusline\s*$', s:get_statusline())
100
101  " %F: Full path to the file in the buffer.
102  set statusline=%F
103  call assert_match('/testdir/Xstatusline\s*$', s:get_statusline())
104
105  " Test for min and max width with %(. For some reason, if this test is moved
106  " after the below test for the help buffer flag, then the code to truncate
107  " the string is not executed.
108  set statusline=%015(%f%)
109  call assert_match('^    Xstatusline\s*$', s:get_statusline())
110  set statusline=%.6(%f%)
111  call assert_match('^<sline\s*$', s:get_statusline())
112  set statusline=%14f
113  call assert_match('^   Xstatusline\s*$', s:get_statusline())
114  set statusline=%.4L
115  call assert_match('^10>3\s*$', s:get_statusline())
116
117  " %h: Help buffer flag, text is "[help]".
118  " %H: Help buffer flag, text is ",HLP".
119  set statusline=%h,%H
120  call assert_match('^,\s*$', s:get_statusline())
121  help
122  call assert_match('^\[Help\],HLP\s*$', s:get_statusline())
123  helpclose
124
125  " %k: Value of "b:keymap_name" or 'keymap'
126  "     when :lmap mappings are being used: <keymap>"
127  set statusline=%k
128  if has('keymap')
129    set keymap=esperanto
130    call assert_match('^<Eo>\s*$', s:get_statusline())
131    set keymap&
132  else
133    call assert_match('^\s*$', s:get_statusline())
134  endif
135
136  " %l: Line number.
137  " %L: Number of line in buffer.
138  " %c: Column number.
139  set statusline=%l/%L,%c
140  call assert_match('^9000/10000,1\s*$', s:get_statusline())
141
142  " %m: Modified flag, text is "[+]", "[-]" if 'modifiable' is off.
143  " %M: Modified flag, text is ",+" or ",-".
144  set statusline=%m%M
145  call assert_match('^\[+\],+\s*$', s:get_statusline())
146  set nomodifiable
147  call assert_match('^\[+-\],+-\s*$', s:get_statusline())
148  write
149  call assert_match('^\[-\],-\s*$', s:get_statusline())
150  set modifiable&
151  call assert_match('^\s*$', s:get_statusline())
152
153  " %n: Buffer number.
154  set statusline=%n
155  call assert_match('^'.bufnr('%').'\s*$', s:get_statusline())
156
157  " %p: Percentage through file in lines as in CTRL-G.
158  " %P: Percentage through file of displayed window.
159  set statusline=%p,%P
160  0
161  call assert_match('^0,Top\s*$', s:get_statusline())
162  norm G
163  call assert_match('^100,Bot\s*$', s:get_statusline())
164  9000
165  " Don't check the exact percentage as it depends on the window size
166  call assert_match('^90,\(Top\|Bot\|\d\+%\)\s*$', s:get_statusline())
167
168  " %q: "[Quickfix List]", "[Location List]" or empty.
169  set statusline=%q
170  call assert_match('^\s*$', s:get_statusline())
171  copen
172  call assert_match('^\[Quickfix List\]\s*$', s:get_statusline())
173  cclose
174  lexpr getline(1, 2)
175  lopen
176  call assert_match('^\[Location List\]\s*$', s:get_statusline())
177  lclose
178
179  " %r: Readonly flag, text is "[RO]".
180  " %R: Readonly flag, text is ",RO".
181  set statusline=%r,%R
182  call assert_match('^,\s*$', s:get_statusline())
183  help
184  call assert_match('^\[RO\],RO\s*$', s:get_statusline())
185  helpclose
186
187  " %t: File name (tail) of file in the buffer.
188  set statusline=%t
189  call assert_match('^Xstatusline\s*$', s:get_statusline())
190
191  " %v: Virtual column number.
192  " %V: Virtual column number as -{num}. Not displayed if equal to 'c'.
193  call cursor(9000, 2)
194  set statusline=%v,%V
195  call assert_match('^2,\s*$', s:get_statusline())
196  set virtualedit=all
197  norm 10|
198  call assert_match('^10,-10\s*$', s:get_statusline())
199  set virtualedit&
200
201  " %w: Preview window flag, text is "[Preview]".
202  " %W: Preview window flag, text is ",PRV".
203  set statusline=%w%W
204  call assert_match('^\s*$', s:get_statusline())
205  pedit
206  wincmd j
207  call assert_match('^\[Preview\],PRV\s*$', s:get_statusline())
208  pclose
209
210  " %y: Type of file in the buffer, e.g., "[vim]". See 'filetype'.
211  " %Y: Type of file in the buffer, e.g., ",VIM". See 'filetype'.
212  set statusline=%y\ %Y
213  call assert_match('^\s*$', s:get_statusline())
214  setfiletype vim
215  call assert_match('^\[vim\] VIM\s*$', s:get_statusline())
216
217  " %=: Separation point between left and right aligned items.
218  set statusline=foo%=bar
219  call assert_match('^foo\s\+bar\s*$', s:get_statusline())
220
221  " Test min/max width, leading zeroes, left/right justify.
222  set statusline=%04B
223  call cursor(9000, 1)
224  call assert_match('^0039\s*$', s:get_statusline())
225  set statusline=#%4B#
226  call assert_match('^#  39#\s*$', s:get_statusline())
227  set statusline=#%-4B#
228  call assert_match('^#39  #\s*$', s:get_statusline())
229  set statusline=%.6f
230  call assert_match('^<sline\s*$', s:get_statusline())
231
232  " %<: Where to truncate.
233  " First check with when %< should not truncate with many columns
234  exe 'set statusline=a%<b' . repeat('c', &columns - 3) . 'd'
235  call assert_match('^abc\+d$', s:get_statusline())
236  exe 'set statusline=a' . repeat('b', &columns - 2) . '%<c'
237  call assert_match('^ab\+c$', s:get_statusline())
238  " Then check when %< should truncate when there with too few columns.
239  exe 'set statusline=a%<b' . repeat('c', &columns - 2) . 'd'
240  call assert_match('^a<c\+d$', s:get_statusline())
241  exe 'set statusline=a' . repeat('b', &columns - 1) . '%<c'
242  call assert_match('^ab\+>$', s:get_statusline())
243
244  "%{: Evaluate expression between '%{' and '}' and substitute result.
245  syntax on
246  let s:expected_curbuf = string(bufnr(''))
247  let s:expected_curwin = string(win_getid())
248  set statusline=%{SyntaxItem()}
249  call assert_match('^vimNumber\s*$', s:get_statusline())
250  s/^/"/
251  call assert_match('^vimLineComment\s*$', s:get_statusline())
252  syntax off
253
254  "%(: Start of item group.
255  set statusline=ab%(cd%q%)de
256  call assert_match('^abde\s*$', s:get_statusline())
257  copen
258  call assert_match('^abcd\[Quickfix List]de\s*$', s:get_statusline())
259  cclose
260
261  " %#: Set highlight group. The name must follow and then a # again.
262  set statusline=ab%#Todo#cd%#Error#ef
263  call assert_match('^abcdef\s*$', s:get_statusline())
264  let sa1=screenattr(&lines - 1, 1)
265  let sa2=screenattr(&lines - 1, 3)
266  let sa3=screenattr(&lines - 1, 5)
267  call assert_notequal(sa1, sa2)
268  call assert_notequal(sa1, sa3)
269  call assert_notequal(sa2, sa3)
270  call assert_equal(sa1, screenattr(&lines - 1, 2))
271  call assert_equal(sa2, screenattr(&lines - 1, 4))
272  call assert_equal(sa3, screenattr(&lines - 1, 6))
273  call assert_equal(sa3, screenattr(&lines - 1, 7))
274
275  " %*: Set highlight group to User{N}
276  set statusline=a%1*b%0*c
277  call assert_match('^abc\s*$', s:get_statusline())
278  let sa1=screenattr(&lines - 1, 1)
279  let sa2=screenattr(&lines - 1, 2)
280  let sa3=screenattr(&lines - 1, 3)
281  call assert_equal(sa1, sa3)
282  call assert_notequal(sa1, sa2)
283
284  " An empty group that contains highlight changes
285  let g:a = ''
286  set statusline=ab%(cd%1*%{g:a}%*%)de
287  call assert_match('^abde\s*$', s:get_statusline())
288  let sa1=screenattr(&lines - 1, 1)
289  let sa2=screenattr(&lines - 1, 4)
290  call assert_equal(sa1, sa2)
291  let g:a = 'X'
292  call assert_match('^abcdXde\s*$', s:get_statusline())
293  let sa1=screenattr(&lines - 1, 1)
294  let sa2=screenattr(&lines - 1, 5)
295  let sa3=screenattr(&lines - 1, 7)
296  call assert_equal(sa1, sa3)
297  call assert_notequal(sa1, sa2)
298
299  let g:a = ''
300  set statusline=ab%1*%(cd%*%{g:a}%1*%)de
301  call assert_match('^abde\s*$', s:get_statusline())
302  let sa1=screenattr(&lines - 1, 1)
303  let sa2=screenattr(&lines - 1, 4)
304  call assert_notequal(sa1, sa2)
305  let g:a = 'X'
306  call assert_match('^abcdXde\s*$', s:get_statusline())
307  let sa1=screenattr(&lines - 1, 1)
308  let sa2=screenattr(&lines - 1, 3)
309  let sa3=screenattr(&lines - 1, 5)
310  let sa4=screenattr(&lines - 1, 7)
311  call assert_notequal(sa1, sa2)
312  call assert_equal(sa1, sa3)
313  call assert_equal(sa2, sa4)
314
315  " An empty group that contains highlight changes and doesn't reset them
316  let g:a = ''
317  set statusline=ab%(cd%1*%{g:a}%)de
318  call assert_match('^abcdde\s*$', s:get_statusline())
319  let sa1=screenattr(&lines - 1, 1)
320  let sa2=screenattr(&lines - 1, 5)
321  call assert_notequal(sa1, sa2)
322  let g:a = 'X'
323  call assert_match('^abcdXde\s*$', s:get_statusline())
324  let sa1=screenattr(&lines - 1, 1)
325  let sa2=screenattr(&lines - 1, 5)
326  let sa3=screenattr(&lines - 1, 7)
327  call assert_notequal(sa1, sa2)
328  call assert_equal(sa2, sa3)
329
330  let g:a = ''
331  set statusline=ab%1*%(cd%*%{g:a}%)de
332  call assert_match('^abcdde\s*$', s:get_statusline())
333  let sa1=screenattr(&lines - 1, 1)
334  let sa2=screenattr(&lines - 1, 3)
335  let sa3=screenattr(&lines - 1, 5)
336  call assert_notequal(sa1, sa2)
337  call assert_equal(sa1, sa3)
338  let g:a = 'X'
339  call assert_match('^abcdXde\s*$', s:get_statusline())
340  let sa1=screenattr(&lines - 1, 1)
341  let sa2=screenattr(&lines - 1, 3)
342  let sa3=screenattr(&lines - 1, 5)
343  let sa4=screenattr(&lines - 1, 7)
344  call assert_notequal(sa1, sa2)
345  call assert_equal(sa1, sa3)
346  call assert_equal(sa1, sa4)
347
348  let g:a = ''
349  set statusline=%#Error#{%(\ %{g:a}\ %)}
350  call assert_match('^{}\s*$', s:get_statusline())
351  let g:a = 'X'
352  call assert_match('^{ X }\s*$', s:get_statusline())
353
354  " %%: a percent sign.
355  set statusline=10%%
356  call assert_match('^10%\s*$', s:get_statusline())
357
358  " %!: evaluated expression is used as the option value
359  set statusline=%!2*3+1
360  call assert_match('7\s*$', s:get_statusline())
361
362  func GetNested()
363    call assert_equal(string(win_getid()), g:actual_curwin)
364    call assert_equal(string(bufnr('')), g:actual_curbuf)
365    return 'nested'
366  endfunc
367  func GetStatusLine()
368    call assert_equal(win_getid(), g:statusline_winid)
369    return 'the %{GetNested()} line'
370  endfunc
371  set statusline=%!GetStatusLine()
372  call assert_match('the nested line', s:get_statusline())
373  call assert_false(exists('g:actual_curwin'))
374  call assert_false(exists('g:actual_curbuf'))
375  call assert_false(exists('g:statusline_winid'))
376  delfunc GetNested
377  delfunc GetStatusLine
378
379  " Test statusline works with 80+ items
380  function! StatusLabel()
381    redrawstatus
382    return '[label]'
383  endfunc
384  let statusline = '%{StatusLabel()}'
385  for i in range(150)
386    let statusline .= '%#TabLine' . (i % 2 == 0 ? 'Fill' : 'Sel') . '#' . string(i)[0]
387  endfor
388  let &statusline = statusline
389  redrawstatus
390  set statusline&
391  delfunc StatusLabel
392
393
394  " Check statusline in current and non-current window
395  " with the 'fillchars' option.
396  set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:-
397  vsplit
398  set statusline=x%=y
399  call assert_match('^x^\+y^x=\+y$', s:get_statusline())
400  set fillchars&
401  close
402
403  %bw!
404  call delete('Xstatusline')
405  set statusline&
406  set laststatus&
407  set splitbelow&
408endfunc
409
410func Test_statusline_visual()
411  func CallWordcount()
412    call wordcount()
413  endfunc
414  new x1
415  setl statusline=count=%{CallWordcount()}
416  " buffer must not be empty
417  call setline(1, 'hello')
418
419  " window with more lines than x1
420  new x2
421  call setline(1, range(10))
422  $
423  " Visual mode in line below liast line in x1 should not give ml_get error
424  call feedkeys("\<C-V>", "xt")
425  redraw
426
427  delfunc CallWordcount
428  bwipe! x1
429  bwipe! x2
430endfunc
431
432func Test_statusline_removed_group()
433  CheckScreendump
434
435  let lines =<< trim END
436    scriptencoding utf-8
437    set laststatus=2
438    let &statusline = '%#StatColorHi2#%(✓%#StatColorHi2#%) Q≡'
439  END
440  call writefile(lines, 'XTest_statusline')
441
442  let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 10, 'cols': 50})
443  call TermWait(buf, 50)
444  call VerifyScreenDump(buf, 'Test_statusline_1', {})
445
446  " clean up
447  call StopVimInTerminal(buf)
448  call delete('XTest_statusline')
449endfunc
450
451func Test_statusline_after_split_vsplit()
452  only
453
454  " Make the status line of each window show the window number.
455  set ls=2 stl=%{winnr()}
456
457  split | redraw
458  vsplit | redraw
459
460  " The status line of the third window should read '3' here.
461  call assert_equal('3', nr2char(screenchar(&lines - 1, 1)))
462
463  only
464  set ls& stl&
465endfunc
466
467
468" vim: shiftwidth=2 sts=2 expandtab
469