-
Notifications
You must be signed in to change notification settings - Fork 8
/
learn_vimscript_the_hard_way.vim
6421 lines (6046 loc) · 319 KB
/
learn_vimscript_the_hard_way.vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Learn Vimscript the Hard Way
«»Echoing Messages
The first pieces of Vimscript we'll look at are the echo and echom commands.
You can read their full documentation by running :help echo and :help echom
in Vim. As you go through this book you should try to read the :help for
every new command you encounter to learn more about them.
Try out echo by running the following command:
--------------------------------------------------------------------------------
:echo "Hello, world!"
--------------------------------------------------------------------------------
You should see Hello, world! appear at the bottom of the window.
Persistent Echoing
Now try out echom by running the following command.
--------------------------------------------------------------------------------
:echom "Hello again, world!"
--------------------------------------------------------------------------------
You should see Hello again, world! appear at the bottom of the window.
To see the difference between these two commands, run the following:
--------------------------------------------------------------------------------
:messages
--------------------------------------------------------------------------------
You should see a list of messages. Hello, world! will not be in this list,
but Hello again, world! will be in it.
When you're writing more complicated Vimscript later in this book you may find
yourself wanting to "print some output" to help you debug problems. Plain old
:echo will print output, but it will often disappear by the time your script
is done. Using :echom will save the output and let you run :messages to
view it later.
Comments
Before moving on, let's look at how to add comments. When you write Vimscript
code (in your ~/.vimrc file or any other one) you can add comments with the
" character, like this:
--------------------------------------------------------------------------------
" Make space more useful
nnoremap <space> za
--------------------------------------------------------------------------------
This doesn't always work (that's one of those ugly corners of Vimscript), but
in most cases it does. Later we'll talk about when it won't (and why that
happens).
Exercises
Read :help echo.
Read :help echom.
Read :help messages.
Add a line to your ~/.vimrc file that displays a friendly ASCII-art cat
(>^.^<) whenever you open Vim.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Setting Options
Vim has many options you can set to change how it behaves.
There are two main kinds of options: boolean options (either "on" or "off") and
options that take a value.
Boolean Options
Run the following command:
--------------------------------------------------------------------------------
:set number
--------------------------------------------------------------------------------
Line numbers should appear on the left side of the window if they weren't there
already. Now run this:
--------------------------------------------------------------------------------
:set nonumber
--------------------------------------------------------------------------------
The line numbers should disappear. number is a boolean option: it can be off
or on. You turn it "on" by running :set number and "off" with :set
nonumber.
All boolean options work this way. :set <name> turns the option on and :set
no<name> turns it off.
Toggling Boolean Options
You can also "toggle" boolean options to set them to the opposite of whatever
they are now. Run this:
--------------------------------------------------------------------------------
:set number!
--------------------------------------------------------------------------------
The line numbers should reappear. Now run it again:
--------------------------------------------------------------------------------
:set number!
--------------------------------------------------------------------------------
They should disappear once more. Adding a ! (exclamation point or "bang") to
a boolean option toggles it.
Checking Options
You can ask Vim what an option is currently set to by using a ?. Run these
commands and watch what happens after each:
--------------------------------------------------------------------------------
:set number
:set number?
:set nonumber
:set number?
--------------------------------------------------------------------------------
Notice how the first :set number? command displayed number while the second
displayed nonumber.
Options with Values
Some options take a value instead of just being off or on. Run the following
commands and watch what happens after each:
--------------------------------------------------------------------------------
:set number
:set numberwidth=10
:set numberwidth=4
:set numberwidth?
--------------------------------------------------------------------------------
The numberwidth option changes how wide the column containing line numbers
will be. You can change non-boolean options with :set <name>=<value>, and
check them the usual way (:set <name>?).
Try checking what a few other common options are set to:
--------------------------------------------------------------------------------
:set wrap?
:set shiftround?
:set matchtime?
--------------------------------------------------------------------------------
Setting Multiple Options at Once
Finally, you can specify more than one option in the same :set command to save
on some typing. Try running this:
--------------------------------------------------------------------------------
:set numberwidth=2
:set nonumber
:set number numberwidth=6
--------------------------------------------------------------------------------
Notice how both options were set and took effect in the last command.
Exercises
Read :help 'number' (notice the quotes).
Read :help relativenumber.
Read :help numberwidth.
Read :help wrap.
Read :help shiftround.
Read :help matchtime.
Add a few lines to your ~/.vimrc file to set these options however you like.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Basic Mapping
If there's one feature of Vimscript that will let you bend Vim to your will more
than any other, it's the ability to map keys. Mapping keys lets you tell Vim:
When I press this key, I want you to do this stuff instead of whatever you
would normally do.
We're going to start off by mapping keys in normal mode. We'll talk about how
to map keys in insert and other modes in the next chapter.
Type a few lines of text into a file, then run:
--------------------------------------------------------------------------------
:map - x
--------------------------------------------------------------------------------
Put your cursor somewhere in the text and press -. Notice how Vim deleted the
character under the cursor, just like if you had pressed x.
We already have a key for "delete the character under the cursor", so let's
change that mapping to something slightly more useful. Run this command:
--------------------------------------------------------------------------------
:map - dd
--------------------------------------------------------------------------------
Now put your cursor on a line somewhere and press - again. This time Vim
deletes the entire line, because that's what dd does.
Special Characters
You can use <keyname> to tell Vim about special keys. Try running this
command:
--------------------------------------------------------------------------------
:map <space> viw
--------------------------------------------------------------------------------
Put your cursor on a word in your text and press the space bar. Vim will
visually select the word.
You can also map modifier keys like Ctrl and Alt. Run this:
--------------------------------------------------------------------------------
:map <c-d> dd
--------------------------------------------------------------------------------
Now pressing Ctrl+d on your keyboard will run dd.
Commenting
Remember in the first lesson where we talked about comments? Mapping keys is
one of the places where Vim comments don't work. Try running this command:
--------------------------------------------------------------------------------
:map <space> viw " Select word
--------------------------------------------------------------------------------
If you try pressing space now, something horrible will almost certainly happen.
Why?
When you press the space bar now, Vim thinks you want it to do what
viw<space>"<space>Select<space>word would do. Obviously this isn't what we
want.
If you look closely at the effect of this mapping you might notice something
strange. Take a few minutes to try to figure out exactly what happens when you
use it, and why that happens.
Don't worry if you don't get it right away -- we'll talk about it more soon.
Exercises
Map the - key to "delete the current line, then paste it below the one we're
on now". This will let you move lines downward in your file with one keystroke.
Add that mapping command to your ~/.vimrc file so you can use it any time
you start Vim.
Figure out how to map the _ key to move the line up instead of down.
Add that mapping to your ~/.vimrc file too.
Try to guess how you might remove a mapping and reset a key to its normal
function.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Modal Mapping
In the last chapter we talked about how to map keys in Vim. We used the map
command which made the keys work in normal mode. If you played around a bit
before moving on to this chapter, you may have noticed that the mappings also
took effect in visual mode.
You can be more specific about when you want mappings to apply by using nmap,
vmap, and imap. These tell Vim to only use the mapping in normal, visual,
or insert mode respectively.
Run this command:
--------------------------------------------------------------------------------
:nmap \ dd
--------------------------------------------------------------------------------
Now put your cursor in your text file, make sure you're in normal mode, and
press \. Vim will delete the current line.
Now enter visual mode and try pressing \. Nothing will happen, because we
told Vim to only use that mapping in normal mode (and \ doesn't do anything by
default).
Run this command:
--------------------------------------------------------------------------------
:vmap \ U
--------------------------------------------------------------------------------
Enter visual mode and select some text, then press \. Vim will convert the
text to uppercase!
Try the \ key a few times in normal and visual modes and notice that it now
does something completely different depending on which mode you're in.
Muscle Memory
At first the idea of mapping the same key to do different things depending on
which mode you're in may sound like a terrible idea. Why would you want to
have to stop and think which mode you're in before pressing the key? Wouldn't
that negate any time you save from the mapping itself?
In practice it turns out that this isn't really a problem. Once you start using
Vim often you won't be thinking about the individual keys you're typing any
more. You'll think: "delete a line" and not "press dd". Your fingers and
brain will learn your mappings and the keys themselves will become subconscious.
Insert Mode
Now that we've covered how to map keys in normal and visual mode, let's move on
to insert mode. Run this command:
--------------------------------------------------------------------------------
:imap <c-d> dd
--------------------------------------------------------------------------------
You might think that this would let you press Ctrl+d whenever you're in insert
mode to delete the current line. This would be handy because you wouldn't need
to go back into normal mode to cut out lines.
Go ahead and try it. It won't work -- instead it will just put two ds in your
file! That's pretty useless.
The problem is that Vim is doing exactly what we told it to. We said: "when
I press <c-d> I want you to do what pressing d and d would normally do".
Well, normally when you're in insert mode and press the d key twice, you get
two ds in a row!
To make this mapping do what we intended we need to be very explicit. Run this
command to change the mapping:
--------------------------------------------------------------------------------
:imap <c-d> <esc>dd
--------------------------------------------------------------------------------
The <esc> is our way of telling Vim to press the Escape key, which will take
us out of insert mode.
Now try the mapping. It works, but notice how you're now back in normal mode.
This makes sense because we told Vim that <c-d> should exit insert mode and
delete a line, but we never told it to go back into insert mode.
Run one more command to fix the mapping once and for all:
--------------------------------------------------------------------------------
:imap <c-d> <esc>ddi
--------------------------------------------------------------------------------
The i at the end enters insert mode, and our mapping is finally complete.
Exercises
Set up a mapping so that you can press <c-u> to convert the current word to
uppercase when you're in insert mode. Remember that U in visual mode will
uppercase the selection. I find this mapping extremely useful when I'm writing
out the name of a long constant like MAX_CONNECTIONS_ALLOWED. I type out the
constant in lower case and then uppercase it with the mapping instead of holding
shift the entire time.
Add that mapping to your ~/.vimrc file.
Set up a mapping so that you can uppercase the current word with <c-u> when in
normal mode. This will be slightly different than the previous mapping
because you don't need to enter normal mode. You should end up back in normal
mode at the end instead of in insert mode as well.
Add that mapping to your ~/.vimrc file.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Strict Mapping
Get ready, because things are about to get a little wild.
So far we've used map, nmap, vmap, and imap to create key mappings that
will save time. These work, but they have a downside. Run the following
commands:
--------------------------------------------------------------------------------
:nmap - dd
:nmap \ -
--------------------------------------------------------------------------------
Now try pressing \ (in normal mode). What happens?
When you press \ Vim sees the mapping and says "I should run - instead".
But we've already mapped - to do something else! Vim sees that and says "oh,
now I need to run dd", and so it deletes the current line.
When you map keys with these commands Vim will take other mappings into
account. This may sound like a good thing at first but in reality it's pure
evil. Let's talk about why, but first remove those mappings by running the
following commands:
--------------------------------------------------------------------------------
:nunmap -
:nunmap \
--------------------------------------------------------------------------------
Recursion
Run this command:
--------------------------------------------------------------------------------
:nmap dd O<esc>jddk
--------------------------------------------------------------------------------
At first glance it might look like this would map dd to:
Effectively this should "clear the current line". Try it.
Vim will seem to freeze when you press dd. If you press <c-c> you'll get
Vim back, but there will be a ton of empty lines in your file! What happened?
This mapping is actually recursive! When you press dd, Vim says:
This mapping can never finish running! Go ahead and remove this terrible thing
with the following command:
--------------------------------------------------------------------------------
:nunmap dd
--------------------------------------------------------------------------------
Side Effects
One downside of the *map commands is the danger of recursing. Another is that
their behavior can change if you install a plugin that maps keys they depend on.
When you install a new Vim plugin there's a good chance that you won't use and
memorize every mapping it creates. Even if you do, you'd have to go back and
look through your ~/.vimrc file to make sure none of your custom mappings use
a key that the plugin has mapped.
This would make installing plugins tedious and error-prone. There must be
a better way.
Nonrecursive Mapping
Vim offers another set of mapping commands that will not take mappings into
account when they perform their actions. Run these commands:
--------------------------------------------------------------------------------
:nmap x dd
:nnoremap \ x
--------------------------------------------------------------------------------
Now press \ and see what happens.
When you press \ Vim ignores the x mapping and does whatever it would do for
x by default. Instead of deleting the current line, it deletes the current
character.
Each of the *map commands has a *noremap counterpart that ignores other
mappings: noremap, nnoremap, vnoremap, and inoremap.
When should you use these nonrecursive variants instead of their normal
counterparts?
Always.
No, seriously, always.
Using a bare *map is just asking for pain down the road when you install
a plugin or add a new custom mapping. Save yourself the trouble and type the
extra characters to make sure it never happens.
Exercises
Convert all the mappings you added to your ~/.vimrc file in the previous
chapters to their nonrecursive counterparts.
Read :help unmap.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Leaders
We've learned how to map keys in a way that won't make us want to tear our hair
out later, but you might have noticed one more problem.
Every time we do something like :nnoremap <space> dd we've overwritten what
<space> normally does. What if we need that key later?
There are a bunch of keys that you don't normally need in your day-to-day Vim
usage. -, H, L, <space>, <cr>, and <bs> do things that you almost
never need (in normal mode, of course). Depending on how you work you may find
others that you never use.
Those are safe to map, but that only gives us six keys to work with. What
happened to Vim's legendary customizability?
Mapping Key Sequences
Unlike Emacs, Vim makes it easy to map more than just single keys. Run these
commands:
--------------------------------------------------------------------------------
:nnoremap -d dd
:nnoremap -c ddO
--------------------------------------------------------------------------------
Try them out by typing -d and -c (quickly) in normal mode. The first
creates a custom mapping to delete a line, while the second "clears" a line and
puts you into insert mode.
This means you can pick a key that you don't care about (like -) as a "prefix"
key and create mappings on top of it. It means you'll have to type an extra key
to activate the mappings, but one extra keystroke can easily be absorbed into
muscle memory.
If you think this might be a good idea, you're right, and it turns out that Vim
already has mechanisms for this "prefix" key!
Leader
Vim calls this "prefix" key the "leader". You can set your leader key to
whatever you like. Run this command:
--------------------------------------------------------------------------------
:let mapleader = "-"
--------------------------------------------------------------------------------
You can replace - with any key you like. I personally like , even though it
shadows a useful function, because it's very easy to type.
When you're creating new mappings you can use <leader> to mean "whatever
I have my leader key set to". Run this command:
--------------------------------------------------------------------------------
:nnoremap <leader>d dd
--------------------------------------------------------------------------------
Now try it out by pressing your leader key and then d. Vim will delete the
current line.
Why bother with setting <leader> at all, though? Why not just include your
"prefix" key directly in your mapping commands? There are three good reasons.
First of all, you may decide you need the normal function of your leader later
on down the road. Defining it in one place makes it easy to change later.
Second, when someone else is looking at your ~/.vimrc file they'll immediately
know what you mean when you say <leader>. They can simply copy your mapping
into their own ~/.vimrc if they like it even if they use a different leader.
Finally, many Vim plugins create mappings that start with <leader>. If you've
already got it set up they'll work properly and will feel familiar right out of
the box.
Local Leader
Vim has a second "leader" key called "local leader". This is meant to be
a prefix for mappings that only take effect for certain types of files, like
Python files or HTML files.
We'll talk about how to make mappings for specific types of files later in the
book, but you can go ahead and set your "localleader" now:
--------------------------------------------------------------------------------
:let maplocalleader = "\\"
--------------------------------------------------------------------------------
Notice that we have to use \\ and not just \ because \ is the escape
character in Vimscript strings. You'll learn more about this later.
Now you can use <localleader> in mappings and it will work just like
<leader> does (except for resolving to a different key, of course).
Feel free to change this key to something else if you don't like backslash.
Exercises
Read :help mapleader.
Read :help maplocalleader.
Set mapleader and maplocalleader in your ~/.vimrc file.
Convert all the mappings you added to your ~/.vimrc file in the previous
chapters to be prefixed with <leader> so they don't shadow existing commands.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Editing Your Vimrc
Before we move on to learning more Vimscript, let's find a way to make it easier
to add new mappings to our ~/.vimrc file.
Sometimes you're coding away furiously at a problem and realize a new mapping
would make your editing easier. You should add it to your ~/.vimrc file right
then and there to make sure you don't forget, but you don't want to lose your
concentration.
The idea of this chapter is that you want to make it easier to make it easier to
edit text.
That's not a typo. Read it again.
The idea of this chapter is that you want to (make it easier to (make it easier
to (edit text))).
Editing Mapping
Let's add a mapping that will open your ~/.vimrc file in a split so you can
quickly edit it and get back to coding. Run this command:
--------------------------------------------------------------------------------
:nnoremap <leader>ev :vsplit $MYVIMRC<cr>
--------------------------------------------------------------------------------
I like to think of this command as "edit my vimrc file".
$MYVIMRC is a special Vim variable that points to your ~/.vimrc file. Don't
worry about that for right now, just trust me that it works.
:vsplit opens a new vertical split. If you'd prefer a horizontal split you
can replace it with :split.
Take a minute and think through that command in your mind. The goal is: "open
my ~/.vimrc file in a new split". Why does it work? Why is every single
piece of that mapping necessary?
With that mapping you can open up your ~/.vimrc file with three keystrokes.
Once you use it a few times it will burn its way into your muscle memory and
take less than half a second to type.
When you're in the middle of coding and come up with a new mapping that would
save you time it's now trivial to add it to your ~/.vimrc file.
Sourcing Mapping
Once you've added a mapping to your ~/.vimrc file, it doesn't immediately take
effect. Your ~/.vimrc file is only read when you start Vim. This means you
need to also run the command manually to make it work in the current session,
which is a pain.
Let's add a mapping to make this easier:
--------------------------------------------------------------------------------
:nnoremap <leader>sv :source $MYVIMRC<cr>
--------------------------------------------------------------------------------
I like to think of this command as "source my vimrc file".
The source command tells Vim to take the contents of the given file and
execute it as Vimscript.
Now you can easily add new mappings during the heat of coding:
<><><>That's eight keystrokes plus whatever it takes to define the mapping. It's very
little overhead, which reduces the chance of breaking focus.
Exercises
Add mappings to "edit my ~/.vimrc" and "source my ~/.vimrc" to your
~/.vimrc file.
Try them out a few times, adding dummy mappings each time.
Read :help myvimrc.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Abbreviations
Vim has a feature called "abbreviations" that feel similar to mappings but are
meant for use in insert, replace, and command modes. They're extremely flexible
and powerful, but we're just going to cover the most common uses here.
We're only going to worry about insert mode abbreviations in this book. Run the
following command:
--------------------------------------------------------------------------------
:iabbrev adn and
--------------------------------------------------------------------------------
Now enter insert mode and type:
--------------------------------------------------------------------------------
One adn two.
--------------------------------------------------------------------------------
As soon as you hit space after typing the adn Vim will replace it with and.
Correcting typos like this is a great use for abbreviations. Run these
commands:
--------------------------------------------------------------------------------
:iabbrev waht what
:iabbrev tehn then
--------------------------------------------------------------------------------
Now enter insert mode again and type:
--------------------------------------------------------------------------------
Well, I don't know waht we should do tehn.
--------------------------------------------------------------------------------
Notice how both abbreviations were substituted, even though you didn't type
a space after the second one.
Keyword Characters
Vim will substitute an abbreviation when you type any "non-keyword character"
after an abbreviation. "Non-keyword character" means any character not in the
iskeyword option. Run this command:
--------------------------------------------------------------------------------
:set iskeyword?
--------------------------------------------------------------------------------
You should see something like iskeyword=@,48-57,_,192-255. This format is
very complicated, but in essence it means that all of the following are
considered "keyword characters":
If you want to read the full description of this option's format you can check
out :help isfname, but I'll warn you that you'd better have a beer at the
ready for this one.
For our purposes you can simply remember that abbreviations will be expanded
when you type anything that's not a letter, number, or underscore.
More Abbreviations
Abbreviations are useful for more than just correcting typos. Let's add a few
more that can help in day-to-day text editing. Run the following commands:
--------------------------------------------------------------------------------
:iabbrev @@ steve@stevelosh.com
:iabbrev ccopy Copyright 2013 Steve Losh, all rights reserved.
--------------------------------------------------------------------------------
Feel free to replace my name and email address with your own, then enter insert
mode and try them out.
These abbreviations take large chunks of text that you type often and compress
them down to a few characters. Over time, this can save you a lot of typing, as
well as wear and tear on your fingers.
Why Not Use Mappings?
If you're thinking that abbreviations seem similar to mappings, you're right.
However, they're intended to be used for different things. Let's look at an
example.
Run this command:
--------------------------------------------------------------------------------
:inoremap ssig -- <cr>Steve Losh<cr>steve@stevelosh.com
--------------------------------------------------------------------------------
This is a mapping intended to let you insert your signature quickly. Try it
out by entering insert mode and typing ssig.
It seems to work great, but there's a problem. Try entering insert mode and
typing this text:
--------------------------------------------------------------------------------
Larry Lessig wrote the book "Remix".
--------------------------------------------------------------------------------
You'll notice that Vim has expanded the ssig in Larry's name! Mappings don't
take into account what characters come before or after the map -- they only look
at the specific sequence that you mapped to.
Remove the mapping and replace it with an abbreviation by running the following
commands:
--------------------------------------------------------------------------------
:iunmap ssig
:iabbrev ssig -- <cr>Steve Losh<cr>steve@stevelosh.com
--------------------------------------------------------------------------------
Now try out the abbreviation again.
This time Vim will pay attention to the characters before and after ssig and
only expand it when we want.
Exercises
Add abbreviations for some common typos you know you personally make to your
~/.vimrc file. Be sure to use the mappings you created in the last chapter to
open and source the file!
Add abbreviations for your own email address, website, and signature as well.
Think of some pieces of text you type very often and add abbreviations for them
too.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»More Mappings
I know we've talked a lot about mappings so far, but we're going to practice
them again now. Mappings are one of the easiest and fastest ways to make your
Vim editing more productive so it's good to focus on them quite a bit.
One concept that has showed up in several examples but that we haven't
explicitly talked about is mapping a sequence of multiple keys.
Run the following command:
--------------------------------------------------------------------------------
:nnoremap jk dd
--------------------------------------------------------------------------------
Now make sure you're in normal mode and press j followed quickly by k. Vim
will delete the current line.
Now try pressing only j and waiting for a bit. If you don't press k quickly
after the j, Vim decides that you don't want to activate the mapping and
instead runs the normal j functionality (moving down a line).
This mapping will make it painful to move around, so let's remove it. Run the
following command:
--------------------------------------------------------------------------------
:nunmap jk
--------------------------------------------------------------------------------
Now typing jk in normal mode will move down and then up a line as usual.
A More Complicated Mapping
You've seen a bunch of simple mappings so far, so it's time to look at something
with a bit more meat to it. Run the following command:
--------------------------------------------------------------------------------
:nnoremap <leader>" viw<esc>a"<esc>hbi"<esc>lel
--------------------------------------------------------------------------------
Now that's an interesting mapping! First, go ahead and try it out. Enter
normal mode, put your cursor over a word in your text and type <leader>". Vim
will surround the word in double quotes!
How does this work? Let's split it apart into pieces and think of what each one
does:
--------------------------------------------------------------------------------
viw<esc>a"<esc>hbi"<esc>lel
--------------------------------------------------------------------------------
<><><>Remember: because we used nnoremap instead of nmap it doesn't matter if
you've mapped any of the keys in this sequence to something else. Vim will use
the default functionality for all of them.
Hopefully you can see how much potential Vim's mappings have, as well as how
unreadable they can become.
Exercises
Create a mapping similar to the one we just looked at, but for single quotes
instead of double quotes.
Try using vnoremap to add a mapping that will wrap whatever text you have
visually selected in quotes. You'll probably need the `< and `>
commands for this, so read up on them with :help `<.
Map H in normal mode to go to the beginning of the current line. Since h
moves left you can think of H as a "stronger" h.
Map L in normal mode to go to the end of the current line. Since l
moves right you can think of L as a "stronger" l.
Find out what commands you just overwrote by reading :help H and :help L.
Decide whether you care about them.
Add all of these mappings to your ~/.vimrc file, making sure to use your "edit
my ~/.vimrc" and "source my ~/.vimrc" mappings to do so.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Training Your Fingers
In this chapter we're going to talk about how to learn Vim more effectively, but
we need to do a bit of preparation first.
Let's set up one more mapping that will save more wear on your left hand than
any other mapping you ever create. Run the following command:
--------------------------------------------------------------------------------
:inoremap jk <esc>
--------------------------------------------------------------------------------
Now enter insert mode and type jk. Vim will act as if you pressed the escape
key and return you to normal mode.
There are a number of ways to exit insert mode in Vim by default:
<><><>Each of those requires you to stretch your fingers uncomfortably. Using jk is
great because the keys are right under two of your strongest fingers and you
don't have to perform a chord.
Some people prefer using jj instead of jk, but I prefer jk for two
reasons:
If you write in a language where jk is a frequently used combination of
letters (like Dutch) you'll probably want to pick a different mapping.
Learning the Map
Now that you've got a great new mapping, how can you learn to use it? Chances
are you've already got the escape key in your muscle memory, so when you're
editing you'll hit it without even thinking.
The trick to relearning a mapping is to force yourself to use it by
disabling the old key(s). Run the following command:
--------------------------------------------------------------------------------
:inoremap <esc> <nop>
--------------------------------------------------------------------------------
This effectively disables the escape key in insert mode by telling Vim to
perform <nop> (no operation) instead. Now you have to use your jk mapping
to exit insert mode.
At first you'll forget, type escape and start trying to do something in normal
mode and you'll wind up with stray characters in your text. It will be
frustrating, but if you stick with it you'll be surprised at how fast your mind
and fingers absorb the new mapping. Within an hour or two you won't be
accidentally hitting escape any more.
This idea applies to any new mapping you create to replace an old one, and even
to life in general. When you want to change a habit, make it harder or
impossible to do!
If you want to start cooking meals instead of microwaving TV dinners, don't buy
any TV dinners when you go shopping. You'll cook some real food when you get
hungry enough.
If you want to quit smoking, always leave your cigarettes in your car's trunk.
When you get the urge to have a casual cigarette you'll think of what a pain in
the ass it will be to walk out to the car and are less likely to bother doing
it.
Exercises
If you still find yourself using the arrow keys to navigate around Vim in normal
mode, map them to <nop> to make yourself stop.
If you still use the arrow keys in insert mode, map them to <nop> there too.
The right way to use Vim is to get out of insert mode as soon as you can and use
normal mode to move around.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Buffer-Local Options and Mappings
Now we're going to take a few minutes to revisit three things we've already
talked about: mappings, abbreviations, and options, but with a twist. We're
going to set each of them in a single buffer at a time.
The true power of this idea will become apparent in the next chapter, but we
need to lay the groundwork for it now.
For this chapter you'll need to open two files in Vim, each in its own split.
I'll call them foo and bar, but you can name them whatever you like. Put
some text into each of them.
Mappings
Switch to file foo and run the following commands:
--------------------------------------------------------------------------------
:nnoremap <leader>d dd
:nnoremap <buffer> <leader>x dd
--------------------------------------------------------------------------------
Now stay in file foo, make sure you're in normal mode, and type <leader>d.
Vim will delete a line. This is nothing new.
Still in file foo, type <leader>x. Vim will delete a line again. This
makes sense because we mapped <leader>x to dd as well.
Now move over to file bar. While in normal mode, type <leader>d. Again,
Vim deletes the current line. Nothing surprising here either.
Now for the twist: while still in file bar, type <leader>x.
Instead of deleting the entire line, Vim just deleted a single character!
What happened?
The <buffer> in the second nnoremap command told Vim to only consider that
mapping when we're in the buffer where we defined it.
When you typed <leader>x in file bar Vim couldn't find a mapping that
matched it, so it treated it as two commands: <leader> (which does nothing on
its own) and x (the normal command to delete a single character.)
Local Leader
In our example we used <leader>x for our buffer-local mapping, but this is bad
form. In general, when you create a mapping that only applies to specific
buffers you should use <localleader> instead of <leader>.
Using two separate leader keys provides a sort of "namespacing" that will help
you keep all your various mappings straight in your head.
It's even more important when you're writing a plugin for other people to use.
The convention of using <localleader> for local mappings will prevent your
plugin from overwriting someone else's <leader> mapping that they've
painstakingly burned into their fingers over time.
Settings
In one of the earliest chapters of the book we talked about settings options
with set. Some options always apply to all of Vim, but others can be set on
a per-buffer basis.
Switch to file foo and run the following command:
--------------------------------------------------------------------------------
:setlocal wrap
--------------------------------------------------------------------------------
Now switch to file bar and run this command:
--------------------------------------------------------------------------------
:setlocal nowrap
--------------------------------------------------------------------------------
Make your Vim window smaller and you'll see that the lines in foo wrap, but
the lines in bar don't.
Let's try another option. Switch to foo and run this command:
--------------------------------------------------------------------------------
:setlocal number
--------------------------------------------------------------------------------
Now switch over to bar and run this command:
--------------------------------------------------------------------------------
:setlocal nonumber
--------------------------------------------------------------------------------
You now have line numbers in foo but not in bar.
Not all options can be used with setlocal. To see if you can set a particular
option locally, read its :help.
I've glossed over a bit of detail about how local options actually work for
now. In the exercises you'll learn more about the gory details.
Shadowing
Before we move on, let's look at a particularly interesting property of local
mappings. Switch over to foo and run the following commands:
--------------------------------------------------------------------------------
:nnoremap <buffer> Q x
:nnoremap Q dd
--------------------------------------------------------------------------------
Now type Q. What happens?
When you press Q, Vim will run the first mapping, not the second, because the
first mapping is more specific than the second.
Switch to file bar and type Q to see that Vim uses the second mapping,
because it's not shadowed by the first in this buffer.
Exercises
Read :help local-options.
Read :help setlocal.
Read :help map-local.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Autocommands
Now we're going to look at a topic almost as important as mappings:
autocommands.
Autocommands are a way to tell Vim to run certain commands whenever certain
events happen. Let's dive right into an example.
Open a new file with :edit foo and close it right away with :quit. Look on
your hard drive and you'll notice that the file is not there. This is because
Vim doesn't actually create the file until you save it for the first time.
Let's change it so that Vim creates files as soon as you edit them. Run the
following command:
--------------------------------------------------------------------------------
:autocmd BufNewFile * :write
--------------------------------------------------------------------------------
This is a lot to take in, but try it out and see that it works. Run :edit foo
again, close it with :quit, and look at your hard drive. This time the file
will be there (and empty, of course).
You'll have to close Vim to remove the autocommand. We'll talk about how to
avoid this in a later chapter.
Autocommand Structure
Let's take a closer look at the autocommand we just created:
--------------------------------------------------------------------------------
:autocmd BufNewFile * :write
^ ^ ^
| | |
| | The command to run.
| |
| A "pattern" to filter the event.
|
The "event" to watch for.
--------------------------------------------------------------------------------
The first piece of the command is the type of event we want to watch for. Vim
offers many events to watch. Some of them include:
This is just a tiny sample of the available events. There are many more you can
use to do lots of interesting things.
The next part of the command is a "pattern" that lets you be more specific about
when you want the command to fire. Start up a new Vim instance and run the
following command:
--------------------------------------------------------------------------------
:autocmd BufNewFile *.txt :write
--------------------------------------------------------------------------------
This is almost the same as the last command, but this time it will only apply to
files whose names end in .txt.
Try it out by running :edit bar, then :quit, then :edit bar.txt, then
:quit. You'll see that Vim writes the bar.txt automatically, but doesn't
write bar because it doesn't match the pattern.
The final part of the command is the command we want to run when the event
fires. This is pretty self-explanatory, except for one catch: you can't use
special characters like <cr> in the command. We'll talk about how to get
around this limitation later in the book, but for now you'll just have to live
with it.
Another Example
Let's define another autocommand, this time using a different event. Run the
following command:
--------------------------------------------------------------------------------
:autocmd BufWritePre *.html :normal gg=G
--------------------------------------------------------------------------------
We're getting a bit ahead of ourselves here because we're going to talk about
normal later in the book, but for now you'll need to bear with me because it's
tough to come up with useful examples at this point.
Create a new file called foo.html. Edit it with Vim and enter the following
text exactly, including the whitespace:
--------------------------------------------------------------------------------
<html>
<body>
<p>Hello!</p>
</body>
</html>
--------------------------------------------------------------------------------
Now save this file with :w. What happened? Vim seems to have reindented the
file for us before saving it!
For now I want you to trust me that running :normal gg=G will tell Vim to
reindent the current file. Don't worry about how that works just yet.
What we do want to pay attention to is the autocommand. The event type is
BufWritePre, which means the event will be checked just before you write any
file.
We used a pattern of *.html to ensure that this command will only fire when
we're working on files that end in .html. This lets us target our
autocommands at specific files, which is a very powerful idea that we'll
continue to explore later on.
Multiple Events
You can create a single autocommand bound to multiple events by separating the
events with a comma. Run this command:
--------------------------------------------------------------------------------
:autocmd BufWritePre,BufRead *.html :normal gg=G
--------------------------------------------------------------------------------
This is almost like our last command, except it will also reindent the code
whenever we read an HTML file as well as when we write it. This could be
useful if you have coworkers that don't indent their HTML nicely.
A common idiom in Vim scripting is to pair the BufRead and BufNewFile events
together to run a command whenever you open a certain kind of file, regardless
of whether it happens to exist already or not. Run the following command:
--------------------------------------------------------------------------------
:autocmd BufNewFile,BufRead *.html setlocal nowrap
--------------------------------------------------------------------------------
This will turn line wrapping off whenever you're working on an HTML file.
FileType Events
One of the most useful events is the FileType event. This event is fired
whenever Vim sets a buffer's filetype.
Let's set up a few useful mappings for a variety of file types. Run the
following commands:
--------------------------------------------------------------------------------
:autocmd FileType javascript nnoremap <buffer> <localleader>c I//<esc>
:autocmd FileType python nnoremap <buffer> <localleader>c I#<esc>
--------------------------------------------------------------------------------
Open a Javascript file (a file that ends in .js), pick a line and type
<localleader>c. This will comment out the line.
Now open a Python file (a file that ends in .py), pick a line and type
<localleader>c. This will comment out the line, but it will use Python's
comment character!
Using autocommands alongside the buffer-local mappings we learned about in the
last chapter we can create mappings that are specific to the type of file that
we're editing.
This reduces the load on our minds when we're coding. Instead of having to
think about moving to the beginning of the line and adding a comment character
we can simply think "comment this line".
Exercises
Skim :help autocmd-events to see a list of all the events you can bind
autocommands to. You don't need to memorize each one right now. Just try to
get a feel for the kinds of things you can do.
Create a few FileType autocommands that use setlocal to set options for your
favorite filetypes just the way you like them. Some options you might like to
change on a per-filetype basis are wrap, list, spell, and number.
Create a few more "comment this line" autocommands for filetypes you work with
often.
Add all of these autocommands to your ~/.vimrc file. Use your shortcut
mappings for editing and sourcing it quickly, of course!
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Buffer-Local Abbreviations
That last chapter was a monster, so let's tackle something easier. We've seen
how to define buffer-local mappings and options, so let's apply the same idea to
abbreviations.
Open your foo and bar files again, switch to foo, and run the following
command:
--------------------------------------------------------------------------------
:iabbrev <buffer> --- —
--------------------------------------------------------------------------------
While still in foo enter insert mode and type the following text:
--------------------------------------------------------------------------------
Hello --- world.
--------------------------------------------------------------------------------
Vim will replace the --- for you. Now switch to bar and try it. It should
be no surprise that it's not replaced, because we defined the abbreviation to be
local to the foo buffer.
Autocommands and Abbreviations
Let's pair up these buffer-local abbreviations with autocommands to set them to
make ourselves a little "snippet" system.
Run the following commands:
--------------------------------------------------------------------------------
:autocmd FileType python :iabbrev <buffer> iff if:<left>
:autocmd FileType javascript :iabbrev <buffer> iff if ()<left>
--------------------------------------------------------------------------------
Open a Javascript file and try out the iff abbreviation. Then open a Python
file and try it there too. Vim will perform the appropriate abbreviation
depending on the type of the current file.
Exercises
Create a few more "snippet" abbreviations for some of the things you type often
in specific kinds of files. Some good candidates are return for most
languages, function for javascript, and things like “ and ”
for HTML files.
Add these snippets to your ~/.vimrc file.
Remember: the best way to learn to use these new snippets is to disable the
old way of doing things. Running :iabbrev <buffer> return NOPENOPENOPE will
force you to use your abbreviation instead. Add these "training" snippets to
match all the ones you created to save time.
================================================================================
########>>>>>>>>>><<<<<<<<<<<%%%%%%%%%%%!!!!!!!!!!!!@@@@@@@@@@@&&&&&&&&*********
================================================================================
«»Autocommand Groups
A few chapters ago we learned about autocommands. Run the following command:
--------------------------------------------------------------------------------
:autocmd BufWrite * :echom "Writing buffer!"
--------------------------------------------------------------------------------
Now write the current buffer with :write and run :messages to view the
message log. You should see the Writing buffer! message in the list.
Now write the current buffer again and run :messages to view the message log.
You should see the Writing buffer! message in the list twice.
Now run the exact same autocommand again:
--------------------------------------------------------------------------------
:autocmd BufWrite * :echom "Writing buffer!"
--------------------------------------------------------------------------------
Write the current buffer one more time and run :messages. You will see the
Writing buffer! message in the list four times. What happened?
When you create an autocommand like this Vim has no way of knowing if you want
it to replace an existing one. In our case, Vim created two separate
autocommands that each happen to do the same thing.
The Problem
Now that you know it's possible to create duplicate autocommands, you may be
thinking: "So what? Just don't do that!"
The problem is that sourcing your ~/.vimrc file rereads the entire file,
including any autocommands you've defined! This means that every time you
source your ~/.vimrc you'll be duplicating autocommands, which will make Vim
run slower because it executes the same commands over and over.
To simulate this, try running the following command:
--------------------------------------------------------------------------------
:autocmd BufWrite * :sleep 200m
--------------------------------------------------------------------------------