├── README.md ├── doc └── learnviml.txt ├── plugin └── learnviml.vim ├── sample └── recipe.vim ├── scraps └── vimlpoo.vim ├── syntax └── lvlindex.vim ├── test ├── _setup.vim └── test001.vim └── todo.txt /README.md: -------------------------------------------------------------------------------- 1 | The Way of the VimL Wizard 2 | ========================== 3 | 4 | A suggested path for learning Vim's scripting language, VimL. 5 | 6 | This help file teaches the VimL scripting language using a progressive 7 | set of reading assignments and followup hands-on exercises. It is aimed 8 | primarily at existing programmers, however beginners can do the external 9 | tutorials referenced within. 10 | 11 | *LearnVimL* 12 | 13 | * is written _in_ Vim help format, internal to Vim itself 14 | * has comprehensive coverage of VimL, from basics to the gritty stuff with 15 | maps, :redir, plugins, etc. 16 | * relies heavily on the existing Vim documentation with assessment questions, 17 | exercises and challenges to reinforce learning 18 | * comes with a searchable set of sample code snippets covering the builtin 19 | functions and idiomatic VimL 20 | * authored by a group of experienced VimL coders, each sharing their individual 21 | skills, tips and tricks to rapidly steer you toward VimL excellence. 22 | 23 | Install 24 | ------- 25 | 26 | * **Linux / OS X:** 27 | 28 | Copy http://github.com/dahu/LearnVimL/raw/master/doc/learnviml.txt to your ~/.vim/doc/ directory. 29 | 30 | * **Windows:** 31 | 32 | Copy http://github.com/dahu/LearnVimL/raw/master/doc/learnviml.txt to your $HOME\vimfiles\doc\ directory. 33 | 34 | Run :helptags ~/.vim/doc/ from within Vim. 35 | Type :help learnviml to get started. 36 | -------------------------------------------------------------------------------- /doc/learnviml.txt: -------------------------------------------------------------------------------- 1 | *learnviml.txt* A Suggested Path for Learning VimL 2 | 3 | This help file teaches the VimL scripting language using a progressive 4 | set of reading assignments and followup hands-on exercises. It is aimed 5 | primarily at existing programmers, however beginners can do the external 6 | tutorials referenced below. 7 | 8 | LearnVimL~ 9 | 10 | * is written -in- Vim help format, internal to Vim itself 11 | * has comprehensive coverage of VimL, from basics to the gritty stuff with 12 | maps, :redir, plugins, etc. 13 | * relies heavily on the existing Vim documentation with assessment questions, 14 | exercises and challenges to reinforce learning 15 | * comes with a searchable set of sample code snippets covering the builtin 16 | functions and idiomatic VimL 17 | * authored by a group of experienced VimL coders, each sharing their individual 18 | skills, tips and tricks to rapidly steer you toward VimL excellence. 19 | 20 | This file is structured with the following conventions: 21 | 22 | CHAPTER HEADINGS are all caps and preceded by a line of # characters. 23 | SECTIONS within a Chapter are all caps and preceded by a line of = characters. 24 | 1. Topics within a Section are numbered, in Title Case. 25 | Exercises are blocked in lines of - characters. 26 | 27 | ############################################################################## 28 | LEARNVIML TABLE OF CONTENTS *learnviml-toc* 29 | 30 | |learnviml-Introduction| 31 | |learnviml-Searchable-Samples| 32 | |learnviml-Syntax| 33 | |learnviml-Builtin-Functions| 34 | |learnviml-Exceptions| 35 | |learnviml-Plugins| 36 | |learnviml-OOP| 37 | |learnviml-Functional(-ish)| 38 | |learnviml-Challenges| 39 | 40 | ############################################################################## 41 | INTRODUCTION *learnviml-Introduction* 42 | 43 | What is VimL? In simple terms, it's Vim's scripting language, but the full 44 | answer is a little more complicated than that. It's actually more than one 45 | language; it's a procedural expression language (with prototypal OOP 46 | extensions) wrapped around a declarative command language (called Ex). It has 47 | builtin regular expressions making text manipulation easier, a comprehensive 48 | library of builtin functions for manipulating strings, floats, lists and 49 | dictionaries as well as Vim editor objects like buffers, windows, tabs and the 50 | myriad auxiliary entities surrounding them. It supports procedural, 51 | functional(-ish) and object-oriented approaches to software development. It may 52 | not be the prettiest language in the world, but it definitely gets the job 53 | done. 54 | 55 | I intend here to walk you through the most important parts of the Vim Reference 56 | Manual and User Guide pertaining to VimL. If you would rather read the essence 57 | from start to end on your own, then: 58 | 59 | * The builtin reference manual for VimL is |usr_41.txt| 60 | * The expression language is covered in |eval.txt| 61 | 62 | If you would like a more colourful, friendly and gentler introduction to the 63 | wonderful world of VimL coding then see: 64 | 65 | * Damian Conway's Beginner's Guide to VimL: 66 | http://www.ibm.com/developerworks/linux/library/l-vim-script-1/index.html 67 | 68 | * Steve Losh's Learn VimL the Hard Way: 69 | http://learnvimscriptthehardway.stevelosh.com/ 70 | 71 | If you're still with me, let's dive in: 72 | 73 | ############################################################################## 74 | SEARCHABLE SAMPLES *learnviml-Searchable-Samples* 75 | *:LVL* *LVL* 76 | 77 | When one of the authors first learnt to program it was with the wonderful 78 | Borland Turbo C compiler. One of the best things about Turbo C was that it 79 | came with extensive documentation for the standard C libraries. Each function 80 | had a complete standalone snippet showing its usage. 81 | 82 | In an attempt to emulate that excellence, LearnVimL comes with a builtin 83 | command, :LVL which searches the bundled samples for the given term, 84 | displaying a title-list of matches. These matches are shown in the 85 | |location-list|, so presisng on a list item will open up the 86 | associated snippet in an editable buffer of its own. From there you can 87 | |:source| the code to see it run and play with it for better understanding. 88 | 89 | ############################################################################## 90 | SYNTAX *learnviml-Syntax* 91 | 92 | Before Vim, there was vi and it didn't have VimL as we know it today; it only 93 | had Ex. VimL extends Ex with a procedural expression language which provides 94 | looping constructs, conditional expressions and a rich expression language 95 | with versatile data structures like lists (dynamic arrays) and dictionaries 96 | (associative arrays, aka hashes/maps). 97 | 98 | Before we jump into all that goodness, though, we ought to look at bare Ex 99 | commands and the way they are invoked from within Vim. 100 | 101 | Read the following parts of |cmdline.txt| 102 | 3. Ex command-lines |cmdline-lines| 103 | 4. Ex command-line ranges |cmdline-ranges| 104 | 6. Ex special characters |cmdline-special| 105 | 106 | Throughout this tutorial we will follow up the reading sections with little 107 | quizzes to make sure you're staying awake and keeping up. 108 | 109 | -------------------------------------------------------------------------- 110 | Exercise Set 1: The Ex Language 111 | 112 | 1.0 What is the Ex language and what is it used for in Vim? 113 | 114 | 1.1 How does it relate to VimL? 115 | 116 | 2.0 How do you comment out an Ex line? 117 | 118 | 2.1 How do you feel about this? Can you imagine any conflicts 119 | this might cause? 120 | 121 | 2.2 Which commands can't take a trailing comment? Why? 122 | 123 | 3.0 The ';' is used in shell and C to separate commands. How do 124 | you separate commands in Ex? 125 | 126 | 3.1 How do you escape the Ex command separator? 127 | 128 | 3.2 Which commands cannot use this command separator? Why? 129 | 130 | 3.3 How do you overcome this limitation? 131 | 132 | 3.4 The developer wanted to replace all apples with bananas and 133 | all cherries with durians, but his approach was broken. Why? 134 | Fix it: (two acceptable solutions) 135 | 136 | :%s/apple/banana/|s/cherry/durian/ 137 | 138 | 3.5 External commands (using the shell) consume the standard Ex 139 | command separator. What is the solution to this problem? 140 | 141 | 4.0 What meanings do '%' and '#' have on the Ex command line? When? 142 | 143 | 4.1 Explain the difference between these two commands: 144 | 145 | :w! name 146 | :w !name 147 | 148 | 5.0 Explain the difference between using ',' and ';' in command-line 149 | ranges. 150 | 151 | 5.1 What do the following special ranges evaluate to? 152 | 153 | . 154 | $ 155 | % 156 | 157 | 5.2 What is the command for the range from the line after the next 158 | occurrence of '^Chapter' and 5 lines before a subsequent '^Example'? 159 | 160 | 6.0 How do you insert the name of the current buffer into a command-line 161 | command? There are two solutions. 162 | 163 | 6.1 Using the |expand()| function, |:echo| the full path name of the 164 | current buffer. 165 | 166 | 6.2 What is the difference between and ? 167 | 168 | 6.3 How do you pull the current up into the command-line? 169 | -------------------------------------------------------------------------- 170 | 171 | While it is assumed that you know how to set and test options in Vim, there 172 | are several enhanced ways to play with options that you should brush up on. 173 | 174 | Read the following parts of |options.txt| 175 | 1. Setting options |set-option| 176 | 177 | In terms of writing VimL, there are around a dozen important options that 178 | influence how your scripts run and how happy you will be writing them. 179 | 180 | 2. Read the following specific options: 181 | * |'debug'| 182 | * |'eventignore'| 183 | * |'ignorecase'| 184 | * |'magic'| 185 | * |'maxfuncdepth'| 186 | * |'runtimepath'| 187 | * |'verbose'| 188 | 189 | -------------------------------------------------------------------------- 190 | Exercise Set 2: VimL-specific Options 191 | 192 | 1.0 What is the difference between these two commands? 193 | 194 | :set ignorecase? 195 | :set ignorecase 196 | 197 | 1.1 Show two ways to display the current value of an option. 198 | (hint: one uses :set and the other uses :echo) 199 | 200 | 1.2 How do you switch off a boolean option? 201 | 202 | 1.3 How do you toggle a boolean option? 203 | 204 | 1.4 What does this command do? 205 | 206 | :set magic&vim 207 | 208 | 1.5 How do you append values to string options? 209 | 210 | 1.6 How do you prepend values to string options? 211 | 212 | 1.7 How do you find out which script last set an option? 213 | 214 | 1.8 How do you include whitespace and backslashes in option values? 215 | 216 | 1.9 What are local options? How do they differ to global options? 217 | What is the command to set local options? 218 | 219 | 1.10 How do you set the global value for a local option without altering 220 | the local value? 221 | 222 | 1.11 What is the difference between: 223 | 224 | :set ft=lisp 225 | :setf lisp 226 | 227 | 1.12 What are the two commands which open the interactive options browser? 228 | 229 | 3.0 When Vim is executing VimL in certain deeply nested situations, errors 230 | are often blindly ignored leaving the developer perplexed as to the 231 | source of problems. Name one way the developer can force Vim to show 232 | errors. 233 | 234 | 4.0 What are some reasons you could think of for the |'eventignore'| option? 235 | 236 | 5.0 Apart from setting |'ignorecase'|, what is another way the VimL 237 | developer can ensure case-sensitive matches? 238 | 239 | 6.0 Should you ever change the value of the |'magic'| option? 240 | What should you do to a developer who does? 241 | 242 | 7.0 Why does VimL have the |'maxfuncdepth'| option? What is the default 243 | depth? When would you increase this value? 244 | 245 | 8.0 What effect would altering the |'runtimepath'| have in the ~/.vimrc 246 | file? What type of plugin would rely heavily on this feature? 247 | 248 | 9.0 What does :set verbose=12 do? When would you need to do that? 249 | 250 | 9.1 How can you solve the problem of information overload with the 251 | verbose option? 252 | -------------------------------------------------------------------------- 253 | 254 | VimL has native support for inline regular expressions, similar to Perl. This 255 | makes VimL especially useful for manipulating text, a very common task for Vim 256 | scripts, naturally. Vim's flavour of regular expressions is not like Perl / 257 | PCRE, but it is nearly as powerful. In some cases, Vim provides even more 258 | expressiveness than Perl regexes. You can read about the differences in 259 | |perl-patterns|. 260 | 261 | Read all of |pattern.txt| 262 | 263 | -------------------------------------------------------------------------- 264 | Exercise Set 3: Install and complete https://github.com/dahu/VimRegexTutor 265 | -------------------------------------------------------------------------- 266 | 267 | Everything in |eval.txt| is new to Vim and constitutes the Expression Language 268 | portion of VimL - the stuff that people expect when they think of a 269 | programming language: variables, conditionals, loops, functions, data types, 270 | etc. Finally we're getting a look at the real language behind VimL. 271 | 272 | Read from |variables| through to |sticky-type-checking| in |eval.txt| 273 | 274 | -------------------------------------------------------------------------- 275 | Exercise Set 4: Variables 276 | 277 | 1.0 How many types of variables does VimL support? 278 | 279 | 1.1 Read |type()|. What is a better way to say: 280 | 281 | if type(somevar) == 2 282 | 283 | 1.2 How does VimL represent hexadecimal and octal numbers? 284 | 285 | 1.3 This is broken, fix it: 286 | 287 | if "foo" 288 | echo "you should see this" 289 | endif 290 | -------------------------------------------------------------------------- 291 | 292 | Read |char2nr()| , |nr2char()|, |str2nr()| , |str2float()| , and |printf()| 293 | for explicit ways to convert between Numbers and Strings in VimL. 294 | 295 | -------------------------------------------------------------------------- 296 | Exercise Set 5: Explicit Number Type Conversions 297 | 298 | 1.0 What could you imagine using |char2nr()| and |nr2char()| for? 299 | 300 | 2.0 We can use echo "0x100" + 0 to convert the string to a number. How 301 | would you convert hexadecimal 100 to decimal without this string trick? 302 | 303 | 3.0 How would you convert 100 decimal to hexadecimal? 304 | 305 | -------------------------------------------------------------------------- 306 | 307 | Read |NL-used-for-Nul| and |CR-used-for-NL| in |pattern.txt| 308 | 309 | -------------------------------------------------------------------------- 310 | Exercise Set 6: Vim's Dirty , and Relationship 311 | 312 | 1.0 Don't you wish you hadn't read that? 313 | -------------------------------------------------------------------------- 314 | 315 | Read sections |41.1| - |41.2| in |usr_41.txt| 316 | 317 | -------------------------------------------------------------------------- 318 | Exercise Set 7: Expressions 319 | 320 | 1.0 Vim's command-line mode is initiated with the ':' key. Is it legal to 321 | start script commands in a vim file with a ':'? 322 | 323 | 1.1 If you visually highlight and yank a bunch of VimL lines from a buffer, 324 | how can you subsequently execute them? 325 | Hint: This is very useful for adhoc debugging and testing of stuff you 326 | find in the manuals. 327 | 328 | 2.0 What's the difference between |:set| and |:let| ? 329 | 330 | 3.0 How do you stop a long-running loop in Vim? 331 | 332 | 4.0 VimL doesn't support the ++ operator like C/C++ does. What does VimL 333 | provide as a shortcut instead of: 334 | 335 | :let i = i + 1 336 | 337 | 5.0 What does prepending s: to a variable do in VimL, like: 338 | 339 | :let s:count = 0 340 | 341 | 6.0 Why doesn't this for-loop work? Fix it without just reordering the list 342 | elements. 343 | 344 | for x in [1, 2.0, "3"] 345 | echo x 346 | endfor 347 | 348 | Hint: the variable, x, can't change (between certain) types 349 | 350 | 7.0 Why is this code not what the developer intended? Fix it. 351 | 352 | if !exists(extension) 353 | let extension = '.vim' 354 | endif 355 | 356 | 8.0 What is the difference between 'single-quoted' and "double-quoted" 357 | strings? Which type should you use? 358 | -------------------------------------------------------------------------- 359 | 360 | Read |internal-variables| in |eval.txt| and the subsequent entries on each 361 | internal variable type. 362 | 363 | -------------------------------------------------------------------------- 364 | Exercise Set 9: Internal Variables 365 | -------------------------------------------------------------------------- 366 | 367 | Read |expression-syntax| in |eval.txt| and sections |41.3| in |usr_41.txt| 368 | 369 | -------------------------------------------------------------------------- 370 | Exercise Set 8: Expressions 371 | -------------------------------------------------------------------------- 372 | 373 | Read |expression-commands| in |eval.txt| and section |41.4| in |usr_41.txt| 374 | 375 | -------------------------------------------------------------------------- 376 | Exercise Set 10: Expression Commands (VimL Statements) 377 | 378 | x.0 How do you use |:let| to change an option in Vim? 379 | -------------------------------------------------------------------------- 380 | 381 | Read section |41.5| in |usr_41.txt| 382 | 383 | -------------------------------------------------------------------------- 384 | Exercise Set 11: Executing Expressions 385 | -------------------------------------------------------------------------- 386 | 387 | Read |user-functions| in |eval.txt| and section |41.7| in |usr_41.txt| 388 | 389 | -------------------------------------------------------------------------- 390 | Exercise Set 12: Defining, Listing, Debugging and Deleting Functions 391 | -------------------------------------------------------------------------- 392 | 393 | Most modern scripting languages (from Awk onwards, if memory serves) offer 394 | arrays and associative arrays (also called hashes, maps or dictionaries) 395 | because many programming needs are adequately met with just these two data 396 | structures. VimL has these two data structures too, referring to them as Lists 397 | and Dictionaries respectively: Lists are integer indexed arrays, and 398 | Dictionaries are string indexed associative arrays. 399 | 400 | Read section |41.8| in |usr_41.txt| , but for now, skip over the Object 401 | Oriented part. This topic is covered later in |learnviml-OOP| . 402 | 403 | -------------------------------------------------------------------------- 404 | Exercise Set 13: Lists and Dictionaries 405 | -------------------------------------------------------------------------- 406 | 407 | Read |eval-examples| in |eval.txt| 408 | 409 | -------------------------------------------------------------------------- 410 | Exercise Set 14: Intermediate Challenges 411 | *Todo Using the |eval-examples| as inspiration, pose a set of 412 | suitable challenges that exercise the expression language. If builtin 413 | functions are required in the solutions, list them in a hints section. 414 | -------------------------------------------------------------------------- 415 | 416 | ############################################################################## 417 | BUILTIN FUNCTIONS *learnviml-Builtin-Functions* 418 | 419 | Browse through the |function-list|, Vim's built-in VimL library containing 420 | more than 250 functions for working with strings, numbers, lists, 421 | dictionaries, buffers, windows, tabs, the arg-list, system commands, file 422 | operations, and many more of the Vim internals. The following exercises are 423 | designed to expose you to many of the useful functions in this library. You 424 | don't have to do all of these exercises now; you could instead use this 425 | section as a type of reference manual practice-ground - a great place to spend 426 | some quality Deliberate Practice on a quiet Friday night. In that vein, keep 427 | in mind LearnVimL's built-in |:LVL| function for searching the code samples. 428 | 429 | -------------------------------------------------------------------------- 430 | Exercise Set 15: Builtin String Functions 431 | -------------------------------------------------------------------------- 432 | 433 | -------------------------------------------------------------------------- 434 | Exercise Set 16: Builtin Float Functions 435 | -------------------------------------------------------------------------- 436 | 437 | -------------------------------------------------------------------------- 438 | Exercise Set 17: Builtin List Functions 439 | -------------------------------------------------------------------------- 440 | 441 | -------------------------------------------------------------------------- 442 | Exercise Set 18: Builtin Dictionary Functions 443 | -------------------------------------------------------------------------- 444 | 445 | -------------------------------------------------------------------------- 446 | Exercise Set 19: Builtin Bitwise Functions 447 | -------------------------------------------------------------------------- 448 | 449 | -------------------------------------------------------------------------- 450 | Exercise Set 20: Builtin Var Functions 451 | -------------------------------------------------------------------------- 452 | 453 | -------------------------------------------------------------------------- 454 | Exercise Set 21: Builtin Cursor and Mark Functions 455 | -------------------------------------------------------------------------- 456 | 457 | -------------------------------------------------------------------------- 458 | Exercise Set 22: Builtin Buffer Text Functions 459 | -------------------------------------------------------------------------- 460 | 461 | -------------------------------------------------------------------------- 462 | Exercise Set 23: Builtin System and File Functions 463 | -------------------------------------------------------------------------- 464 | 465 | -------------------------------------------------------------------------- 466 | Exercise Set 24: Builtin Date and Time Functions 467 | -------------------------------------------------------------------------- 468 | 469 | -------------------------------------------------------------------------- 470 | Exercise Set 25: Builtin Buffer, Window, Tab and Arg Functions 471 | -------------------------------------------------------------------------- 472 | 473 | -------------------------------------------------------------------------- 474 | Exercise Set 26: Builtin Command-line Functions 475 | -------------------------------------------------------------------------- 476 | 477 | -------------------------------------------------------------------------- 478 | Exercise Set 27: Builtin Quickfix Functions 479 | -------------------------------------------------------------------------- 480 | 481 | -------------------------------------------------------------------------- 482 | Exercise Set 28: Builtin Completion Functions 483 | -------------------------------------------------------------------------- 484 | 485 | -------------------------------------------------------------------------- 486 | Exercise Set 29: Builtin Folding Functions 487 | -------------------------------------------------------------------------- 488 | 489 | -------------------------------------------------------------------------- 490 | Exercise Set 30: Builtin Syntax and Highlighting Functions 491 | -------------------------------------------------------------------------- 492 | 493 | -------------------------------------------------------------------------- 494 | Exercise Set 31: Builtin Spelling Functions 495 | -------------------------------------------------------------------------- 496 | 497 | -------------------------------------------------------------------------- 498 | Exercise Set 32: Builtin History Functions 499 | -------------------------------------------------------------------------- 500 | 501 | -------------------------------------------------------------------------- 502 | Exercise Set 33: Builtin Interactive Functions 503 | -------------------------------------------------------------------------- 504 | 505 | -------------------------------------------------------------------------- 506 | Exercise Set 34: Builtin GUI Functions 507 | -------------------------------------------------------------------------- 508 | 509 | -------------------------------------------------------------------------- 510 | Exercise Set 35: Builtin Server Functions 511 | -------------------------------------------------------------------------- 512 | 513 | -------------------------------------------------------------------------- 514 | Exercise Set 36: Builtin Window Size Functions 515 | -------------------------------------------------------------------------- 516 | 517 | -------------------------------------------------------------------------- 518 | Exercise Set 37: Miscellaneous Builtin Functions 519 | -------------------------------------------------------------------------- 520 | 521 | All good editors allow its users to override keyboard behaviour. Vim's maps 522 | provide key bindings for all of the different modes including operator pending 523 | mode which lets the Vim developer create custom motions, one of Vim's killer 524 | features. 525 | 526 | Read |map.txt| 527 | Read |map.txt| 528 | Read |'timeout'| option 529 | Read |'maxmapdepth'| option 530 | Read |usr_40.txt| 531 | 532 | -------------------------------------------------------------------------- 533 | Exercise Set 38: Key Maps 534 | -------------------------------------------------------------------------- 535 | 536 | Vim has a rich event system which is programmed through the autocommand 537 | interface. There are around eighty different events in various categories, 538 | like Reading & Writing files; manipulating Buffers, Windows and Tabs; changing 539 | Options; starting and closing Vim; Shell interaction; and tracking cursor 540 | movement and Insert Mode switching. 541 | 542 | Read |autocmd.txt| 543 | Read |filetype.txt| 544 | 545 | -------------------------------------------------------------------------- 546 | Exercise Set 39: Autocommands and Filetypes 547 | -------------------------------------------------------------------------- 548 | 549 | |:normal| is a very handy Ex command for issuing normal-mode commands from 550 | within a script as if they were typed. This is commonly used in user maps and 551 | functions that manipulate the buffer using Vim's native command mode. 552 | 553 | Read |various.txt| 554 | 555 | -------------------------------------------------------------------------- 556 | Exercise Set 40: Redraw, Normal, and External Commands 557 | -------------------------------------------------------------------------- 558 | 559 | One of Vim's killer features is Motions, the ability to manipulate entire 560 | textual clusters as single objects, moving between them, moving them, yanking 561 | and putting them, and visually selecting them for even more complicated 562 | operations. Happily, the Vim developer is also granted the power to create 563 | their own motions to provide these powerful editing benefits to their own 564 | users. 565 | 566 | In regard to |:normal|, read |motion.txt| 567 | 568 | -------------------------------------------------------------------------- 569 | Exercise Set 41: Motions 570 | -------------------------------------------------------------------------- 571 | 572 | ############################################################################## 573 | EXCEPTIONS *learnviml-Exceptions* 574 | 575 | Vim has a try/catch exception model that simplifies the handling of unexpected 576 | failures. 577 | 578 | Read |41.9| in |usr_41.txt| 579 | 580 | -------------------------------------------------------------------------- 581 | Exercise Set 42: Exceptions 582 | -------------------------------------------------------------------------- 583 | 584 | ############################################################################## 585 | PLUGINS *learnviml-Plugins* 586 | 587 | The rite of passage for any Vim developer is to create their own Plugin. Vim 588 | has hundreds of plugins providing incredibly diverse features and 589 | functionality never dreamed of by the original authors, Bill & Bram. In this 590 | section you will learn about the standard components of normal Vim plugins, 591 | but you will also install a helper plugin called Area41 which provides 592 | templates to save you the hassle of putting all the standard work into the 593 | creation of new plugins. This will let you create compliant plugins quickly, 594 | allowing you to focus on the important part - your code. 595 | 596 | Read |41.11| in |usr_41.txt| 597 | 598 | Install the Area41 plugin. 599 | 600 | -------------------------------------------------------------------------- 601 | Exercise Set 43: Writing Normal Plugins 602 | -------------------------------------------------------------------------- 603 | 604 | Every programming language you edit in Vim has a corresponding filetype plugin 605 | in the background which silently reconfigures the various Vim indentation, 606 | syntax, colouring and compilation options whenever you start editing a file of 607 | that type. Here you're going to learn how to write a filetype plugin of your 608 | own. 609 | 610 | Read |41.12| in |usr_41.txt| 611 | 612 | -------------------------------------------------------------------------- 613 | Exercise Set 44: Writing Filetype Plugins 614 | -------------------------------------------------------------------------- 615 | 616 | Big plugins benefit from being broken down into modular pieces. Resource 617 | hungry but seldom run plugins benefit from a load-on-demand launcher. Both of 618 | these techniques are provided by the same "autoload" Library architecture in 619 | Vim. 620 | 621 | Read |41.15| in |usr_41.txt| 622 | 623 | -------------------------------------------------------------------------- 624 | Exercise Set 45: Writing Library Scripts (autoload) 625 | -------------------------------------------------------------------------- 626 | 627 | ############################################################################## 628 | OBJECT ORIENTED VIML *learnviml-OOP* 629 | 630 | VimL uses a prototypal form of Object Oriented design, more similar to 631 | Javascript than class based systems like C++, Java, Python and Ruby. 632 | 633 | VimLPOO Outline 634 | --------------- 635 | [see ./scraps/vimlpoo.vim] 636 | * intro - prototypal, not class based 637 | * reference NERDTree and VimPEG as examples of VimLPOO in the wild 638 | * show simple factory method of object creation 639 | ** show inheritance and polymorphism (http://of-vim-and-vigor.blogspot.com/2013/08/not-classy-vimlpoo.html) 640 | * show alternate way of object creation (a la NEERDTree) 641 | 642 | *Todo Show the two common architectures for VimLPOO 643 | *Todo Show inheritance 644 | 645 | ############################################################################## 646 | FUNCTIONAL(-ISH) VIML *learnviml-Functional(-ish)* 647 | 648 | While VimL is strictly not a functional language, it does offer a few 649 | functional-ish functions that operate on its Lists and Dictionaries which 650 | provide clean and elegant alternatives to procedural solutions. 651 | 652 | Functional(-ish) VimL Outline 653 | ----------------------------- 654 | * show newviml ideas (http://of-vim-and-vigor.blogspot.com/search?q=newviml) 655 | * show anonymous functions (http://of-vim-and-vigor.blogspot.com/2014/01/anonymous-functions-in-viml.html) 656 | 657 | Anonymous Functions~ 658 | 659 | VimL does not natively offer anonymous functions but they can be simulated 660 | with the following helper functions: 661 | 662 | *Todo Insert the Fn() and Fx() helper functions. 663 | 664 | ############################################################################## 665 | CHALLENGES *learnviml-Challenges* 666 | 667 | You now know most of the various pieces that constitute the VimL landscape. 668 | Well, you've -seen- them anyway. To know them, you're going to have to -use- 669 | them. What follows here is an increasingly involved set of challenges aimed at 670 | giving you that practice. Do them all or do the ones that catch your fancy. 671 | Design for yourself other challenges that require you to flex your newfound 672 | VimL muscles. 673 | 674 | *Todo these tasks have not been ordered by difficulty yet, and many more need to be added. 675 | 676 | . Write an autocommand that removes trailing whitespace from all lines in the 677 | buffer when the user exits insert mode. 678 | 679 | . VimL lacks a random number generator. Write one without shelling out to the 680 | OS. 681 | 682 | . Write a syntax plugin for a filetype you use that is missing from Vim, or 683 | improve an existing filetype that has bugs, limitations or omissions. 684 | 685 | . Write a plugin that receives commands from one window but performs them in 686 | another. Particular commands to support include: * and 687 | 688 | . Vim's native tab-page interface is a bit clunky. Write a plugin that makes 689 | tabs work the way you know they should. 690 | 691 | vim:noet:sw=8:nosmarttab:sts=0:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:fdm=marker:ft=help:norl:noro:modifiable: 692 | -------------------------------------------------------------------------------- /plugin/learnviml.vim: -------------------------------------------------------------------------------- 1 | " Vim global plugin for LearnVimL recipes. 2 | " Maintainer: Barry Arthur 3 | " Israel Chauca F. 4 | " Description: Manage LearnVimL recipes. 5 | " Last Change: 2014-01-18 6 | " License: Vim License (see :help license) 7 | " Location: plugin/learnviml.vim 8 | " Website: https://github.com/dahu/LearnVimL 9 | " 10 | " See learnviml.txt for help. This can be accessed by doing: 11 | " :help learnviml.txt 12 | 13 | " Vimscript Setup: {{{1 14 | " Allow use of line continuation. 15 | let s:save_cpo = &cpo 16 | set cpo&vim 17 | 18 | " load guard 19 | "if exists("g:loaded_learnviml") 20 | " \ || v:version < 700 21 | " \ || v:version == 703 && !has('patch338') 22 | " \ || &compatible 23 | " let &cpo = s:save_cpo 24 | " finish 25 | "endif 26 | "let g:loaded_learnviml = 1 27 | 28 | let s:basedir = expand(':p:h:h') 29 | 30 | " Options: {{{1 31 | " "learnviml_split_dir_index" and "learnviml_split_dir_recipe" define on which 32 | " direction Vim should open every split. The accepted values for them are 33 | " "up", "down", "right" and "left". 34 | 35 | " Private Functions: {{{1 36 | 37 | function! s:switch_to(name) 38 | let prefix = 'LearnVimL_' 39 | let name = prefix . substitute(a:name, '^\a', '\u&', '') 40 | let bufnr = bufnr(name) 41 | let winnr = bufwinnr(bufnr) 42 | let dir_opt = get(g:, 'learnviml_split_dir_' . tolower(a:name), 'default') 43 | let dir_dict = {'default' : '', 44 | \ 'up' : 'aboveleft ', 45 | \ 'down' : 'belowright ', 46 | \ 'right' : 'rightbelow v', 47 | \ 'left' : 'leftabove v'} 48 | let dir = get(dir_dict, dir_opt, '') 49 | if bufnr == -1 50 | exec dir . 'new ' . name 51 | elseif winnr == winnr() 52 | " We are already here! 53 | elseif winnr > -1 54 | exec winnr . "wincmd w" 55 | else 56 | exec dir . "split | buffer " . bufnr 57 | endif 58 | endfunction 59 | 60 | function! s:read_recipes() 61 | let recipes = [] 62 | for file in glob(s:basedir . '/sample/**/*.vim', 0, 1) 63 | if filereadable(file) 64 | call extend(recipes, readfile(file)) 65 | endif 66 | endfor 67 | return recipes 68 | endfunction 69 | 70 | function! s:criteria() 71 | let c = {} 72 | let c.title = [] 73 | call add(c.title, ['title =~# ''\m^"=\{4}\s\S''', 'The title line must start with a double quote followed by four equal signs (=) and a space.']) 74 | call add(c.title, ['title =~# "\\m^\\A\\+\\u"', 'The title must start with a capital letter.']) 75 | call add(c.title, ['title =~# "\\m\\.$"', 'The title must end with a period.']) 76 | call add(c.title, ['title !~# "\\m\\s$"', 'The title must not end with trailing whitespace.']) 77 | return c 78 | endfunction 79 | 80 | function! s:parse_recipe(...) range 81 | let body = getline(a:firstline + 1, a:lastline) 82 | if !a:0 83 | let title = substitute(getline(a:firstline), '^"=\+\s*', '', '') 84 | return extend(s:recipes, {title : body}) 85 | endif 86 | let title = getline(a:firstline) 87 | let criteria = s:criteria() 88 | let recipe = getline(a:firstline, a:lastline) 89 | let title = get(recipe, 0, '') 90 | for [criterion, message] in criteria.title 91 | if !eval(criterion) 92 | call add(s:report, 'Line ' . a:firstline . ': ' . message) 93 | endif 94 | endfor 95 | " TODO Is there something we can do with the recipe's body? maybe with 96 | " lambda functions? :-D 97 | endfunction 98 | 99 | function! s:recipe_checker() 100 | let s:report = [] 101 | g/\%^\|^"=/ .,/\n"=\|\%$/ call s:parse_recipe(1) 102 | call s:switch_to('Report') 103 | %delete _ 104 | if empty(&buftype) 105 | setl buftype=nofile 106 | endif 107 | call setline(1, empty(s:report) ? 'No problem was found.' : s:report) 108 | endfunction 109 | 110 | function! s:handle_index_cursor() 111 | if line('.') < 3 112 | 3 113 | endif 114 | if col('.') < 3 115 | normal! 3| 116 | endif 117 | if s:index_line != line('.') 118 | let s:index_line = line('.') 119 | call s:get_recipe(getline('.')) 120 | call s:switch_to('Index') 121 | endif 122 | endfunction 123 | 124 | function! s:get_index(pat) 125 | let s:recipes = {} 126 | let s:index_line = 0 127 | call s:switch_to('Index') 128 | setl modifiable 129 | let saved_lazyredraw = &lazyredraw 130 | set lazyredraw 131 | augroup LearnVimL 132 | au! 133 | augroup END 134 | %delete _ 135 | call setline(1, s:read_recipes()) 136 | let delim = '"=\{4}\s*' 137 | let pat = '^' . delim . '\%(.*\n\%(' . delim . '\)\@!\)\{-1,}.\{-}\zs' 138 | \ . escape(a:pat, '/') 139 | let cmd = printf('g/%s/ .;/\n%s\|\%%$/ call s:parse_recipe()', pat, delim) 140 | exec cmd 141 | %delete _ 142 | let index = keys(s:recipes) 143 | if empty(index) 144 | let header = ['No recipe matched the given pattern: ' . a:pat, '----'] 145 | let index = [''] 146 | else 147 | let header = ['Press Enter to go to the code of the current item.', '----'] 148 | let index = map(index, '(v:key % 2 ? "+ " : "* ") . v:val') 149 | endif 150 | call setline(1, header + index) 151 | setl nomodifiable 152 | au LearnVimL CursorMoved call s:handle_index_cursor() 153 | if empty(&buftype) 154 | " One-time setup 155 | exec 'nnore :call switch_to("Recipe")' 156 | exec 'inore :call switch_to("Recipe")' 157 | setl buftype=nofile ft=lvlindex noswapfile undolevels=0 158 | endif 159 | let &lazyredraw = saved_lazyredraw 160 | redraw 161 | endfunction 162 | 163 | function! s:get_recipe(title) 164 | let saved_lazyredraw = &lazyredraw 165 | set lazyredraw 166 | call s:switch_to('Recipe') 167 | if bufname('%') =~# 'Recipe$' 168 | let &lazyredraw = saved_lazyredraw 169 | redraw 170 | return 171 | endif 172 | %delete _ 173 | let title = substitute(a:title, '^[+*]\s\+', '', '') 174 | let recipe = copy(get(s:recipes, title, [])) 175 | if !empty(recipe) 176 | call insert(recipe, '" ' . title) 177 | call setline(1, recipe) 178 | endif 179 | if &swapfile 180 | " One-time setup. 181 | setl noswapfile ft=vim undolevels=0 182 | endif 183 | silent write 184 | let &lazyredraw = saved_lazyredraw 185 | redraw 186 | endfunction 187 | 188 | function! s:close_lvl() 189 | for name in ['Recipe', 'Index'] 190 | call s:switch_to(name) 191 | close 192 | endfor 193 | endfunction 194 | 195 | " Public Interface: {{{1 196 | 197 | " Commands: {{{1 198 | command! -nargs=+ LVL silent call s:get_index() 199 | command! LVLClose silent call s:close_lvl() 200 | command! LVLSyntaxChecker silent call s:recipe_checker() 201 | 202 | " Teardown: {{{1 203 | " reset &cpo back to users setting 204 | let &cpo = s:save_cpo 205 | 206 | " Template From: https://github.com/dahu/Area-41/ 207 | " vim: set sw=2 sts=2 et fdm=marker: 208 | -------------------------------------------------------------------------------- /sample/recipe.vim: -------------------------------------------------------------------------------- 1 | "==== Use a default value if variable does not exists. 2 | " See :help internal-variables. 3 | let foo = get(g:, 'bar', 1) 4 | "==== Switch a boolean option. 5 | set wrap! 6 | set invhlsearch 7 | "==== Set a complicated option. 8 | set formatlistpat=^\\s\\d\\.\\s\\+ 9 | " is better written as 10 | let &formatlistpat = '^\s\d\.\s\+' 11 | " on the command-line, use: :let &flp = =string(&flp) 12 | "==== Show the value of an option. 13 | set formatoptions? 14 | echo &formatoptions 15 | "==== Apply custom highlighting to echoed text. 16 | echohl WarningMsg 17 | echom 'Some error happened. Please forgive me, I did not mean it.' 18 | echohl None 19 | -------------------------------------------------------------------------------- /scraps/vimlpoo.vim: -------------------------------------------------------------------------------- 1 | function! Person(name) 2 | let p = {} 3 | let p.name = a:name 4 | func p.greet(another) 5 | return "hello, " . a:another.name 6 | endfunc 7 | return p 8 | endfunction 9 | 10 | function! ExcitedPerson(name) 11 | let p = Person(a:name) 12 | func! p.greet(another) 13 | return "Hot diggity, " . a:another.name . '!' 14 | endfunc 15 | return p 16 | endfunction 17 | 18 | function! Child(name) 19 | let p = ExcitedPerson(a:name) 20 | let p.parent_greet = p.greet 21 | func! p.greet(another) 22 | return call(self.parent_greet, [a:another], self) . ". Where's my present?!" 23 | endfunc 24 | return p 25 | endfunction 26 | 27 | let a = Person('Alice') 28 | let b = ExcitedPerson('Bob') 29 | let c = Child('Charlie') 30 | 31 | for p in [b, c] 32 | echo p.greet(a) 33 | echo a.greet(p) 34 | unlet p 35 | endfor 36 | -------------------------------------------------------------------------------- /syntax/lvlindex.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax plugin. 2 | " Language: lvlindex 3 | " Maintainer: Barry Arthur 4 | " Israel Chauca F. 5 | " Description: Syntax for LearnVimL index. 6 | " Last Change: 2014-01-18 7 | " License: Vim License (see :help license) 8 | " Location: syntax/lvlindex.vim 9 | " Website: https://github.com/dahu/LearnVimL 10 | " 11 | " See learnviml.txt for help. This can be accessed by doing: 12 | " 13 | " :help learnviml.txt 14 | 15 | " Quit when a (custom) syntax file was already loaded 16 | if exists("b:current_syntax") 17 | finish 18 | endif 19 | 20 | " Allow use of line continuation. 21 | let s:save_cpo = &cpo 22 | set cpo&vim 23 | 24 | setl conceallevel=2 concealcursor=nvic 25 | 26 | syn match LVLOdd /^+ .*$/ nextgroup=LVLEven 27 | syn match LVLEven /^* .*$/ nextgroup=LVLOdd 28 | syn match LVLHeader /^\%1l.*/ nextgroup=LVLLine 29 | syn match LVLLine /^\%2l----\n/ nextgroup=LVLOdd 30 | syn match LVLMarker /^[+*]/ contained containedin=LVLOdd,LVLEven conceal cchar=- 31 | 32 | " Define the default highlighting. 33 | " Only used when an item doesn't have highlighting yet 34 | hi link LVLOdd String 35 | hi link LVLEven Normal 36 | hi link LVLLine Comment 37 | hi link LVLHeader Statement 38 | hi link LVLMarker Identifier 39 | 40 | let b:current_syntax = "lvlindex" 41 | 42 | let &cpo = s:save_cpo 43 | unlet s:save_cpo 44 | 45 | " Template From: https://github.com/dahu/Area-41/ 46 | " vim: set sw=2 sts=2 et fdm=marker: 47 | -------------------------------------------------------------------------------- /test/_setup.vim: -------------------------------------------------------------------------------- 1 | let &rtp = expand(':p:h:h') . ',' . &rtp . ',' . expand(':p:h:h') . '/after' 2 | runtime plugin/learnviml.vim 3 | for fn in ['Plan', 'Ok', 'Is', 'Isnt', 'Like', 'Unlike', 'Pass', 'Fail', 4 | \ 'Diag', 'Skip', 'Todo', 'Bailout', 'SetOutputFile'] 5 | exec 'command! -nargs=* Tap' . fn . ' call vimtap#' . fn .'()' 6 | endfor 7 | -------------------------------------------------------------------------------- /test/test001.vim: -------------------------------------------------------------------------------- 1 | command! -nargs=+ Cursor call cursor() | doau CursorMoved 2 | 3 | call vimtest#StartTap() 4 | TapPlan 13 5 | call setline(1, 'let x = 1') 6 | LVL set 7 | Cursor 1 1 8 | TapIs winnr('$'), 3, 'We have three windows.' 9 | TapOk bufwinnr('LearnVimL_Index') > 0, 'Index is present.' 10 | TapOk bufwinnr('LearnVimL_Recipe') > 0, 'Recipe is present.' 11 | TapOk !empty(getline(1)), 'The recipe has content.' 12 | TapIs winnr(), bufwinnr('LearnVimL_Index'), 'Current window is LearnVimL_Index.' 13 | Cursor 1 1 14 | TapIs line('.'), 3, 'The cursor can not go onto the heading.' 15 | Cursor 3 1 16 | TapIs col('.'), 3, 'The cursor can not go onto the list markers.' 17 | TapOk line('$') > 2, 'There is one recipe at least.' 18 | exec "normal! \" 19 | TapOk line('$') > 2, 'We have a recipe.' 20 | let line1 = getline(1) 21 | wincmd p 22 | Cursor 4 3 23 | wincmd p 24 | let line2 = getline(1) 25 | TapOk line1 == line2 && !empty(line2), 'The recipe was updated on CursorMoved.' 26 | wincmd p 27 | Cursor 3 3 28 | exec "normal! \" 29 | TapIsnt getline(1), line2, 'The recipe changed on CR.' 30 | let lines1 = getline(1,'$') 31 | LVL let 32 | let lines2 = getline(1,'$') 33 | TapOk lines1 != lines2, 'The index changed on :LVL let.' 34 | " Test "sourceabililty", this must be the last test because the window layout 35 | " and contents can change in unexpected ways. 36 | wincmd p 37 | let v:errmsg = '' 38 | source % 39 | TapOk empty(v:errmsg,), 'Sourcing the recipe works.' 40 | call vimtest#Quit() 41 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | * make saving & executing the LVL_recipe results easier/possible 2 | 3 | * start early eval.txt exercises as simple one-liners 4 | * build up by giving function templates requiring learners to fill gaps 5 | * work up to having learners write multiple functions with calling between them 6 | * for more advanced sections, have: 7 | ** nearly working functions that require fixups 8 | ** problem statements requiring code solutions 9 | ** case-studies of "good" real-world code (taken from some of the great plugins) 10 | 11 | --------------------------------------------------------------------------------