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