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 "%{%expr%}: evaluates enxpressions present in result of expr 255 func! Inner_eval() 256 return '%n some other text' 257 endfunc 258 func! Outer_eval() 259 return 'some text %{%Inner_eval()%}' 260 endfunc 261 set statusline=%{%Outer_eval()%} 262 call assert_match('^some text ' . bufnr() . ' some other text\s*$', s:get_statusline()) 263 delfunc Inner_eval 264 delfunc Outer_eval 265 266 "%{%expr%}: Doesn't get stuck in recursion 267 func! Recurse_eval() 268 return '%{%Recurse_eval()%}' 269 endfunc 270 set statusline=%{%Recurse_eval()%} 271 call assert_match('^%{%Recurse_eval()%}\s*$', s:get_statusline()) 272 delfunc Recurse_eval 273 274 "%(: Start of item group. 275 set statusline=ab%(cd%q%)de 276 call assert_match('^abde\s*$', s:get_statusline()) 277 copen 278 call assert_match('^abcd\[Quickfix List]de\s*$', s:get_statusline()) 279 cclose 280 281 " %#: Set highlight group. The name must follow and then a # again. 282 set statusline=ab%#Todo#cd%#Error#ef 283 call assert_match('^abcdef\s*$', s:get_statusline()) 284 let sa1=screenattr(&lines - 1, 1) 285 let sa2=screenattr(&lines - 1, 3) 286 let sa3=screenattr(&lines - 1, 5) 287 call assert_notequal(sa1, sa2) 288 call assert_notequal(sa1, sa3) 289 call assert_notequal(sa2, sa3) 290 call assert_equal(sa1, screenattr(&lines - 1, 2)) 291 call assert_equal(sa2, screenattr(&lines - 1, 4)) 292 call assert_equal(sa3, screenattr(&lines - 1, 6)) 293 call assert_equal(sa3, screenattr(&lines - 1, 7)) 294 295 " %*: Set highlight group to User{N} 296 set statusline=a%1*b%0*c 297 call assert_match('^abc\s*$', s:get_statusline()) 298 let sa1=screenattr(&lines - 1, 1) 299 let sa2=screenattr(&lines - 1, 2) 300 let sa3=screenattr(&lines - 1, 3) 301 call assert_equal(sa1, sa3) 302 call assert_notequal(sa1, sa2) 303 304 " An empty group that contains highlight changes 305 let g:a = '' 306 set statusline=ab%(cd%1*%{g:a}%*%)de 307 call assert_match('^abde\s*$', s:get_statusline()) 308 let sa1=screenattr(&lines - 1, 1) 309 let sa2=screenattr(&lines - 1, 4) 310 call assert_equal(sa1, sa2) 311 let g:a = 'X' 312 call assert_match('^abcdXde\s*$', s:get_statusline()) 313 let sa1=screenattr(&lines - 1, 1) 314 let sa2=screenattr(&lines - 1, 5) 315 let sa3=screenattr(&lines - 1, 7) 316 call assert_equal(sa1, sa3) 317 call assert_notequal(sa1, sa2) 318 319 let g:a = '' 320 set statusline=ab%1*%(cd%*%{g:a}%1*%)de 321 call assert_match('^abde\s*$', s:get_statusline()) 322 let sa1=screenattr(&lines - 1, 1) 323 let sa2=screenattr(&lines - 1, 4) 324 call assert_notequal(sa1, sa2) 325 let g:a = 'X' 326 call assert_match('^abcdXde\s*$', s:get_statusline()) 327 let sa1=screenattr(&lines - 1, 1) 328 let sa2=screenattr(&lines - 1, 3) 329 let sa3=screenattr(&lines - 1, 5) 330 let sa4=screenattr(&lines - 1, 7) 331 call assert_notequal(sa1, sa2) 332 call assert_equal(sa1, sa3) 333 call assert_equal(sa2, sa4) 334 335 " An empty group that contains highlight changes and doesn't reset them 336 let g:a = '' 337 set statusline=ab%(cd%1*%{g:a}%)de 338 call assert_match('^abcdde\s*$', s:get_statusline()) 339 let sa1=screenattr(&lines - 1, 1) 340 let sa2=screenattr(&lines - 1, 5) 341 call assert_notequal(sa1, sa2) 342 let g:a = 'X' 343 call assert_match('^abcdXde\s*$', s:get_statusline()) 344 let sa1=screenattr(&lines - 1, 1) 345 let sa2=screenattr(&lines - 1, 5) 346 let sa3=screenattr(&lines - 1, 7) 347 call assert_notequal(sa1, sa2) 348 call assert_equal(sa2, sa3) 349 350 let g:a = '' 351 set statusline=ab%1*%(cd%*%{g:a}%)de 352 call assert_match('^abcdde\s*$', s:get_statusline()) 353 let sa1=screenattr(&lines - 1, 1) 354 let sa2=screenattr(&lines - 1, 3) 355 let sa3=screenattr(&lines - 1, 5) 356 call assert_notequal(sa1, sa2) 357 call assert_equal(sa1, sa3) 358 let g:a = 'X' 359 call assert_match('^abcdXde\s*$', s:get_statusline()) 360 let sa1=screenattr(&lines - 1, 1) 361 let sa2=screenattr(&lines - 1, 3) 362 let sa3=screenattr(&lines - 1, 5) 363 let sa4=screenattr(&lines - 1, 7) 364 call assert_notequal(sa1, sa2) 365 call assert_equal(sa1, sa3) 366 call assert_equal(sa1, sa4) 367 368 let g:a = '' 369 set statusline=%#Error#{%(\ %{g:a}\ %)} 370 call assert_match('^{}\s*$', s:get_statusline()) 371 let g:a = 'X' 372 call assert_match('^{ X }\s*$', s:get_statusline()) 373 374 " %%: a percent sign. 375 set statusline=10%% 376 call assert_match('^10%\s*$', s:get_statusline()) 377 378 " %!: evaluated expression is used as the option value 379 set statusline=%!2*3+1 380 call assert_match('7\s*$', s:get_statusline()) 381 382 func GetNested() 383 call assert_equal(string(win_getid()), g:actual_curwin) 384 call assert_equal(string(bufnr('')), g:actual_curbuf) 385 return 'nested' 386 endfunc 387 func GetStatusLine() 388 call assert_equal(win_getid(), g:statusline_winid) 389 return 'the %{GetNested()} line' 390 endfunc 391 set statusline=%!GetStatusLine() 392 call assert_match('the nested line', s:get_statusline()) 393 call assert_false(exists('g:actual_curwin')) 394 call assert_false(exists('g:actual_curbuf')) 395 call assert_false(exists('g:statusline_winid')) 396 delfunc GetNested 397 delfunc GetStatusLine 398 399 " Test statusline works with 80+ items 400 function! StatusLabel() 401 redrawstatus 402 return '[label]' 403 endfunc 404 let statusline = '%{StatusLabel()}' 405 for i in range(150) 406 let statusline .= '%#TabLine' . (i % 2 == 0 ? 'Fill' : 'Sel') . '#' . string(i)[0] 407 endfor 408 let &statusline = statusline 409 redrawstatus 410 set statusline& 411 delfunc StatusLabel 412 413 414 " Check statusline in current and non-current window 415 " with the 'fillchars' option. 416 set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:- 417 vsplit 418 set statusline=x%=y 419 call assert_match('^x^\+y^x=\+y$', s:get_statusline()) 420 set fillchars& 421 close 422 423 %bw! 424 call delete('Xstatusline') 425 set statusline& 426 set laststatus& 427 set splitbelow& 428endfunc 429 430func Test_statusline_visual() 431 func CallWordcount() 432 call wordcount() 433 endfunc 434 new x1 435 setl statusline=count=%{CallWordcount()} 436 " buffer must not be empty 437 call setline(1, 'hello') 438 439 " window with more lines than x1 440 new x2 441 call setline(1, range(10)) 442 $ 443 " Visual mode in line below liast line in x1 should not give ml_get error 444 call feedkeys("\<C-V>", "xt") 445 redraw 446 447 delfunc CallWordcount 448 bwipe! x1 449 bwipe! x2 450endfunc 451 452func Test_statusline_removed_group() 453 CheckScreendump 454 455 let lines =<< trim END 456 scriptencoding utf-8 457 set laststatus=2 458 let &statusline = '%#StatColorHi2#%(✓%#StatColorHi2#%) Q≡' 459 END 460 call writefile(lines, 'XTest_statusline') 461 462 let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 10, 'cols': 50}) 463 call TermWait(buf, 50) 464 call VerifyScreenDump(buf, 'Test_statusline_1', {}) 465 466 " clean up 467 call StopVimInTerminal(buf) 468 call delete('XTest_statusline') 469endfunc 470 471func Test_statusline_using_mode() 472 CheckScreendump 473 474 let lines =<< trim END 475 setlocal statusline=-%{mode()}- 476 split 477 setlocal statusline=+%{mode()}+ 478 END 479 call writefile(lines, 'XTest_statusline') 480 481 let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 7, 'cols': 50}) 482 call VerifyScreenDump(buf, 'Test_statusline_mode_1', {}) 483 484 call term_sendkeys(buf, ":") 485 call VerifyScreenDump(buf, 'Test_statusline_mode_2', {}) 486 487 " clean up 488 call term_sendkeys(buf, "close\<CR>") 489 call StopVimInTerminal(buf) 490 call delete('XTest_statusline') 491endfunc 492 493func Test_statusline_after_split_vsplit() 494 only 495 496 " Make the status line of each window show the window number. 497 set ls=2 stl=%{winnr()} 498 499 split | redraw 500 vsplit | redraw 501 502 " The status line of the third window should read '3' here. 503 call assert_equal('3', nr2char(screenchar(&lines - 1, 1))) 504 505 only 506 set ls& stl& 507endfunc 508 509" Test using a multibyte character for 'stl' and 'stlnc' items in 'fillchars' 510" with a custom 'statusline' 511func Test_statusline_mbyte_fillchar() 512 only 513 set laststatus=2 514 set fillchars=vert:\|,fold:-,stl:━,stlnc:═ 515 set statusline=a%=b 516 call assert_match('^a\+━\+b$', s:get_statusline()) 517 vnew 518 call assert_match('^a\+━\+b━a\+═\+b$', s:get_statusline()) 519 wincmd w 520 call assert_match('^a\+═\+b═a\+━\+b$', s:get_statusline()) 521 set statusline& fillchars& laststatus& 522 %bw! 523endfunc 524 525" Used to write beyond allocated memory. This assumes MAXPATHL is 4096 bytes. 526func Test_statusline_verylong_filename() 527 let fname = repeat('x', 4090) 528 exe "new " .. fname 529 set buftype=help 530 set previewwindow 531 redraw 532 bwipe! 533endfunc 534 535" vim: shiftwidth=2 sts=2 expandtab 536