Learning Vimscript
Notes taken from reading Learn Vimscript the Hard Way.
Persistent Echoing
Using :echom
will save the output and let you run :messages
to view it later.
Setting Options
There are two main kinds of options:
- Boolean options (either “on” or “off”):
:set <name>
turns the option on and:set no<name>
turns it off.:set <name>!
to toggle a boolean option.
- Options that take a value:
- Change non-boolean options with
:set <name>=<value>
,
- Change non-boolean options with
You can ask Vim what an option is currently set to by :set <name>?
.
Mappings
map, nmap, vmap, and imap
to create key mappings.- Each of the map commands has a
*noremap
counterpart that ignores other mappings:noremap, nnoremap, vnoremap, and inoremap
. *unmap
commands remove the mapping for the modes.
Autocommands
Autocommands are a way to tell Vim to run certain commands whenever certain events happen.
Vim offers many events to watch, :help autocommand-events
.
E.g.:
BufNewFile
starting to edit a file that doesn’t existBufRead
starting to edit a new buffer, after reading the fileFileType
when the filetype option has been set
Grouping Autocommands
Clear an autocommands group uses autocmd!
inside the group:
Local Abbreviations
Variables
Vim treats the integer 0
as false
and the integer 1
as true
.
Local Options
Set a local option as a variable using prefix: :let &l:number = 1
.
Registers as Variables
- Set registers as variables:
:let @a = "hello!"
. - Registers can also be read:
:echo @a
. - When yank (
y
), yanked value is stored in"
register::echo @"
. - When search (
/
), search command is stored in/
register::echo @/
.
Variable Scoping
When we used b:
in the variable name we told Vim that
the variable hello
should be local to the current buffer: :let b:hello = "world"
.
Conditionals
- Can separate each line with a pipe character (
|
).
If Condition
- Integer
0
isfalse
. - Vim does not necessarily treat a non-empty string as
true
:- Strings that start with a number are coerced to that number;
- Otherwise they’re coerced to
0
.
Case Sensitivity
The behavior of ==
depends on a user’s settings.
A bare ==
should never appear in your plugins’ code.
Use the case-insensitive ==?
or the case-sensitive ==#
.
You should always use explicit case sensitive or insensitive comparisons.
Functions
Vimscript functions must start with a capital letter if they are unscoped!
If a function doesn’t return a value, it implicitly returns 0
.
Function Arguments
When you write a Vimscript function that takes arguments,
you always need to prefix those arguments with a:
to tell Vim that
they’re in the argument scope.
Note: you can’t reassign argument variables.
Strings
Vim’s +
operator is only for Numbers. When you pass a string to +
,
Vim will try to coerce it to a number before performing the addition.
Use .
to concatenate strings: :echom "Hello, " . "world"
.
Using single quotes tells Vim that you want the string exactly as-is, with no escape sequences.
String Functions
- length:
strlen("foo")
orlen("foo")
. - splitting:
split("one two three")
orsplit("one,two,three", ",")
. - joining:
join(["foo", "bar"], "...")
. - casing:
tolower("Foo")
andtoupper("Foo")
.
Execute
The execute
command evaluate a string as if it were a Vimscript command.
Normal
The normal
command takes a sequence of keys as typed in normal mode.
- The
normal
command will take into account any mappings that exist. So always usenormal!
command to avoid mappings. - The
normal!
command doesn’t parse special character sequences like<cr>
. Combiningnormal!
withexecute
fixes that problem.
Regular Expressions
- Read
:help magic
. - Read
:help match
.
Lists
- Vimscript lists are ordered, heterogeneous collections of elements:
['foo', 3, 'bar']
. - The index
-1
refers to the last element in the list,-2
is the second-to-last, and so on. - Slicing
['a', 'b', 'c', 'd', 'e'][0:2] => ['a', 'b', 'c']
- Slice indexes can be negative:
['a', 'b', 'c', 'd', 'e'][-2:-1] => ['d', 'e']
- Concatenate with
+
:['a', 'b'] + ['c'] => ['a', 'b', 'c']
List Functions
add(foo, 'b')
mutates the listfoo
in-place to append'b'
.len(foo)
returns the length of the list.get(foo, 100, 'default')
get the item at the given index, or return the given default value if the index is out of range in the list.index(foo, 'b')
returns the first index of the given item,-1
if not found.join([1, 2, 3], ',')
returns1,2,3
reverse(foo)
reverses the given list in place.
Looping
For Loops
While Loops
Dictionaries
Vimscript dictionaries are similar to Javascript’s objects.
Dictionaries are created using curly brackets. Values are heterogeneous, but keys are always coerced to strings.
Vimscript also supports the Javascript-style “dot” lookup when the key is a string consisting only of letters, digits and/or underscores.
Dictionary Functions
let test = remove(foo, 'a')
andunlet foo.b
remove entries from a dictionary.get({'a': 100}, 'a', 'default')
.has_key({'a': 100}, 'a')
returns1
or0
.
Toggling
- For boolean options we can use set
someoption!
to “toggle” the option.
Functional Programming
Vimscript supports using variables to store functions: let Myfunc = function("sort")
.
Paths
Plugin
Folder Structure
Directory | Description |
---|---|
~/.vim/colors/ | color schemes |
~/.vim/plugin/ | run once every time Vim starts |
~/.vim/ftdetect/ | autocommands that detect and set the filetype of files |
~/.vim/ftplugin/ | filetype named files |
~/.vim/indent/ | indentation |
~/.vim/compiler/ | set compiler-related options in the current buffer based on their names |
~/.vim/after/ | loaded every time Vim starts, but after the files in ~/.vim/plugin/ |
~/.vim/autoload/ | delay the loading of your plugin’s code until it’s actually needed |
~/.vim/doc/ | documentation |