41Write a Vim script
The Vim script language is used for the startup vimrc file, syntax files, and many other things. This chapter explains the items that can be used in a Vim script. There are a lot of them, thus this is a long chapter.
- Introduction
- Variables
- Expressions
- Conditionals
- Executing an expression
- Using functions
- Defining a function
- Lists and Dictionaries
- Exceptions
- Various remarks
- Writing a plugin
- Writing a filetype plugin
- Writing a compiler plugin
- Writing a plugin that loads quickly
- Writing library scripts
- Distributing Vim scripts
Table of contents
41.1Introduction
Your first experience with Vim scripts is the vimrc file. Vim reads it when it starts up and executes the commands. You can set options to values you prefer. And you can use any colon command in it (commands that start with a :
; these are sometimes referred to as Ex commands or command-line commands).
Syntax files are also Vim scripts. As are files that set options for a specific file type. A complicated macro can be defined by a separate Vim script file. You can think of other uses yourself.
Let's start with a simple example:
:let i = 1
:while i < 5
: echo "count is" i
: let i += 1
:endwhile
The :
characters are not really needed here. You only need to use them when you type a command. In a Vim script file they can be left out. We will use them here anyway to make clear these are colon commands and make them stand out from Normal mode commands. Note: You can try out the examples by yanking the lines from the text here and executing them with :@"
The output of the example code is:
count is 1 count is 2 count is 3 count is 4
In the first line the :let
command assigns a value to a variable. The generic form is:
:let {variable} = {expression}
In this case the variable name is i
and the expression is a simple value, the number one.
The :while
command starts a loop. The generic form is:
:while {condition}
: {statements}
:endwhile
The statements until the matching :endwhile
are executed for as long as the condition is true. The condition used here is the expression "i
<
5". This is true when the variable i is smaller than five.
If you happen to write a while loop that keeps on running, you can interrupt it by pressing CTRL‑C (CTRL‑Break on MS-Windows).
The :echo
command prints its arguments. In this case the string "count is" and the value of the variable i. Since i is one, this will print:
count is 1
Then there is the :let i += 1
command. This does the same thing as :let i = i + 1
. This adds one to the variable i and assigns the new value to the same variable.
The example was given to explain the commands, but would you really want to make such a loop, it can be written much more compact:
:for i in range(1, 4)
: echo "count is" i
:endfor
We won't explain how :for and range() work until later. Follow the links if you are impatient.
#Four kinds of numbers
Numbers can be decimal, hexadecimal, octal or binary. A hexadecimal number starts with 0x
or 0X
. For example 0x1f
is decimal 31. An octal number starts with a zero. 017
is decimal 15. A binary number starts with 0b
or 0B
. For example 0b101
is decimal 5. Careful: don't put a zero before a decimal number, it will be interpreted as an octal number!
The :echo
command always prints decimal numbers. Example:
:echo 0x7f 036
127 30 ~
A number is made negative with a minus sign. This also works for hexadecimal, octal and binary numbers. A minus sign is also used for subtraction. Compare this with the previous example:
:echo 0x7f -036
97 ~
White space in an expression is ignored. However, it's recommended to use it for separating items, to make the expression easier to read. For example, to avoid the confusion with a negative number above, put a space between the minus sign and the following number:
:echo 0x7f - 036
41.2Variables
A variable name consists of ASCII letters, digits and the underscore. It cannot start with a digit. Valid variable names are:
counter _aap3 very_long_variable_name_with_underscores FuncLength LENGTH
Invalid names are foo+bar
and 6var
.
These variables are global. To see a list of currently defined variables use this command:
:let
You can use global variables everywhere. This also means that when the variable count
is used in one script file, it might also be used in another file. This leads to confusion at least, and real problems at worst. To avoid this, you can use a variable local to a script file by prepending s:
. For example, one script contains this code:
:let s:count = 1
:while s:count < 5
: source other.vim
: let s:count += 1
:endwhile
Since s:count
is local to this script, you can be sure that sourcing the other.vim
script will not change this variable. If other.vim
also uses an s:count
variable, it will be a different copy, local to that script. More about script-local variables here: script‑variable.
There are more kinds of variables, see internal‑variables. The most often used ones are:
b:name | variable local to a buffer |
w:name | variable local to a window |
g:name | global variable (also in a function) |
v:name | variable predefined by Vim |
#Deleting variables
Variables take up memory and show up in the output of the :let
command. To delete a variable use the :unlet
command. Example:
:unlet s:count
This deletes the script-local variable s:count
to free up the memory it uses. If you are not sure if the variable exists, and don't want an error message when it doesn't, append !:
:unlet! s:count
When a script finishes, the local variables used there will not be automatically freed. The next time the script executes, it can still use the old value. Example:
:if !exists("s:call_count")
: let s:call_count = 0
:endif
:let s:call_count = s:call_count + 1
:echo "called" s:call_count "times"
The exists()
function checks if a variable has already been defined. Its argument is the name of the variable you want to check. Not the variable itself! If you would do this:
:if !exists(s:call_count)
Then the value of s:call_count
will be used as the name of the variable that exists() checks. That's not what you want.
The exclamation mark !
negates a value. When the value was true, it becomes false. When it was false, it becomes true. You can read it as not
. Thus "if !exists()" can be read as "if not exists()".
What Vim calls true is anything that is not zero. Zero is false.
Vim automatically converts a string to a number when it is looking for a number. When using a string that doesn't start with a digit the resulting number is zero. Thus look out for this:
:if "true"
The "true" will be interpreted as a zero, thus as false!
#String variables and constants
So far only numbers were used for the variable value. Strings can be used as well. Numbers and strings are the basic types of variables that Vim supports. The type is dynamic, it is set each time when assigning a value to the variable with :let
. More about types in “Lists and Dictionaries”.
To assign a string value to a variable, you need to use a string constant. There are two types of these. First the string in double quotes:
:let name = "peter"
:echo name
peter ~
If you want to include a double quote inside the string, put a backslash in front of it:
:let name = "\"peter\""
:echo name
"peter" ~
To avoid the need for a backslash, you can use a string in single quotes:
:let name = '"peter"'
:echo name
"peter" ~
Inside a single-quote string all the characters are as they are. Only the single quote itself is special: you need to use two to get one. A backslash is taken literally, thus you can't use it to change the meaning of the character after it.
In double-quote strings it is possible to use special characters. Here are a few useful ones:
\t | <Tab> |
\n | <NL>, line break |
\r | <CR>, <Enter> |
\e | <Esc> |
\b | <BS>, backspace |
\" | " |
\\ | \ , backslash |
\<Esc> | <Esc> |
\<C-W> | CTRL‑W |
The last two are just examples. The \<name>
form can be used to include the special key name
.
See expr‑quote for the full list of special items in a string.
41.3Expressions
Vim has a rich, yet simple way to handle expressions. You can read the definition here: expression‑syntax. Here we will show the most common items.
The numbers, strings and variables mentioned above are expressions by themselves. Thus everywhere an expression is expected, you can use a number, string or variable. Other basic items in an expression are:
$NAME | environment variable |
&name | option |
@r | register |
Examples:
:echo "The value of 'tabstop' is" &ts
:echo "Your home directory is" $HOME
:if @a > 5
The &name form can be used to save an option value, set it to a new value, do something and restore the old value. Example:
:let save_ic = &ic
:set noic
:/The Start/,$delete
:let &ic = save_ic
This makes sure the "The Start" pattern is used with the ignorecase option off. Still, it keeps the value that the user had set. (Another way to do this would be to add \C
to the pattern, see /\C.)
#Mathematics
It becomes more interesting if we combine these basic items. Let's start with mathematics on numbers:
a + b | add |
a - b | subtract |
a * b | multiply |
a / b | divide |
a % b | modulo |
The usual precedence is used. Example:
:echo 10 + 5 * 2
20 ~
Grouping is done with parentheses. No surprises here. Example:
:echo (10 + 5) * 2
30 ~
Strings can be concatenated with .
. Example:
:echo "foo" . "bar"
foobar ~
When the :echo
command gets multiple arguments, it separates them with a space. In the example the argument is a single expression, thus no space is inserted.
Borrowed from the C language is the conditional expression:
a ? b : c
If a
evaluates to true b
is used, otherwise c
is used. Example:
:let i = 4
:echo i > 5 ? "i is big" : "i is small"
i is small ~
The three parts of the constructs are always evaluated first, thus you could see it work as:
(a) ? (b) : (c)
41.4Conditionals
The :if
commands executes the following statements, until the matching :endif
, only when a condition is met. The generic form is:
:if {condition} {statements} :endif
Only when the expression {condition} evaluates to true (non-zero) will the {statements} be executed. These must still be valid commands. If they contain garbage, Vim won't be able to find the :endif
.
You can also use :else
. The generic form for this is:
:if {condition} {statements} :else {statements} :endif
The second {statements} is only executed if the first one isn't.
Finally, there is :elseif
:
:if {condition} {statements} :elseif {condition} {statements} :endif
This works just like using :else
and then if
, but without the need for an extra :endif
.
A useful example for your vimrc file is checking the term option and doing something depending upon its value:
:if &term == "xterm"
: " Do stuff for xterm
:elseif &term == "vt100"
: " Do stuff for a vt100 terminal
:else
: " Do something for other terminals
:endif
#Logic operations
We already used some of them in the examples. These are the most often used ones:
a == b | equal to |
a != b | not equal to |
a > b | greater than |
a >= b | greater than or equal to |
a < b | less than |
a <= b | less than or equal to |
The result is one if the condition is met and zero otherwise. An example:
:if v:version >= 700
: echo "congratulations"
:else
: echo "you are using an old version, upgrade!"
:endif
Here v:version
is a variable defined by Vim, which has the value of the Vim version. 600 is for version 6.0. Version 6.1 has the value 601. This is very useful to write a script that works with multiple versions of Vim. v:version
The logic operators work both for numbers and strings. When comparing two strings, the mathematical difference is used. This compares byte values, which may not be right for some languages.
When comparing a string with a number, the string is first converted to a number. This is a bit tricky, because when a string doesn't look like a number, the number zero is used. Example:
:if 0 == "one"
: echo "yes"
:endif
This will echo yes
, because one
doesn't look like a number, thus it is converted to the number zero.
For strings there are two more items:
a =~ b | matches with |
a !~ b | does not match with |
The left item a
is used as a string. The right item b
is used as a pattern, like what's used for searching. Example:
:if str =~ " "
: echo "str contains a space"
:endif
:if str !~ '\.