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