1" Test commands that are not compiled in a :def function 2 3source check.vim 4source vim9.vim 5source term_util.vim 6source view_util.vim 7 8def Test_edit_wildcards() 9 var filename = 'Xtest' 10 edit `=filename` 11 assert_equal('Xtest', bufname()) 12 13 var filenr = 123 14 edit Xtest`=filenr` 15 assert_equal('Xtest123', bufname()) 16 17 filenr = 77 18 edit `=filename``=filenr` 19 assert_equal('Xtest77', bufname()) 20 21 edit X`=filename`xx`=filenr`yy 22 assert_equal('XXtestxx77yy', bufname()) 23 24 CheckDefFailure(['edit `=xxx`'], 'E1001:') 25 CheckDefFailure(['edit `="foo"'], 'E1083:') 26enddef 27 28def Test_expand_alternate_file() 29 var lines =<< trim END 30 edit Xfileone 31 var bone = bufnr() 32 edit Xfiletwo 33 var btwo = bufnr() 34 edit Xfilethree 35 var bthree = bufnr() 36 37 edit # 38 assert_equal(bthree, bufnr()) 39 edit %% 40 assert_equal(btwo, bufnr()) 41 edit %% # comment 42 assert_equal(bthree, bufnr()) 43 edit %%yy 44 assert_equal('Xfiletwoyy', bufname()) 45 46 exe "edit %%" .. bone 47 assert_equal(bone, bufnr()) 48 exe "edit %%" .. btwo .. "xx" 49 assert_equal('Xfiletwoxx', bufname()) 50 51 next Xfileone Xfiletwo Xfilethree 52 assert_equal('Xfileone', argv(0)) 53 assert_equal('Xfiletwo', argv(1)) 54 assert_equal('Xfilethree', argv(2)) 55 next %%%zz 56 assert_equal('Xfileone', argv(0)) 57 assert_equal('Xfiletwo', argv(1)) 58 assert_equal('Xfilethreezz', argv(2)) 59 60 v:oldfiles = ['Xonefile', 'Xtwofile'] 61 edit %%<1 62 assert_equal('Xonefile', bufname()) 63 edit %%<2 64 assert_equal('Xtwofile', bufname()) 65 assert_fails('edit %%<3', 'E684:') 66 67 edit Xfileone.vim 68 edit Xfiletwo 69 edit %%:r 70 assert_equal('Xfileone', bufname()) 71 END 72 CheckDefAndScriptSuccess(lines) 73enddef 74 75def Test_global_backtick_expansion() 76 new 77 setline(1, 'xx') 78 var name = 'foobar' 79 g/^xx/s/.*/`=name` 80 assert_equal('foobar', getline(1)) 81 bwipe! 82enddef 83 84def Test_folddo_backtick_expansion() 85 new 86 var name = 'xxx' 87 folddoopen edit `=name` 88 assert_equal('xxx', bufname()) 89 bwipe! 90 91 new 92 setline(1, ['one', 'two']) 93 set nomodified 94 :1,2fold 95 foldclose 96 folddoclose edit `=name` 97 assert_equal('xxx', bufname()) 98 bwipe! 99enddef 100 101def Test_hardcopy_wildcards() 102 CheckUnix 103 CheckFeature postscript 104 105 var outfile = 'print' 106 hardcopy > X`=outfile`.ps 107 assert_true(filereadable('Xprint.ps')) 108 109 delete('Xprint.ps') 110enddef 111 112def Test_syn_include_wildcards() 113 writefile(['syn keyword Found found'], 'Xthemine.vim') 114 var save_rtp = &rtp 115 &rtp = '.' 116 117 var fname = 'mine' 118 syn include @Group Xthe`=fname`.vim 119 assert_match('Found.* contained found', execute('syn list Found')) 120 121 &rtp = save_rtp 122 delete('Xthemine.vim') 123enddef 124 125def Test_echo_linebreak() 126 var lines =<< trim END 127 vim9script 128 redir @a 129 echo 'one' 130 .. 'two' 131 redir END 132 assert_equal("\nonetwo", @a) 133 END 134 CheckScriptSuccess(lines) 135 136 lines =<< trim END 137 vim9script 138 redir @a 139 echo 11 + 140 77 141 - 22 142 redir END 143 assert_equal("\n66", @a) 144 END 145 CheckScriptSuccess(lines) 146enddef 147 148def Test_condition_types() 149 var lines =<< trim END 150 if 'text' 151 endif 152 END 153 CheckDefAndScriptFailure(lines, 'E1135:', 1) 154 155 lines =<< trim END 156 if [1] 157 endif 158 END 159 CheckDefFailure(lines, 'E1012:', 1) 160 CheckScriptFailure(['vim9script'] + lines, 'E745:', 2) 161 162 lines =<< trim END 163 g:cond = 'text' 164 if g:cond 165 endif 166 END 167 CheckDefExecAndScriptFailure(lines, 'E1135:', 2) 168 169 lines =<< trim END 170 g:cond = 0 171 if g:cond 172 elseif 'text' 173 endif 174 END 175 CheckDefFailure(lines, 'E1012:', 3) 176 CheckScriptFailure(['vim9script'] + lines, 'E1135:', 4) 177 178 lines =<< trim END 179 if g:cond 180 elseif [1] 181 endif 182 END 183 CheckDefFailure(lines, 'E1012:', 2) 184 CheckScriptFailure(['vim9script'] + lines, 'E745:', 3) 185 186 lines =<< trim END 187 g:cond = 'text' 188 if 0 189 elseif g:cond 190 endif 191 END 192 CheckDefExecAndScriptFailure(lines, 'E1135:', 3) 193 194 lines =<< trim END 195 while 'text' 196 endwhile 197 END 198 CheckDefFailure(lines, 'E1012:', 1) 199 CheckScriptFailure(['vim9script'] + lines, 'E1135:', 2) 200 201 lines =<< trim END 202 while [1] 203 endwhile 204 END 205 CheckDefFailure(lines, 'E1012:', 1) 206 CheckScriptFailure(['vim9script'] + lines, 'E745:', 2) 207 208 lines =<< trim END 209 g:cond = 'text' 210 while g:cond 211 endwhile 212 END 213 CheckDefExecAndScriptFailure(lines, 'E1135:', 2) 214enddef 215 216def Test_if_linebreak() 217 var lines =<< trim END 218 vim9script 219 if 1 && 220 true 221 || 1 222 g:res = 42 223 endif 224 assert_equal(42, g:res) 225 END 226 CheckScriptSuccess(lines) 227 unlet g:res 228 229 lines =<< trim END 230 vim9script 231 if 1 && 232 0 233 g:res = 0 234 elseif 0 || 235 0 236 || 1 237 g:res = 12 238 endif 239 assert_equal(12, g:res) 240 END 241 CheckScriptSuccess(lines) 242 unlet g:res 243enddef 244 245def Test_while_linebreak() 246 var lines =<< trim END 247 vim9script 248 var nr = 0 249 while nr < 250 10 + 3 251 nr = nr 252 + 4 253 endwhile 254 assert_equal(16, nr) 255 END 256 CheckScriptSuccess(lines) 257 258 lines =<< trim END 259 vim9script 260 var nr = 0 261 while nr 262 < 263 10 264 + 265 3 266 nr = nr 267 + 268 4 269 endwhile 270 assert_equal(16, nr) 271 END 272 CheckScriptSuccess(lines) 273enddef 274 275def Test_for_linebreak() 276 var lines =<< trim END 277 vim9script 278 var nr = 0 279 for x 280 in 281 [1, 2, 3, 4] 282 nr = nr + x 283 endfor 284 assert_equal(10, nr) 285 END 286 CheckScriptSuccess(lines) 287 288 lines =<< trim END 289 vim9script 290 var nr = 0 291 for x 292 in 293 [1, 2, 294 3, 4 295 ] 296 nr = nr 297 + 298 x 299 endfor 300 assert_equal(10, nr) 301 END 302 CheckScriptSuccess(lines) 303enddef 304 305def Test_method_call_linebreak() 306 var lines =<< trim END 307 vim9script 308 var res = [] 309 func RetArg( 310 arg 311 ) 312 let s:res = a:arg 313 endfunc 314 [1, 315 2, 316 3]->RetArg() 317 assert_equal([1, 2, 3], res) 318 END 319 CheckScriptSuccess(lines) 320enddef 321 322def Test_skipped_expr_linebreak() 323 if 0 324 var x = [] 325 ->map(() => 0) 326 endif 327enddef 328 329def Test_dict_member() 330 var test: dict<list<number>> = {data: [3, 1, 2]} 331 test.data->sort() 332 assert_equal({data: [1, 2, 3]}, test) 333 test.data 334 ->reverse() 335 assert_equal({data: [3, 2, 1]}, test) 336 337 var lines =<< trim END 338 vim9script 339 var test: dict<list<number>> = {data: [3, 1, 2]} 340 test.data->sort() 341 assert_equal({data: [1, 2, 3]}, test) 342 END 343 CheckScriptSuccess(lines) 344enddef 345 346def Test_bar_after_command() 347 def RedrawAndEcho() 348 var x = 'did redraw' 349 redraw | echo x 350 enddef 351 RedrawAndEcho() 352 assert_match('did redraw', Screenline(&lines)) 353 354 def CallAndEcho() 355 var x = 'did redraw' 356 reg_executing() | echo x 357 enddef 358 CallAndEcho() 359 assert_match('did redraw', Screenline(&lines)) 360 361 if has('unix') 362 # bar in filter write command does not start new command 363 def WriteToShell() 364 new 365 setline(1, 'some text') 366 w !cat | cat > Xoutfile 367 bwipe! 368 enddef 369 WriteToShell() 370 assert_equal(['some text'], readfile('Xoutfile')) 371 delete('Xoutfile') 372 373 # bar in filter read command does not start new command 374 def ReadFromShell() 375 new 376 r! echo hello there | cat > Xoutfile 377 r !echo again | cat >> Xoutfile 378 bwipe! 379 enddef 380 ReadFromShell() 381 assert_equal(['hello there', 'again'], readfile('Xoutfile')) 382 delete('Xoutfile') 383 endif 384enddef 385 386def Test_filter_is_not_modifier() 387 var tags = [{a: 1, b: 2}, {x: 3, y: 4}] 388 filter(tags, ( _, v) => has_key(v, 'x') ? 1 : 0 ) 389 assert_equal([{x: 3, y: 4}], tags) 390enddef 391 392def Test_command_modifier_filter() 393 var lines =<< trim END 394 final expected = "\nType Name Content\n c \"c piyo" 395 @a = 'hoge' 396 @b = 'fuga' 397 @c = 'piyo' 398 399 assert_equal(execute('filter /piyo/ registers abc'), expected) 400 END 401 CheckDefAndScriptSuccess(lines) 402enddef 403 404def Test_win_command_modifiers() 405 assert_equal(1, winnr('$')) 406 407 set splitright 408 vsplit 409 assert_equal(2, winnr()) 410 close 411 aboveleft vsplit 412 assert_equal(1, winnr()) 413 close 414 set splitright& 415 416 vsplit 417 assert_equal(1, winnr()) 418 close 419 belowright vsplit 420 assert_equal(2, winnr()) 421 close 422 rightbelow vsplit 423 assert_equal(2, winnr()) 424 close 425 426 if has('browse') 427 browse set 428 assert_equal('option-window', expand('%')) 429 close 430 endif 431 432 vsplit 433 botright split 434 assert_equal(3, winnr()) 435 assert_equal(&columns, winwidth(0)) 436 close 437 close 438 439 vsplit 440 topleft split 441 assert_equal(1, winnr()) 442 assert_equal(&columns, winwidth(0)) 443 close 444 close 445 446 gettabinfo()->len()->assert_equal(1) 447 tab split 448 gettabinfo()->len()->assert_equal(2) 449 tabclose 450 451 vertical new 452 assert_inrange(&columns / 2 - 2, &columns / 2 + 1, winwidth(0)) 453 close 454enddef 455 456func Test_command_modifier_confirm() 457 CheckNotGui 458 CheckRunVimInTerminal 459 460 " Test for saving all the modified buffers 461 let lines =<< trim END 462 call setline(1, 'changed') 463 def Getout() 464 confirm write Xfile 465 enddef 466 END 467 call writefile(lines, 'Xconfirmscript') 468 call writefile(['empty'], 'Xfile') 469 let buf = RunVimInTerminal('-S Xconfirmscript', {'rows': 8}) 470 call term_sendkeys(buf, ":call Getout()\n") 471 call WaitForAssert({-> assert_match('(Y)es, \[N\]o: ', term_getline(buf, 8))}, 1000) 472 call term_sendkeys(buf, "y") 473 call WaitForAssert({-> assert_match('(Y)es, \[N\]o: ', term_getline(buf, 8))}, 1000) 474 call term_sendkeys(buf, "\<CR>") 475 call TermWait(buf) 476 call StopVimInTerminal(buf) 477 478 call assert_equal(['changed'], readfile('Xfile')) 479 call delete('Xfile') 480 call delete('.Xfile.swp') " in case Vim was killed 481 call delete('Xconfirmscript') 482endfunc 483 484def Test_command_modifiers_keep() 485 if has('unix') 486 def DoTest(addRflag: bool, keepMarks: bool, hasMarks: bool) 487 new 488 setline(1, ['one', 'two', 'three']) 489 normal 1Gma 490 normal 2Gmb 491 normal 3Gmc 492 if addRflag 493 set cpo+=R 494 else 495 set cpo-=R 496 endif 497 if keepMarks 498 keepmarks :%!cat 499 else 500 :%!cat 501 endif 502 if hasMarks 503 assert_equal(1, line("'a")) 504 assert_equal(2, line("'b")) 505 assert_equal(3, line("'c")) 506 else 507 assert_equal(0, line("'a")) 508 assert_equal(0, line("'b")) 509 assert_equal(0, line("'c")) 510 endif 511 quit! 512 enddef 513 DoTest(false, false, true) 514 DoTest(true, false, false) 515 DoTest(false, true, true) 516 DoTest(true, true, true) 517 set cpo&vim 518 519 new 520 setline(1, ['one', 'two', 'three', 'four']) 521 assert_equal(4, line("$")) 522 normal 1Gma 523 normal 2Gmb 524 normal 3Gmc 525 lockmarks :1,2!wc 526 # line is deleted, marks don't move 527 assert_equal(3, line("$")) 528 assert_equal('four', getline(3)) 529 assert_equal(1, line("'a")) 530 assert_equal(2, line("'b")) 531 assert_equal(3, line("'c")) 532 quit! 533 endif 534 535 edit Xone 536 edit Xtwo 537 assert_equal('Xone', expand('#')) 538 keepalt edit Xthree 539 assert_equal('Xone', expand('#')) 540 541 normal /a*b* 542 assert_equal('a*b*', histget("search")) 543 keeppatterns normal /c*d* 544 assert_equal('a*b*', histget("search")) 545 546 new 547 setline(1, range(10)) 548 :10 549 normal gg 550 assert_equal(10, getpos("''")[1]) 551 keepjumps normal 5G 552 assert_equal(10, getpos("''")[1]) 553 quit! 554enddef 555 556def Test_bar_line_continuation() 557 var lines =<< trim END 558 au BufNewFile Xfile g:readFile = 1 559 | g:readExtra = 2 560 g:readFile = 0 561 g:readExtra = 0 562 edit Xfile 563 assert_equal(1, g:readFile) 564 assert_equal(2, g:readExtra) 565 bwipe! 566 au! BufNewFile 567 568 au BufNewFile Xfile g:readFile = 1 569 | g:readExtra = 2 570 | g:readMore = 3 571 g:readFile = 0 572 g:readExtra = 0 573 g:readMore = 0 574 edit Xfile 575 assert_equal(1, g:readFile) 576 assert_equal(2, g:readExtra) 577 assert_equal(3, g:readMore) 578 bwipe! 579 au! BufNewFile 580 unlet g:readFile 581 unlet g:readExtra 582 unlet g:readMore 583 END 584 CheckDefAndScriptSuccess(lines) 585enddef 586 587def Test_command_modifier_other() 588 new Xsomefile 589 setline(1, 'changed') 590 var buf = bufnr() 591 hide edit Xotherfile 592 var info = getbufinfo(buf) 593 assert_equal(1, info[0].hidden) 594 assert_equal(1, info[0].changed) 595 edit Xsomefile 596 bwipe! 597 598 au BufNewFile Xfile g:readFile = 1 599 g:readFile = 0 600 edit Xfile 601 assert_equal(1, g:readFile) 602 bwipe! 603 g:readFile = 0 604 noautocmd edit Xfile 605 assert_equal(0, g:readFile) 606 au! BufNewFile 607 unlet g:readFile 608 609 noswapfile edit XnoSwap 610 assert_equal(false, &l:swapfile) 611 bwipe! 612 613 var caught = false 614 try 615 sandbox !ls 616 catch /E48:/ 617 caught = true 618 endtry 619 assert_true(caught) 620 621 :8verbose g:verbose_now = &verbose 622 assert_equal(8, g:verbose_now) 623 unlet g:verbose_now 624enddef 625 626def EchoHere() 627 echomsg 'here' 628enddef 629def EchoThere() 630 unsilent echomsg 'there' 631enddef 632 633def Test_modifier_silent_unsilent() 634 echomsg 'last one' 635 silent echomsg "text" 636 assert_equal("\nlast one", execute(':1messages')) 637 638 silent! echoerr "error" 639 640 echomsg 'last one' 641 silent EchoHere() 642 assert_equal("\nlast one", execute(':1messages')) 643 644 silent EchoThere() 645 assert_equal("\nthere", execute(':1messages')) 646 647 try 648 silent eval [][0] 649 catch 650 echomsg "caught" 651 endtry 652 assert_equal("\ncaught", execute(':1messages')) 653enddef 654 655def Test_range_after_command_modifier() 656 CheckScriptFailure(['vim9script', 'silent keepjump 1d _'], 'E1050: Colon required before a range: 1d _', 2) 657 new 658 setline(1, 'xxx') 659 CheckScriptSuccess(['vim9script', 'silent keepjump :1d _']) 660 assert_equal('', getline(1)) 661 bwipe! 662enddef 663 664def Test_silent_pattern() 665 new 666 silent! :/pat/put _ 667 bwipe! 668enddef 669 670def Test_eval_command() 671 var from = 3 672 var to = 5 673 g:val = 111 674 def Increment(nrs: list<number>) 675 for nr in nrs 676 g:val += nr 677 endfor 678 enddef 679 eval range(from, to) 680 ->Increment() 681 assert_equal(111 + 3 + 4 + 5, g:val) 682 unlet g:val 683 684 var lines =<< trim END 685 vim9script 686 g:caught = 'no' 687 try 688 eval 123 || 0 689 catch 690 g:caught = 'yes' 691 endtry 692 assert_equal('yes', g:caught) 693 unlet g:caught 694 END 695 CheckScriptSuccess(lines) 696enddef 697 698def Test_map_command() 699 var lines =<< trim END 700 nnoremap <F3> :echo 'hit F3 #'<CR> 701 assert_equal(":echo 'hit F3 #'<CR>", maparg("<F3>", "n")) 702 END 703 CheckDefSuccess(lines) 704 CheckScriptSuccess(['vim9script'] + lines) 705enddef 706 707def Test_normal_command() 708 new 709 setline(1, 'doesnotexist') 710 var caught = 0 711 try 712 exe "norm! \<C-]>" 713 catch /E433/ 714 caught = 2 715 endtry 716 assert_equal(2, caught) 717 718 try 719 exe "norm! 3\<C-]>" 720 catch /E433/ 721 caught = 3 722 endtry 723 assert_equal(3, caught) 724 bwipe! 725enddef 726 727def Test_put_command() 728 new 729 @p = 'ppp' 730 put p 731 assert_equal('ppp', getline(2)) 732 733 put ='below' 734 assert_equal('below', getline(3)) 735 put! ='above' 736 assert_equal('above', getline(3)) 737 assert_equal('below', getline(4)) 738 739 # compute range at runtime 740 setline(1, range(1, 8)) 741 @a = 'aaa' 742 :$-2put a 743 assert_equal('aaa', getline(7)) 744 745 setline(1, range(1, 8)) 746 :2 747 :+2put! a 748 assert_equal('aaa', getline(4)) 749 750 bwipe! 751 752 CheckDefFailure(['put =xxx'], 'E1001:') 753enddef 754 755def Test_put_with_linebreak() 756 new 757 var lines =<< trim END 758 vim9script 759 pu =split('abc', '\zs') 760 ->join() 761 END 762 CheckScriptSuccess(lines) 763 getline(2)->assert_equal('a b c') 764 bwipe! 765enddef 766 767def Test_command_star_range() 768 new 769 setline(1, ['xxx foo xxx', 'xxx bar xxx', 'xxx foo xx bar']) 770 setpos("'<", [0, 1, 0, 0]) 771 setpos("'>", [0, 3, 0, 0]) 772 :*s/\(foo\|bar\)/baz/g 773 getline(1, 3)->assert_equal(['xxx baz xxx', 'xxx baz xxx', 'xxx baz xx baz']) 774 775 bwipe! 776enddef 777 778def Test_f_args() 779 var lines =<< trim END 780 vim9script 781 782 func SaveCmdArgs(...) 783 let g:args = a:000 784 endfunc 785 786 command -nargs=* TestFArgs call SaveCmdArgs(<f-args>) 787 788 TestFArgs 789 assert_equal([], g:args) 790 791 TestFArgs one two three 792 assert_equal(['one', 'two', 'three'], g:args) 793 END 794 CheckScriptSuccess(lines) 795enddef 796 797def Test_user_command_comment() 798 command -nargs=1 Comd echom <q-args> 799 800 var lines =<< trim END 801 vim9script 802 Comd # comment 803 END 804 CheckScriptSuccess(lines) 805 806 lines =<< trim END 807 vim9script 808 Comd# comment 809 END 810 CheckScriptFailure(lines, 'E1144:') 811 812 delcommand Comd 813enddef 814 815def Test_star_command() 816 var lines =<< trim END 817 vim9script 818 @s = 'g:success = 8' 819 set cpo+=* 820 exe '*s' 821 assert_equal(8, g:success) 822 unlet g:success 823 set cpo-=* 824 assert_fails("exe '*s'", 'E1050:') 825 END 826 CheckScriptSuccess(lines) 827enddef 828 829def Test_cmd_argument_without_colon() 830 new Xfile 831 setline(1, ['a', 'b', 'c', 'd']) 832 write 833 edit +3 % 834 assert_equal(3, getcurpos()[1]) 835 edit +/a % 836 assert_equal(1, getcurpos()[1]) 837 bwipe 838 delete('Xfile') 839enddef 840 841def Test_ambiguous_user_cmd() 842 command Cmd1 eval 0 843 command Cmd2 eval 0 844 var lines =<< trim END 845 Cmd 846 END 847 CheckDefAndScriptFailure(lines, 'E464:', 1) 848 delcommand Cmd1 849 delcommand Cmd2 850enddef 851 852def Test_command_not_recognized() 853 var lines =<< trim END 854 d.key = 'asdf' 855 END 856 CheckDefFailure(lines, 'E1146:', 1) 857 858 lines =<< trim END 859 d['key'] = 'asdf' 860 END 861 CheckDefFailure(lines, 'E1146:', 1) 862enddef 863 864def Test_magic_not_used() 865 new 866 for cmd in ['set magic', 'set nomagic'] 867 exe cmd 868 setline(1, 'aaa') 869 s/.../bbb/ 870 assert_equal('bbb', getline(1)) 871 endfor 872 873 set magic 874 setline(1, 'aaa') 875 assert_fails('s/.\M../bbb/', 'E486:') 876 assert_fails('snomagic/.../bbb/', 'E486:') 877 assert_equal('aaa', getline(1)) 878 879 bwipe! 880enddef 881 882def Test_gdefault_not_used() 883 new 884 for cmd in ['set gdefault', 'set nogdefault'] 885 exe cmd 886 setline(1, 'aaa') 887 s/./b/ 888 assert_equal('baa', getline(1)) 889 endfor 890 891 set nogdefault 892 bwipe! 893enddef 894 895def g:SomeComplFunc(findstart: number, base: string): any 896 if findstart 897 return 0 898 else 899 return ['aaa', 'bbb'] 900 endif 901enddef 902 903def Test_insert_complete() 904 # this was running into an error with the matchparen hack 905 new 906 set completefunc=SomeComplFunc 907 feedkeys("i\<c-x>\<c-u>\<Esc>", 'ntx') 908 assert_equal('aaa', getline(1)) 909 910 set completefunc= 911 bwipe! 912enddef 913 914def Test_wincmd() 915 split 916 var id1 = win_getid() 917 if true 918 try | wincmd w | catch | endtry 919 endif 920 assert_notequal(id1, win_getid()) 921 close 922enddef 923 924def Test_windo_missing_endif() 925 var lines =<< trim END 926 windo if 1 927 END 928 CheckDefExecFailure(lines, 'E171:', 1) 929enddef 930 931" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 932