summaryrefslogtreecommitdiff
path: root/runtime/doc/usr_41.txt
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-12-30 20:24:12 +0000
committerBram Moolenaar <Bram@vim.org>2021-12-30 20:24:12 +0000
commit04fb916684829f6aa12f33f14d0d0023b458f200 (patch)
tree83db5549cd2d924541be05e0be54986f27f0a3d0 /runtime/doc/usr_41.txt
parentd293981d2b76b40013143fe2302b910585e50808 (diff)
downloadvim-git-04fb916684829f6aa12f33f14d0d0023b458f200.tar.gz
Update runtime files
Diffstat (limited to 'runtime/doc/usr_41.txt')
-rw-r--r--runtime/doc/usr_41.txt1559
1 files changed, 764 insertions, 795 deletions
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 89bd54282..a9abe59be 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1,4 +1,4 @@
-*usr_41.txt* For Vim version 8.2. Last change: 2021 Sep 10
+*usr_41.txt* For Vim version 8.2. Last change: 2021 Dec 30
VIM USER MANUAL - by Bram Moolenaar
@@ -37,7 +37,8 @@ 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
+
+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.
@@ -47,23 +48,25 @@ script file. You can think of other uses yourself.
And if you are familiar with JavaScript:
https://w0rp.com/blog/post/vim-script-for-the-javascripter/
+Vim script comes in two flavors: legacy and |Vim9|. Since this help file is
+for new users, we'll teach you the newer and more convenient |Vim9| syntax.
+
+To try out Vim script the best way is to edit a script file and source it.
+Basically: >
+ :edit test.vim
+ [insert the script lines you want]
+ :w
+ :source %
+
Let's start with a simple example: >
- :let i = 1
- :while i < 5
- : echo "count is" i
- : let i += 1
- :endwhile
+ vim9script
+ var i = 1
+ while i < 5
+ echo "count is" i
+ i += 1
+ endwhile
<
- Note:
- 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 ~
@@ -71,45 +74,46 @@ The output of the example code is:
count is 3 ~
count is 4 ~
-In the first line the ":let" command assigns a value to a variable. The
+In the first line the `vim9script` command makes clear this is a new, |Vim9|
+script file. That matters for how the rest of the file is used.
+
+The `var i = 1` command declares the "i" variable and initializes it. The
generic form is: >
- :let {variable} = {expression}
+ var {name} = {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 `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
+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.
Note:
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"
+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.
-Note: this is how it works in legacy Vim script, which is what we discuss in
-this file. In Vim9 script it's a bit different, see |usr_46.txt|.
+Then there is the `i += 1` command. This does the same thing as "i = i + 1",
+it 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
+ 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
+We won't explain how `for` and `range()` work until later. Follow the links
if you are impatient.
@@ -120,32 +124,47 @@ 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 "0o", "0O" or a zero and another digit. "0o17" is
-decimal 15. Using just a zero prefix is not supported in Vim9 script.
+An octal number starts with "0o", "0O". "0o17" is decimal 15.
A binary number starts with "0b" or "0B". For example "0b101" is decimal 5.
-A decimal number is just digits. Careful: don't put a zero before a decimal
-number, it will be interpreted as an octal number in legacy script!
+A decimal number is just digits. Careful: In legacy script 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: >
+The `echo` command evaluates its argument and always prints decimal numbers.
+Example: >
- :echo 0x7f 0o36
+ echo 0x7f 0o36
< 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: >
+octal and binary numbers: >
+
+ echo -0x7f
+< -127 ~
- :echo 0x7f -0o36
-< 97 ~
+A minus sign is also used for subtraction. This can sometimes lead to
+confusion. If we put a minus sign before both numbers we get an error: >
-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 -0o36
+< E1004: White space required before and after '-' at "-0o36" ~
- :echo 0x7f - 0o36
+Note: if you are not using a |Vim9| script to try out these commands but type
+them directly, they will be executed as legacy script. Then the echo command
+sees the second minus sign as subtraction. To get the error, prefix the
+command with `vim9cmd`: >
+
+ vim9cmd echo -0x7f -0o36
+< E1004: White space required before and after '-' at "-0o36" ~
+
+White space in an expression is often required to make sure it is easy to read
+and avoid errors. Such as thinking that the "-0o36" above makes the number
+negative, while it is actually seen as a subtraction.
+
+To actually have the minus sign be used for negation, you can put the second
+expression in parenthesis: >
+
+ echo -0x7f (-0o36)
==============================================================================
*41.2* Variables
@@ -160,27 +179,45 @@ cannot start with a digit. Valid variable names are:
LENGTH
Invalid names are "foo+bar" and "6var".
- These variables are global. To see a list of currently defined variables
-use this command: >
+
+Some variables are global. To see a list of currently defined global
+variables type 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: >
+You can use global variables everywhere. However, it is easy to use the same
+name in two unrelated scripts. Therefore variables declared in a script are
+local to that script. For example, if you have this in "script1.vim": >
+
+ vim9script
+ var counter = 5
+ echo counter
+< 5 ~
+
+And you try to use the variable in "script2.vim": >
+
+ vim9script
+ echo counter
+< E121: Undefined variable: counter ~
+
+Using a script-local variable means you can be sure that it is only changed in
+that script and not elsewhere.
- :let s:count = 1
- :while s:count < 5
- : source other.vim
- : let s:count += 1
- :endwhile
+If you do want to share variables between scripts, use the "g:" prefix and
+assign the value directly, do not use `var`. Thus in "script1.vim": >
-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|.
+ vim9script
+ g:counter = 5
+ echo g:counter
+< 5 ~
+
+And then in "script2.vim": >
+
+ vim9script
+ echo g:counter
+< 5 ~
+
+More about script-local variables here: |script-variable|.
There are more kinds of variables, see |internal-variables|. The most often
used ones are:
@@ -193,79 +230,99 @@ used ones are:
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: >
+Variables take up memory and show up in the output of the `let` command. To
+delete a global variable use the `unlet` command. Example: >
- :unlet s:count
+ unlet g:counter
-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 !: >
+This deletes the global variable "g:counter" 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
+ unlet! g:counter
-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: >
+You cannot `unlet` script-local variables in |Vim9| script. You can in legacy
+script.
- :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"
+When a script finishes, the local variables declared there will not be
+deleted. Functions defined in the script can use them. Example:
+>
+ vim9script
+ var counter = 0
+ def g:GetCount(): number
+ s:counter += 1
+ return s:counter
+ enddef
-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: >
+Every time you call the function it will return the next count: >
+ :echo g:GetCount()
+< 1 ~
+>
+ :echo g:GetCount()
+< 2 ~
- :if !exists(s:call_count)
+If you are worried a script-local variable is consuming too much
+memory, set it to an empty value after you no longer need it.
-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.
- Note:
- 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!
+Note: below we'll leave out the `vim9script` line, so we can concentrate on
+the relevant commands, but you'll still need to put it at the top of your
+script file.
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 |41.8|.
- 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: >
+Example: >
- :let name = "peter"
- :echo name
+ var name = "Peter"
+ echo name
< peter ~
-If you want to include a double quote inside the string, put a backslash in
-front of it: >
+Every variable has a type. Very often, as in this example, the type is
+defined by assigning a value. This is called type inference. If you do not
+want to give the variable a value yet, you need to specify the type: >
+
+ var name: string
+ var age: number
+ ...
+ name = "Peter"
+ age = 42
+
+If you make a mistake and try to assign the wrong type of value you'll get an
+error: >
+
+ age = "Peter"
+< E1012: Type mismatch; expected number but got string ~
+
+More about types in |41.8|.
+
+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, as we used
+already. If you want to include a double quote inside the string, put a
+backslash in front of it: >
- :let name = "\"peter\""
- :echo name
-< "peter" ~
+ var name = "he is \"Peter\""
+ echo name
+< he is "Peter" ~
To avoid the need for a backslash, you can use a string in single quotes: >
- :let name = '"peter"'
- :echo name
-< "peter" ~
+ var name = 'he is "Peter"'
+ echo name
+< he is "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:
+character after it: >
+
+ var name = 'P\e''ter'''
+ echo name
+< P\e'ter' ~
+
+In double-quote strings it is possible to use special characters. Here are a
+few useful ones:
\t <Tab>
\n <NL>, line break
@@ -279,15 +336,17 @@ a few useful ones:
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.
+
+See |expr-quote| for the full list of special items in a string.
==============================================================================
*41.3* Expressions
-Vim has a rich, yet simple way to handle expressions. You can read the
+Vim has a fairly standard 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
+
+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:
@@ -297,17 +356,17 @@ string or variable. Other basic items in an expression are:
Examples: >
- :echo "The value of 'tabstop' is" &ts
- :echo "Your home directory is" $HOME
- :if @a > 5
+ echo "The value of 'tabstop' is" &ts
+ echo "Your home directory is" $HOME
+ if @a == 'text'
-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: >
+The &name form can also be used to set an option value, do something and
+restore the old value. Example: >
- :let save_ic = &ic
- :set noic
- :/The Start/,$delete
- :let &ic = save_ic
+ var save_ic = &ic
+ set noic
+ s/The Start/The Beginning/
+ &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
@@ -327,80 +386,86 @@ mathematics on numbers:
The usual precedence is used. Example: >
- :echo 10 + 5 * 2
+ echo 10 + 5 * 2
< 20 ~
Grouping is done with parentheses. No surprises here. Example: >
- :echo (10 + 5) * 2
+ echo (10 + 5) * 2
< 30 ~
Strings can be concatenated with ".." (see |expr6|). Example: >
- :echo "foo" .. "bar"
+ echo "foo" .. "bar"
< foobar ~
-When the ":echo" command gets multiple arguments, it separates them with a
+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:
+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 ~
+ var nr = 4
+ echo nr > 5 ? "nr is big" : "nr is small"
+< nr is small ~
The three parts of the constructs are always evaluated first, thus you could
-see it work as:
+see it works as: >
(a) ? (b) : (c)
==============================================================================
*41.4* Conditionals
-The ":if" commands executes the following statements, until the matching
-":endif", only when a condition is met. The generic form is:
+The `if` commands executes the following statements, until the matching
+`endif`, only when a condition is met. The generic form is:
- :if {condition}
+ if {condition}
{statements}
- :endif
+ 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:
+Only when the expression {condition} evaluates to true or one will the
+{statements} be executed. If they are not executed they must still be valid
+commands. If they contain garbage, Vim won't be able to find the matching
+`endif`.
- :if {condition}
+You can also use `else`. The generic form for this is:
+
+ if {condition}
{statements}
- :else
+ else
{statements}
- :endif
+ endif
-The second {statements} is only executed if the first one isn't.
- Finally, there is ":elseif":
+The second {statements} block is only executed if the first one isn't.
- :if {condition}
+Finally, there is `elseif`
+
+ if {condition}
{statements}
- :elseif {condition}
+ elseif {condition}
{statements}
- :endif
+ 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: >
+This works just like using `else` and then `if`, but without the need for an
+extra `endif`.
- :if &term == "xterm"
- : " Do stuff for xterm
- :elseif &term == "vt100"
- : " Do stuff for a vt100 terminal
- :else
- : " Do something for other terminals
- :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
+
+This uses "#" to start a comment, more about that later.
LOGIC OPERATIONS
@@ -415,168 +480,186 @@ ones:
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: >
+The result is true if the condition is met and false otherwise. An example: >
- :if v:version >= 700
- : echo "congratulations"
- :else
- : echo "you are using an old version, upgrade!"
- :endif
+ 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
+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.
+If you try to compare a string with a number you will get an error.
-For strings there are two more items:
+For strings there are two more useful items:
- a =~ b matches with
- a !~ b does not match with
+ str =~ pat matches with
+ str !~ pat does not match with
-The left item "a" is used as a string. The right item "b" is used as a
+The left item "str" is used as a string. The right item "pat" is used as a
pattern, like what's used for searching. Example: >
- :if str =~ " "
- : echo "str contains a space"
- :endif
- :if str !~ '\.$'
- : echo "str does not end in a full stop"
- :endif
+ if str =~ " "
+ echo "str contains a space"
+ endif
+ if str !~ '\.$'
+ echo "str does not end in a full stop"
+ endif
Notice the use of a single-quote string for the pattern. This is useful,
because backslashes would need to be doubled in a double-quote string and
patterns tend to contain many backslashes.
-The 'ignorecase' option is used when comparing strings. When you don't want
-that, append "#" to match case and "?" to ignore case. Thus "==?" compares
-two strings to be equal while ignoring case. And "!~#" checks if a pattern
-doesn't match, also checking the case of letters. For the full table see
-|expr-==|.
+The match is not anchored, if you want to match the whole string start with
+"^" and end with "$".
+
+The 'ignorecase' option is not used when comparing strings. When you do want
+to ignore case append "?". Thus "==?" compares two strings to be equal while
+ignoring case. For the full table see |expr-==|.
MORE LOOPING
-The ":while" command was already mentioned. Two more statements can be used
-in between the ":while" and the ":endwhile":
+The `while` command was already mentioned. Two more statements can be used in
+between the `while` and the `endwhile`:
- :continue Jump back to the start of the while loop; the
+ continue Jump back to the start of the while loop; the
loop continues.
- :break Jump forward to the ":endwhile"; the loop is
+ break Jump forward to the `endwhile`; the loop is
discontinued.
Example: >
- :while counter < 40
- : call do_something()
- : if skip_flag
- : continue
- : endif
- : if finished_flag
- : break
- : endif
- : sleep 50m
- :endwhile
+ while counter < 40
+ do_something()
+ if skip_flag
+ continue
+ endif
+ if finished_flag
+ break
+ endif
+ sleep 50m
+ --counter
+ endwhile
-The ":sleep" command makes Vim take a nap. The "50m" specifies fifty
-milliseconds. Another example is ":sleep 4", which sleeps for four seconds.
+The `sleep` command makes Vim take a nap. The "50m" specifies fifty
+milliseconds. Another example is `sleep 4`, which sleeps for four seconds.
-Even more looping can be done with the ":for" command, see below in |41.8|.
+Even more looping can be done with the `for` command, see below in |41.8|.
==============================================================================
*41.5* Executing an expression
So far the commands in the script were executed by Vim directly. The
-":execute" command allows executing the result of an expression. This is a
+`execute` command allows executing the result of an expression. This is a
very powerful way to build commands and execute them.
- An example is to jump to a tag, which is contained in a variable: >
- :execute "tag " .. tag_name
+An example is to jump to a tag, which is contained in a variable: >
+
+ execute "tag " .. tag_name
The ".." is used to concatenate the string "tag " with the value of variable
"tag_name". Suppose "tag_name" has the value "get_cmd", then the command that
will be executed is: >
- :tag get_cmd
+ tag get_cmd
-The ":execute" command can only execute colon commands. The ":normal" command
+The `execute` command can only execute Ex commands. The `normal` command
executes Normal mode commands. However, its argument is not an expression but
the literal command characters. Example: >
- :normal gg=G
+ normal gg=G
+
+This jumps to the first line with "gg" and formats all lines with the "="
+operator and the "G" movement.
-This jumps to the first line and formats all lines with the "=" operator.
- To make ":normal" work with an expression, combine ":execute" with it.
+To make `normal` work with an expression, combine `execute` with it.
Example: >
- :execute "normal " .. normal_commands
+ execute "normal " .. count .. "j"
+
+This will move the cursor "count" lines down.
-The variable "normal_commands" must contain the Normal mode commands.
- Make sure that the argument for ":normal" is a complete command. Otherwise
+Make sure that the argument for `normal` is a complete command. Otherwise
Vim will run into the end of the argument and abort the command. For example,
-if you start Insert mode, you must leave Insert mode as well. This works: >
+if you start the delete operator, you must give the movement command also.
+This works: >
+
+ normal d$
- :execute "normal Inew text \<Esc>"
+This does nothing: >
-This inserts "new text " in the current line. Notice the use of the special
-key "\<Esc>". This avoids having to enter a real <Esc> character in your
-script.
+ normal d
+
+If you start Insert mode and do not end it with Esc, it will end anyway. This
+works to insert "new text": >
+
+ execute "normal inew text"
+
+If you want to do something after inserting text you do need to end Insert
+mode: >
+
+ execute "normal inew text\<Esc>b"
+
+This inserts "new text" and puts the cursor on the first letter of "text".
+Notice the use of the special key "\<Esc>". This avoids having to enter a
+real <Esc> character in your script. That is where `execute` with a
+double-quote string comes in handy.
If you don't want to execute a string but evaluate it to get its expression
value, you can use the eval() function: >
- :let optname = "path"
- :let optval = eval('&' .. optname)
+ var optname = "path"
+ var optvalue = eval('&' .. optname)
A "&" character is prepended to "path", thus the argument to eval() is
"&path". The result will then be the value of the 'path' option.
- The same thing can be done with: >
- :exe 'let optval = &' .. optname
==============================================================================
*41.6* Using functions
Vim defines many functions and provides a large amount of functionality that
way. A few examples will be given in this section. You can find the whole
-list here: |functions|.
+list below: |function-list|.
-A function is called with the ":call" command. The parameters are passed in
+A function is called with the `call` command. The parameters are passed in
between parentheses separated by commas. Example: >
- :call search("Date: ", "W")
+ call search("Date: ", "W")
This calls the search() function, with arguments "Date: " and "W". The
search() function uses its first argument as a search pattern and the second
one as flags. The "W" flag means the search doesn't wrap around the end of
the file.
+Using `call` is optional in |Vim9| script, this works the same way: >
+
+ search("Date: ", "W")
+
A function can be called in an expression. Example: >
- :let line = getline(".")
- :let repl = substitute(line, '\a', "*", "g")
- :call setline(".", repl)
+ var line = getline(".")
+ var repl = substitute(line, '\a', "*", "g")
+ setline(".", repl)
The getline() function obtains a line from the current buffer. Its argument
is a specification of the line number. In this case "." is used, which means
the line where the cursor is.
- The substitute() function does something similar to the ":substitute"
-command. The first argument is the string on which to perform the
-substitution. The second argument is the pattern, the third the replacement
-string. Finally, the last arguments are the flags.
- The setline() function sets the line, specified by the first argument, to a
+
+The substitute() function does something similar to the `substitute` command.
+The first argument is the string on which to perform the substitution. The
+second argument is the pattern, the third the replacement string. Finally,
+the last arguments are the flags.
+
+The setline() function sets the line, specified by the first argument, to a
new string, the second argument. In this example the line under the cursor is
replaced with the result of the substitute(). Thus the effect of the three
statements is equal to: >
@@ -590,8 +673,8 @@ after the substitute() call.
FUNCTIONS *function-list*
There are many functions. We will mention them here, grouped by what they are
-used for. You can find an alphabetical list here: |functions|. Use CTRL-] on
-the function name to jump to detailed help on it.
+used for. You can find an alphabetical list here: |builtin-function-list|.
+Use CTRL-] on the function name to jump to detailed help on it.
String manipulation: *string-functions*
nr2char() get a character by its number value
@@ -1234,9 +1317,9 @@ Various: *various-functions*
Vim enables you to define your own functions. The basic function declaration
begins as follows: >
- :function {name}({var1}, {var2}, ...)
- : {body}
- :endfunction
+ def {name}({var1}, {var2}, ...): return-type
+ {body}
+ enddef
<
Note:
Function names must begin with a capital letter.
@@ -1244,115 +1327,107 @@ begins as follows: >
Let's define a short function to return the smaller of two numbers. It starts
with this line: >
- :function Min(num1, num2)
+ def Min(num1: number, num2: number): number
+
+This tells Vim that the function is named "Min", it takes two arguments that
+are numbers: "num1" and "num2" and returns a number.
-This tells Vim that the function is named "Min" and it takes two arguments:
-"num1" and "num2".
- The first thing you need to do is to check to see which number is smaller:
+The first thing you need to do is to check to see which number is smaller:
>
- : if a:num1 < a:num2
+ if num1 < num2
-The special prefix "a:" tells Vim that the variable is a function argument.
Let's assign the variable "smaller" the value of the smallest number: >
- : if a:num1 < a:num2
- : let smaller = a:num1
- : else
- : let smaller = a:num2
- : endif
+ var smaller: number
+ if num1 < num2
+ smaller = num1
+ else
+ smaller = num2
+ endif
The variable "smaller" is a local variable. Variables used inside a function
-are local unless prefixed by something like "g:", "a:", or "s:".
+are local unless prefixed by something like "g:", "w:", or "s:".
Note:
To access a global variable from inside a function you must prepend
"g:" to it. Thus "g:today" inside a function is used for the global
variable "today", and "today" is another variable, local to the
- function.
+ function or the script.
-You now use the ":return" statement to return the smallest number to the user.
+You now use the `return` statement to return the smallest number to the user.
Finally, you end the function: >
- : return smaller
- :endfunction
+ return smaller
+ enddef
The complete function definition is as follows: >
- :function Min(num1, num2)
- : if a:num1 < a:num2
- : let smaller = a:num1
- : else
- : let smaller = a:num2
- : endif
- : return smaller
- :endfunction
+ def Min(num1: number, num2: number): number
+ var smaller: number
+ if num1 < num2
+ smaller = num1
+ else
+ smaller = num2
+ endif
+ return smaller
+ enddef
+
+Obviously this is a verbose example. You can make it shorter by using two
+return commands: >
+
+ def Min(num1: number, num2: number): number
+ if num1 < num2
+ return num1
+ endif
+ return num2
+ enddef
-For people who like short functions, this does the same thing: >
+And if you remember the conditional expression, you need only one line: >
- :function Min(num1, num2)
- : if a:num1 < a:num2
- : return a:num1
- : endif
- : return a:num2
- :endfunction
+ def Min(num1: number, num2: number): number
+ return num1 < num2 ? num1 : num2
+ enddef
A user defined function is called in exactly the same way as a built-in
function. Only the name is different. The Min function can be used like
this: >
- :echo Min(5, 8)
+ echo Min(5, 8)
-Only now will the function be executed and the lines be interpreted by Vim.
+Only now will the function be executed and the lines be parsed by Vim.
If there are mistakes, like using an undefined variable or function, you will
now get an error message. When defining the function these errors are not
-detected.
+detected. To get the errors sooner you can tell Vim to compile all the
+functions in the script: >
-When a function reaches ":endfunction" or ":return" is used without an
-argument, the function returns zero.
+ defcompile
-To redefine a function that already exists, use the ! for the ":function"
-command: >
-
- :function! Min(num1, num2, num3)
+For a function that does not return anything leave out the return type: >
+ def SayIt(text: string)
+ echo text
+ enddef
-USING A RANGE
-
-The ":call" command can be given a line range. This can have one of two
-meanings. When a function has been defined with the "range" keyword, it will
-take care of the line range itself.
- The function will be passed the variables "a:firstline" and "a:lastline".
-These will have the line numbers from the range the function was called with.
-Example: >
+It is also possible to define a legacy function with `function` and
+`endfunction`. These do not have types and are not compiled. They execute
+much slower.
- :function Count_words() range
- : let lnum = a:firstline
- : let n = 0
- : while lnum <= a:lastline
- : let n = n + len(split(getline(lnum)))
- : let lnum = lnum + 1
- : endwhile
- : echo "found " .. n .. " words"
- :endfunction
-You can call this function with: >
-
- :10,30call Count_words()
+USING A RANGE
-It will be executed once and echo the number of words.
- The other way to use a line range is by defining a function without the
-"range" keyword. The function will be called once for every line in the
-range, with the cursor in that line. Example: >
+A line range can be used with a function call. The function will be called
+once for every line in the range, with the cursor in that line. Example: >
- :function Number()
- : echo "line " .. line(".") .. " contains: " .. getline(".")
- :endfunction
+ def Number()
+ echo "line " .. line(".") .. " contains: " .. getline(".")
+ enddef
If you call this function with: >
:10,15call Number()
-The function will be called six times.
+The function will be called six times, starting on line 10 and ending on line
+15.
VARIABLE NUMBER OF ARGUMENTS
@@ -1361,43 +1436,50 @@ Vim enables you to define functions that have a variable number of arguments.
The following command, for instance, defines a function that must have 1
argument (start) and can have up to 20 additional arguments: >
- :function Show(start, ...)
+ def Show(start: string, ...items: list<string>)
-The variable "a:1" contains the first optional argument, "a:2" the second, and
-so on. The variable "a:0" contains the number of extra arguments.
- For example: >
+The variable "items" will be a list containing the extra arguments. You can
+use it like any list, for example: >
- :function Show(start, ...)
- : echohl Title
- : echo "start is " .. a:start
- : echohl None
- : let index = 1
- : while index <= a:0
- : echo " Arg " .. index .. " is " .. a:{index}
- : let index = index + 1
- : endwhile
- : echo ""
- :endfunction
+ def Show(start: string, ...items: list<string>)
+ echohl Title
+ echo "start is " .. start
+ echohl None
+ for index in range(len(items))
+ echon " Arg " .. index .. " is " .. items[index]
+ endfor
+ echo
+ enddef
-This uses the ":echohl" command to specify the highlighting used for the
-following ":echo" command. ":echohl None" stops it again. The ":echon"
-command works like ":echo", but doesn't output a line break.
+You can call it like this: >
-You can also use the a:000 variable, it is a List of all the "..." arguments.
-See |a:000|.
+ Show('Title', 'one', 'two', 'three')
+< start is Title Arg 0 is one Arg 1 is two Arg 2 is three ~
+
+This uses the `echohl` command to specify the highlighting used for the
+following `echo` command. `echohl None` stops it again. The `echon` command
+works like `echo`, but doesn't output a line break.
+
+If you call it with one argument the "items" list will be empty.
+`range(len(items))` returns a list with the indexes, what `for` loops over,
+we'll explain that further down.
LISTING FUNCTIONS
-The ":function" command lists the names and arguments of all user-defined
+The `function` command lists the names and arguments of all user-defined
functions: >
:function
-< function Show(start, ...) ~
+< def <SNR>86_Show(start: string, ...items: list<string>) ~
function GetVimIndent() ~
function SetSyn(name) ~
-To see what a function does, use its name as an argument for ":function": >
+The "<SNR>" prefix means that a function is script-local. |Vim9| functions
+wil start with "def" and include argument and return types. Legacy functions
+are listed with "function".
+
+To see what a function does, use its name as an argument for `function`: >
:function SetSyn
< 1 if &syntax == '' ~
@@ -1405,55 +1487,64 @@ To see what a function does, use its name as an argument for ":function": >
3 endif ~
endfunction ~
+To see the "Show" function you need to include the script prefix, since a
+"Show" function can be defined multiple times in different scripts. To find
+the exact name you can use `function`, but the result may be a very long list.
+To only get the functions matching a pattern you can use the `filter` prefix:
+>
+
+ :filter Show function
+< def <SNR>86_Show(start: string, ...items: list<string>) ~
+>
+ :function <SNR>86_Show
+< 1 echohl Title ~
+ 2 echo "start is " .. start ~
+ etc.
+
DEBUGGING
The line number is useful for when you get an error message or when debugging.
See |debug-scripts| about debugging mode.
- You can also set the 'verbose' option to 12 or higher to see all function
+
+You can also set the 'verbose' option to 12 or higher to see all function
calls. Set it to 15 or higher to see every executed line.
DELETING A FUNCTION
-To delete the Show() function: >
+To delete the SetSyn() function: >
- :delfunction Show
+ :delfunction SetSyn
-You get an error when the function doesn't exist.
+Deleting only works for global functions and functions in legacy script, not
+for functions defined in a |Vim9| script.
+
+You get an error when the function doesn't exist or cannot be deleted.
FUNCTION REFERENCES
Sometimes it can be useful to have a variable point to one function or
-another. You can do it with the function() function. It turns the name of a
-function into a reference: >
-
- :let result = 0 " or 1
- :function! Right()
- : return 'Right!'
- :endfunc
- :function! Wrong()
- : return 'Wrong!'
- :endfunc
- :
- :if result == 1
- : let Afunc = function('Right')
- :else
- : let Afunc = function('Wrong')
- :endif
- :echo call(Afunc, [])
+another. You can do it with function reference variable. Often shortened to
+"funcref". Example: >
+
+ def Right()
+ return 'Right!'
+ enddef
+ def Wrong()
+ return 'Wrong!'
+ enddef
+
+ var Afunc = g:result == 1 ? Right : Wrong
+ Afunc()
< Wrong! ~
+This assumes "g:result" is not one.
+
Note that the name of a variable that holds a function reference must start
with a capital. Otherwise it could be confused with the name of a builtin
function.
- The way to invoke a function that a variable refers to is with the call()
-function. Its first argument is the function reference, the second argument
-is a List with arguments.
-
-Function references are most useful in combination with a Dictionary, as is
-explained in the next section.
More information about defining your own functions here: |user-functions|.
@@ -1463,94 +1554,97 @@ More information about defining your own functions here: |user-functions|.
So far we have used the basic types String and Number. Vim also supports two
composite types: List and Dictionary.
-A List is an ordered sequence of things. The things can be any kind of value,
+A List is an ordered sequence of items. The items can be any kind of value,
thus you can make a List of numbers, a List of Lists and even a List of mixed
items. To create a List with three strings: >
- :let alist = ['aap', 'mies', 'noot']
+ var alist = ['aap', 'mies', 'noot']
The List items are enclosed in square brackets and separated by commas. To
create an empty List: >
- :let alist = []
+ var alist = []
You can add items to a List with the add() function: >
- :let alist = []
- :call add(alist, 'foo')
- :call add(alist, 'bar')
- :echo alist
+ var alist = []
+ add(alist, 'foo')
+ add(alist, 'bar')
+ echo alist
< ['foo', 'bar'] ~
List concatenation is done with +: >
- :echo alist + ['foo', 'bar']
-< ['foo', 'bar', 'foo', 'bar'] ~
+ var alist = ['foo', 'bar']
+ alist = alist + ['and', 'more']
+ echo alist
+< ['foo', 'bar', 'and', 'more'] ~
-Or, if you want to extend a List directly: >
+Or, if you want to extend a List with a function: >
- :let alist = ['one']
- :call extend(alist, ['two', 'three'])
- :echo alist
+ var alist = ['one']
+ extend(alist, ['two', 'three'])
+ echo alist
< ['one', 'two', 'three'] ~
-Notice that using add() will have a different effect: >
+Notice that using `add()` will have a different effect: >
- :let alist = ['one']
- :call add(alist, ['two', 'three'])
- :echo alist
+ var alist = ['one']
+ add(alist, ['two', 'three'])
+ echo alist
< ['one', ['two', 'three']] ~
-The second argument of add() is added as a single item.
+The second argument of add() is added as an item, now you have a nested list.
FOR LOOP
One of the nice things you can do with a List is iterate over it: >
- :let alist = ['one', 'two', 'three']
- :for n in alist
- : echo n
- :endfor
+ var alist = ['one', 'two', 'three']
+ for n in alist
+ echo n
+ endfor
< one ~
two ~
three ~
-This will loop over each element in List "alist", assigning the value to
+This will loop over each element in List "alist", assigning each value to
variable "n". The generic form of a for loop is: >
- :for {varname} in {listexpression}
- : {commands}
- :endfor
+ for {varname} in {listexpression}
+ {commands}
+ endfor
To loop a certain number of times you need a List of a specific length. The
range() function creates one for you: >
- :for a in range(3)
- : echo a
- :endfor
+ for a in range(3)
+ echo a
+ endfor
< 0 ~
1 ~
2 ~
Notice that the first item of the List that range() produces is zero, thus the
last item is one less than the length of the list.
- You can also specify the maximum value, the stride and even go backwards: >
- :for a in range(8, 4, -2)
- : echo a
- :endfor
+You can also specify the maximum value, the stride and even go backwards: >
+
+ for a in range(8, 4, -2)
+ echo a
+ endfor
< 8 ~
6 ~
4 ~
A more useful example, looping over lines in the buffer: >
- :for line in getline(1, 20)
- : if line =~ "Date: "
- : echo matchstr(line, 'Date: \zs.*')
- : endif
- :endfor
+ for line in getline(1, 20)
+ if line =~ "Date: "
+ echo line
+ endif
+ endfor
This looks into lines 1 to 20 (inclusive) and echoes any date found in there.
@@ -1560,11 +1654,16 @@ DICTIONARIES
A Dictionary stores key-value pairs. You can quickly lookup a value if you
know the key. A Dictionary is created with curly braces: >
- :let uk2nl = {'one': 'een', 'two': 'twee', 'three': 'drie'}
+ var uk2nl = {one: 'een', two: 'twee', three: 'drie'}
Now you can lookup words by putting the key in square brackets: >
- :echo uk2nl['two']
+ echo uk2nl['two']
+< twee ~
+
+If the key does not have special characters, you can use the dot notation: >
+
+ echo uk2nl.two
< twee ~
The generic form for defining a Dictionary is: >
@@ -1579,9 +1678,9 @@ The possibilities with Dictionaries are numerous. There are various functions
for them as well. For example, you can obtain a list of the keys and loop
over them: >
- :for key in keys(uk2nl)
- : echo key
- :endfor
+ for key in keys(uk2nl)
+ echo key
+ endfor
< three ~
one ~
two ~
@@ -1589,9 +1688,9 @@ over them: >
You will notice the keys are not ordered. You can sort the list to get a
specific order: >
- :for key in sort(keys(uk2nl))
- : echo key
- :endfor
+ for key in sort(keys(uk2nl))
+ echo key
+ endfor
< one ~
three ~
two ~
@@ -1600,147 +1699,6 @@ But you can never get back the order in which items are defined. For that you
need to use a List, it stores items in an ordered sequence.
-DICTIONARY FUNCTIONS
-
-The items in a Dictionary can normally be obtained with an index in square
-brackets: >
-
- :echo uk2nl['one']
-< een ~
-
-A method that does the same, but without so many punctuation characters: >
-
- :echo uk2nl.one
-< een ~
-
-This only works for a key that is made of ASCII letters, digits and the
-underscore. You can also assign a new value this way: >
-
- :let uk2nl.four = 'vier'
- :echo uk2nl
-< {'three': 'drie', 'four': 'vier', 'one': 'een', 'two': 'twee'} ~
-
-And now for something special: you can directly define a function and store a
-reference to it in the dictionary: >
-
- :function uk2nl.translate(line) dict
- : return join(map(split(a:line), 'get(self, v:val, "???")'))
- :endfunction
-
-Let's first try it out: >
-
- :echo uk2nl.translate('three two five one')
-< drie twee ??? een ~
-
-The first special thing you notice is the "dict" at the end of the ":function"
-line. This marks the function as being used from a Dictionary. The "self"
-local variable will then refer to that Dictionary.
- Now let's break up the complicated return command: >
-
- split(a:line)
-
-The split() function takes a string, chops it into whitespace separated words
-and returns a list with these words. Thus in the example it returns: >
-
- :echo split('three two five one')
-< ['three', 'two', 'five', 'one'] ~
-
-This list is the first argument to the map() function. This will go through
-the list, evaluating its second argument with "v:val" set to the value of each
-item. This is a shortcut to using a for loop. This command: >
-
- :let alist = map(split(a:line), 'get(self, v:val, "???")')
-
-Is equivalent to: >
-
- :let alist = split(a:line)
- :for idx in range(len(alist))
- : let alist[idx] = get(self, alist[idx], "???")
- :endfor
-
-The get() function checks if a key is present in a Dictionary. If it is, then
-the value is retrieved. If it isn't, then the default value is returned, in
-the example it's '???'. This is a convenient way to handle situations where a
-key may not be present and you don't want an error message.
-
-The join() function does the opposite of split(): it joins together a list of
-words, putting a space in between.
- This combination of split(), map() and join() is a nice way to filter a line
-of words in a very compact way.
-
-
-OBJECT ORIENTED PROGRAMMING
-
-Now that you can put both values and functions in a Dictionary, you can
-actually use a Dictionary like an object.
- Above we used a Dictionary for translating Dutch to English. We might want
-to do the same for other languages. Let's first make an object (aka
-Dictionary) that has the translate function, but no words to translate: >
-
- :let transdict = {}
- :function transdict.translate(line) dict
- : return join(map(split(a:line), 'get(self.words, v:val, "???")'))
- :endfunction
-
-It's slightly different from the function above, using 'self.words' to lookup
-word translations. But we don't have a self.words. Thus you could call this
-an abstract class.
-
-Now we can instantiate a Dutch translation object: >
-
- :let uk2nl = copy(transdict)
- :let uk2nl.words = {'one': 'een', 'two': 'twee', 'three': 'drie'}
- :echo uk2nl.translate('three one')
-< drie een ~
-
-And a German translator: >
-
- :let uk2de = copy(transdict)
- :let uk2de.words = {'one': 'eins', 'two': 'zwei', 'three': 'drei'}
- :echo uk2de.translate('three one')
-< drei eins ~
-
-You see that the copy() function is used to make a copy of the "transdict"
-Dictionary and then the copy is changed to add the words. The original
-remains the same, of course.
-
-Now you can go one step further, and use your preferred translator: >
-
- :if $LANG =~ "de"
- : let trans = uk2de
- :else
- : let trans = uk2nl
- :endif
- :echo trans.translate('one two three')
-< een twee drie ~
-
-Here "trans" refers to one of the two objects (Dictionaries). No copy is
-made. More about List and Dictionary identity can be found at |list-identity|
-and |dict-identity|.
-
-Now you might use a language that isn't supported. You can overrule the
-translate() function to do nothing: >
-
- :let uk2uk = copy(transdict)
- :function! uk2uk.translate(line)
- : return a:line
- :endfunction
- :echo uk2uk.translate('three one wladiwostok')
-< three one wladiwostok ~
-
-Notice that a ! was used to overwrite the existing function reference. Now
-use "uk2uk" when no recognized language is found: >
-
- :if $LANG =~ "de"
- : let trans = uk2de
- :elseif $LANG =~ "nl"
- : let trans = uk2nl
- :else
- : let trans = uk2uk
- :endif
- :echo trans.translate('one two three')
-< one two three ~
-
For further reading see |Lists| and |Dictionaries|.
==============================================================================
@@ -1748,53 +1706,58 @@ For further reading see |Lists| and |Dictionaries|.
Let's start with an example: >
- :try
- : read ~/templates/pascal.tmpl
- :catch /E484:/
- : echo "Sorry, the Pascal template file cannot be found."
- :endtry
+ try
+ read ~/templates/pascal.tmpl
+ catch /E484:/
+ echo "Sorry, the Pascal template file cannot be found."
+ endtry
-The ":read" command will fail if the file does not exist. Instead of
+The `read` command will fail if the file does not exist. Instead of
generating an error message, this code catches the error and gives the user a
nice message.
-For the commands in between ":try" and ":endtry" errors are turned into
+For the commands in between `try` and `endtry` errors are turned into
exceptions. An exception is a string. In the case of an error the string
contains the error message. And every error message has a number. In this
case, the error we catch contains "E484:". This number is guaranteed to stay
the same (the text may change, e.g., it may be translated).
-When the ":read" command causes another error, the pattern "E484:" will not
+Besides being able to give a nice error message, Vim will also continue
+executing commands. Otherwise, once an uncaught error is encountered,
+execution will be aborted.
+
+When the `read` command causes another error, the pattern "E484:" will not
match in it. Thus this exception will not be caught and result in the usual
error message.
You might be tempted to do this: >
- :try
- : read ~/templates/pascal.tmpl
- :catch
- : echo "Sorry, the Pascal template file cannot be found."
- :endtry
+ try
+ read ~/templates/pascal.tmpl
+ catch
+ echo "Sorry, the Pascal template file cannot be found."
+ endtry
-This means all errors are caught. But then you will not see errors that are
-useful, such as "E21: Cannot make changes, 'modifiable' is off".
+This means all errors are caught. But then you will not see an error that
+would indicate a completely different problem, such as "E21: Cannot make
+changes, 'modifiable' is off".
-Another useful mechanism is the ":finally" command: >
+Another useful mechanism is the `finally` command: >
- :let tmp = tempname()
- :try
- : exe ".,$write " .. tmp
- : exe "!filter " .. tmp
- : .,$delete
- : exe "$read " .. tmp
- :finally
- : call delete(tmp)
- :endtry
+ var tmp = tempname()
+ try
+ exe ":.,$write " .. tmp
+ exe "!filter " .. tmp
+ :.,$delete
+ exe ":$read " .. tmp
+ finally
+ call delete(tmp)
+ endtry
This filters the lines from the cursor until the end of the file through the
"filter" command, which takes a file name argument. No matter if the
-filtering works, something goes wrong in between ":try" and ":finally" or the
-user cancels the filtering by pressing CTRL-C, the "call delete(tmp)" is
+filtering works, something goes wrong in between `try` and `finally` or the
+user cancels the filtering by pressing CTRL-C, the `call delete(tmp)` is
always executed. This makes sure you don't leave the temporary file behind.
More information about exception handling can be found in the reference
@@ -1803,30 +1766,25 @@ manual: |exception-handling|.
==============================================================================
*41.10* Various remarks
-Here is a summary of items that apply to Vim scripts. They are also mentioned
-elsewhere, but form a nice checklist.
+Here is a summary of items that are useful to know when writing Vim scripts.
+
+The end-of-line character depends on the system. For Vim scripts it is
+recommended to always use the Unix fileformat, this also works on any other
+system. That way you can copy your Vim scripts from MS-Windows to Unix and
+they still work. See |:source_crnl|. To be sure it is set right, do this
+before writing the file: >
-The end-of-line character depends on the system. For Unix a single <NL>
-character is used. For MS-Windows and the like, <CR><NL> is used. This is
-important when using mappings that end in a <CR>. See |:source_crnl|.
+ :setlocal fileformat=unix
WHITE SPACE
Blank lines are allowed and ignored.
-Leading whitespace characters (blanks and TABs) are always ignored. The
-whitespaces between parameters (e.g. between the "set" and the "cpoptions" in
-the example below) are reduced to one blank character and plays the role of a
-separator, the whitespaces after the last (visible) character may or may not
-be ignored depending on the situation, see below.
-
-For a ":set" command involving the "=" (equal) sign, such as in: >
-
- :set cpoptions =aABceFst
+Leading whitespace characters (blanks and TABs) are always ignored.
-the whitespace immediately before the "=" sign is ignored. But there can be
-no whitespace after the "=" sign!
+Trailing whitespace is often ignored, but not always. One command that
+includes it is `map`.
To include a whitespace character in the value of an option, it must be
escaped by a "\" (backslash) as in the following example: >
@@ -1843,81 +1801,84 @@ will issue an error, because it is interpreted as: >
:set nice
:set file
+|Vim9| script is very picky when it comes to white space. This was done
+intentionally to make sure scripts are easy to read and to avoid mistakes.
+
COMMENTS
-The character " (the double quote mark) starts a comment. Everything after
+In |Vim9| script the character # starts a comment. Everything after
and including this character until the end-of-line is considered a comment and
is ignored, except for commands that don't consider comments, as shown in
-examples below. A comment can start on any character position on the line.
+examples below. A comment can start on any character position on the line,
+but not when it is part of the command, e.g. in a string.
+
+The character " (the double quote mark) starts a comment in legacy script.
There is a little "catch" with comments for some commands. Examples: >
- :abbrev dev development " shorthand
- :map <F3> o#include " insert include
- :execute cmd " do it
- :!ls *.c " list C files
+ abbrev dev development # shorthand
+ map <F3> o#include # insert include
+ execute cmd # do it
+ !ls *.c # list C files
-The abbreviation 'dev' will be expanded to 'development " shorthand'. The
+The abbreviation 'dev' will be expanded to 'development # shorthand'. The
mapping of <F3> will actually be the whole line after the 'o# ....' including
-the '" insert include'. The "execute" command will give an error. The "!"
-command will send everything after it to the shell, causing an error for an
-unmatched '"' character.
- There can be no comment after ":map", ":abbreviate", ":execute" and "!"
-commands (there are a few more commands with this restriction). For the
-":map", ":abbreviate" and ":execute" commands there is a trick: >
+the '# insert include'. The `execute` command will give an error. The `!`
+command will send everything after it to the shell, most likely causing an
+error.
- :abbrev dev development|" shorthand
- :map <F3> o#include|" insert include
- :execute cmd |" do it
+There can be no comment after `map`, `abbreviate`, `execute` and `!` commands
+(there are a few more commands with this restriction). For the `map`,
+`abbreviate` and `execute` commands there is a trick: >
+
+ abbrev dev development|# shorthand
+ map <F3> o#include|# insert include
+ execute '!ls *.c' |# do it
With the '|' character the command is separated from the next one. And that
-next command is only a comment. For the last command you need to do two
-things: |:execute| and use '|': >
- :exe '!ls *.c' |" list C files
+next command is only a comment. The last command, using `execute` is a
+general solution, it works for all commands that do not accept a comment or a
+'|' to separate the next command.
Notice that there is no white space before the '|' in the abbreviation and
mapping. For these commands, any character until the end-of-line or '|' is
included. As a consequence of this behavior, you don't always see that
trailing whitespace is included: >
- :map <F4> o#include
+ map <F4> o#include
-To spot these problems, you can set the 'list' option when editing vimrc
-files.
+To spot these problems, you can highlight trailing spaces: >
+ match Search /\s\+$/
For Unix there is one special way to comment a line, that allows making a Vim
-script executable: >
+script executable, and it also works in legacy script: >
#!/usr/bin/env vim -S
echo "this is a Vim script"
quit
-The "#" command by itself lists a line with the line number. Adding an
-exclamation mark changes it into doing nothing, so that you can add the shell
-command to execute the rest of the file. |:#!| |-S|
-
PITFALLS
-Even bigger problem arises in the following example: >
+An even bigger problem arises in the following example: >
- :map ,ab o#include
- :unmap ,ab
+ map ,ab o#include
+ unmap ,ab
Here the unmap command will not work, because it tries to unmap ",ab ". This
does not exist as a mapped sequence. An error will be issued, which is very
-hard to identify, because the ending whitespace character in ":unmap ,ab " is
+hard to identify, because the ending whitespace character in `unmap ,ab ` is
not visible.
And this is the same as what happens when one uses a comment after an 'unmap'
command: >
- :unmap ,ab " comment
+ unmap ,ab # comment
Here the comment part will be ignored. However, Vim will try to unmap
',ab ', which does not exist. Rewrite it as: >
- :unmap ,ab| " comment
+ unmap ,ab| # comment
RESTORING THE VIEW
@@ -1925,8 +1886,9 @@ RESTORING THE VIEW
Sometimes you want to make a change and go back to where the cursor was.
Restoring the relative position would also be nice, so that the same line
appears at the top of the window.
- This example yanks the current line, puts it above the first line in the
-file and then restores the view: >
+
+This example yanks the current line, puts it above the first line in the file
+and then restores the view: >
map ,p ma"aYHmbgg"aP`bzt`a
@@ -1944,31 +1906,21 @@ What this does: >
PACKAGING
-To avoid your function names to interfere with functions that you get from
-others, use this scheme:
-- Prepend a unique string before each function name. I often use an
- abbreviation. For example, "OW_" is used for the option window functions.
-- Put the definition of your functions together in a file. Set a global
- variable to indicate that the functions have been loaded. When sourcing the
- file again, first unload the functions.
-Example: >
-
- " This is the XXX package
-
- if exists("XXX_loaded")
- delfun XXX_one
- delfun XXX_two
- endif
+Sometimes you will want to use global variables or functions, so that they can
+be used anywhere. A good example is a global variable that passes a
+preference to a plugin. To avoid other scripts using the same name, use a
+prefix that is very unlikely to be used elsewhere. For example, if you have a
+"mytags" plugin, you could use: >
- function XXX_one(a)
- ... body of function ...
- endfun
+ g:mytags_location = '$HOME/project'
+ g:mytags_style = 'fast'
- function XXX_two(b)
- ... body of function ...
- endfun
+To minimize interference between plugins keep as much as possible local to the
+script. |Vim9| script helps you with that, by default functions and variables
+are script-local.
- let XXX_loaded = 1
+If you split your plugin into parts, you can use `import` and `export` to
+share items between those parts. See `:export` for the details.
==============================================================================
*41.11* Writing a plugin *write-plugin*
@@ -1992,10 +1944,9 @@ NAME
First of all you must choose a name for your plugin. The features provided
by the plugin should be clear from its name. And it should be unlikely that
someone else writes a plugin with the same name but which does something
-different. And please limit the name to 8 characters, to avoid problems on
-old MS-Windows systems.
+different.
-A script that corrects typing mistakes could be called "typecorr.vim". We
+A script that corrects typing mistakes could be called "typecorrect.vim". We
will use it here as an example.
For the plugin to work for everybody, it should follow a few guidelines. This
@@ -2011,7 +1962,6 @@ Let's start with the body of the plugin, the lines that do the actual work: >
16 iabbrev wnat want
17 iabbrev synchronisation
18 \ synchronization
- 19 let s:count = 4
The actual list should be much longer, of course.
@@ -2019,6 +1969,18 @@ The line numbers have only been added to explain a few things, don't put them
in your plugin file!
+FIRST LINE
+>
+ 1 vim9script noclear
+
+You need to use `vimscript` as the very first command. Best is to put it in
+the very first line.
+
+The script we are writing will have a `finish` command to bail out when it is
+loaded a second time. To avoid the items defined in the script are lost the
+"noclear" argument is used. More info about this at |vim9-reload|.
+
+
HEADER
You will probably add new corrections to the plugin and soon have several
@@ -2026,64 +1988,63 @@ versions lying around. And when distributing this file, people will want to
know who wrote this wonderful plugin and where they can send remarks.
Therefore, put a header at the top of your plugin: >
- 1 " Vim global plugin for correcting typing mistakes
- 2 " Last Change: 2000 Oct 15
- 3 " Maintainer: Bram Moolenaar <Bram@vim.org>
+ 2 # Vim global plugin for correcting typing mistakes
+ 3 # Last Change: 2021 Dec 30
+ 4 # Maintainer: Bram Moolenaar <Bram@vim.org>
About copyright and licensing: Since plugins are very useful and it's hardly
worth restricting their distribution, please consider making your plugin
either public domain or use the Vim |license|. A short note about this near
the top of the plugin should be sufficient. Example: >
- 4 " License: This file is placed in the public domain.
+ 5 # License: This file is placed in the public domain.
-LINE CONTINUATION, AVOIDING SIDE EFFECTS *use-cpo-save*
+LINE CONTINUATION AND AVOIDING SIDE EFFECTS *use-cpo-save*
In line 18 above, the line-continuation mechanism is used |line-continuation|.
Users with 'compatible' set will run into trouble here, they will get an error
message. We can't just reset 'compatible', because that has a lot of side
-effects. To avoid this, we will set the 'cpoptions' option to its Vim default
+effects. Instead, we will set the 'cpoptions' option to its Vim default
value and restore it later. That will allow the use of line-continuation and
make the script work for most people. It is done like this: >
- 11 let s:save_cpo = &cpo
+ 11 var save_cpo = &cpo
12 set cpo&vim
..
- 42 let &cpo = s:save_cpo
- 43 unlet s:save_cpo
+ 42 &cpo = save_cpo
-We first store the old value of 'cpoptions' in the s:save_cpo variable. At
+We first store the old value of 'cpoptions' in the "save_cpo" variable. At
the end of the plugin this value is restored.
-Notice that a script-local variable is used |s:var|. A global variable could
+Notice that "save_cpo" is a script-local variable. A global variable could
already be in use for something else. Always use script-local variables for
things that are only used in the script.
NOT LOADING
-It's possible that a user doesn't always want to load this plugin. Or the
+It is possible that a user doesn't always want to load this plugin. Or the
system administrator has dropped it in the system-wide plugin directory, but a
user has his own plugin he wants to use. Then the user must have a chance to
-disable loading this specific plugin. This will make it possible: >
+disable loading this specific plugin. These lines will make it possible: >
- 6 if exists("g:loaded_typecorr")
- 7 finish
- 8 endif
- 9 let g:loaded_typecorr = 1
+ 7 if exists("g:loaded_typecorrect")
+ 8 finish
+ 9 endif
+ 10 g:loaded_typecorrect = 1
-This also avoids that when the script is loaded twice it would cause error
-messages for redefining functions and cause trouble for autocommands that are
-added twice.
+This also avoids that when the script is loaded twice it would pointlessly
+redefine functions and cause trouble for autocommands that are added twice.
-The name is recommended to start with "loaded_" and then the file name of the
-plugin, literally. The "g:" is prepended just to avoid mistakes when using
-the variable in a function (without "g:" it would be a variable local to the
-function).
+The name is recommended to start with "g:loaded_" and then the file name of
+the plugin, literally. The "g:" is prepended to make the variable global, so
+that other places can check whether its functionality is available. Without
+"g:" it would be local to the script.
-Using "finish" stops Vim from reading the rest of the file, it's much quicker
-than using if-endif around the whole file.
+Using `finish` stops Vim from reading the rest of the file, it's much quicker
+than using if-endif around the whole file, since Vim would still need to parse
+the commands to find the `endif`.
MAPPING
@@ -2098,10 +2059,10 @@ item can be used: >
The "<Plug>TypecorrAdd;" thing will do the work, more about that further on.
-The user can set the "mapleader" variable to the key sequence that he wants
-this mapping to start with. Thus if the user has done: >
+The user can set the "g:mapleader" variable to the key sequence that he wants
+plugin mappings to start with. Thus if the user has done: >
- let mapleader = "_"
+ g:mapleader = "_"
the mapping will define "_a". If the user didn't do this, the default value
will be used, which is a backslash. Then a map for "\a" will be defined.
@@ -2131,44 +2092,45 @@ If a script gets longer, you often want to break up the work in pieces. You
can use functions or mappings for this. But you don't want these functions
and mappings to interfere with the ones from other scripts. For example, you
could define a function Add(), but another script could try to define the same
-function. To avoid this, we define the function local to the script by
-prepending it with "s:".
+function. To avoid this, we define the function local to the script.
+Fortunately, in |Vim9| script this is the default. In a legacy script you
+would need to prefix the name with "s:".
We will define a function that adds a new typing correction: >
- 30 function s:Add(from, correct)
- 31 let to = input("type the correction for " .. a:from .. ": ")
- 32 exe ":iabbrev " .. a:from .. " " .. to
+ 30 def Add(from: string, correct: bool)
+ 31 var to = input("type the correction for " .. from .. ": ")
+ 32 exe ":iabbrev " .. from .. " " .. to
..
- 36 endfunction
+ 36 enddef
-Now we can call the function s:Add() from within this script. If another
-script also defines s:Add(), it will be local to that script and can only
-be called from the script it was defined in. There can also be a global Add()
-function (without the "s:"), which is again another function.
+Now we can call the function Add() from within this script. If another
+script also defines Add(), it will be local to that script and can only
+be called from that script. There can also be a global g:Add() function,
+which is again another function.
<SID> can be used with mappings. It generates a script ID, which identifies
the current script. In our typing correction plugin we use it like this: >
24 noremap <unique> <script> <Plug>TypecorrAdd; <SID>Add
..
- 28 noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
+ 28 noremap <SID>Add :call <SID>Add(expand("<cword>"), true)<CR>
Thus when a user types "\a", this sequence is invoked: >
- \a -> <Plug>TypecorrAdd; -> <SID>Add -> :call <SID>Add()
+ \a -> <Plug>TypecorrAdd; -> <SID>Add -> :call <SID>Add(...)
If another script also maps <SID>Add, it will get another script ID and
thus define another mapping.
-Note that instead of s:Add() we use <SID>Add() here. That is because the
-mapping is typed by the user, thus outside of the script. The <SID> is
-translated to the script ID, so that Vim knows in which script to look for
+Note that instead of Add() we use <SID>Add() here. That is because the
+mapping is typed by the user, thus outside of the script context. The <SID>
+is translated to the script ID, so that Vim knows in which script to look for
the Add() function.
This is a bit complicated, but it's required for the plugin to work together
with other plugins. The basic rule is that you use <SID>Add() in mappings and
-s:Add() in other places (the script itself, autocommands, user commands).
+Add() in other places (the script itself, autocommands, user commands).
We can also add a menu entry to do the same as the mapping: >
@@ -2217,13 +2179,16 @@ USER COMMAND
Now let's add a user command to add a correction: >
38 if !exists(":Correct")
- 39 command -nargs=1 Correct :call s:Add(<q-args>, 0)
+ 39 command -nargs=1 Correct :call Add(<q-args>, false)
40 endif
The user command is defined only if no command with the same name already
exists. Otherwise we would get an error here. Overriding the existing user
command with ":command!" is not a good idea, this would probably make the user
wonder why the command he defined himself doesn't work. |:command|
+If it did happen you can find out who to blame with: >
+
+ verbose command Correct
SCRIPT VARIABLES
@@ -2234,20 +2199,25 @@ with using the same variable name in different scripts. The variables will be
kept as long as Vim is running. And the same variables are used when sourcing
the same script again. |s:var|
-The fun is that these variables can also be used in functions, autocommands
-and user commands that are defined in the script. In our example we can add
-a few lines to count the number of corrections: >
+The nice thing about |Vim9| script is that variables are local to the script
+by default. You can prepend "s:" if you like, but you do not need to. And
+functions in the script can also use the script variables without a prefix.
- 19 let s:count = 4
+Script-local variables can also be used in functions, autocommands and user
+commands that are defined in the script. Thus they are the perfect way to
+share information between parts of your plugin, without it leaking out. In
+our example we can add a few lines to count the number of corrections: >
+
+ 19 var count = 4
..
- 30 function s:Add(from, correct)
+ 30 def Add(from: string, correct: bool)
..
- 34 let s:count = s:count + 1
- 35 echo s:count .. " corrections now"
- 36 endfunction
+ 34 count += 1
+ 35 echo "you now have " .. count .. " corrections"
+ 36 enddef
-First s:count is initialized to 4 in the script itself. When later the
-s:Add() function is called, it increments s:count. It doesn't matter from
+"count" is declared and initialized to 4 in the script itself. When later
+the Add() function is called, it increments "count". It doesn't matter from
where the function was called, since it has been defined in the script, it
will use the local variables from this script.
@@ -2256,17 +2226,17 @@ THE RESULT
Here is the resulting complete example: >
- 1 " Vim global plugin for correcting typing mistakes
- 2 " Last Change: 2000 Oct 15
- 3 " Maintainer: Bram Moolenaar <Bram@vim.org>
- 4 " License: This file is placed in the public domain.
- 5
- 6 if exists("g:loaded_typecorr")
- 7 finish
- 8 endif
- 9 let g:loaded_typecorr = 1
- 10
- 11 let s:save_cpo = &cpo
+ 1 vim9script noclear
+ 2 # Vim global plugin for correcting typing mistakes
+ 3 # Last Change: 2021 Dec 30
+ 4 # Maintainer: Bram Moolenaar <Bram@vim.org>
+ 5 # License: This file is placed in the public domain.
+ 6
+ 7 if exists("g:loaded_typecorrect")
+ 8 finish
+ 9 endif
+ 10 g:loaded_typecorrect = 1
+ 11 var save_cpo = &cpo
12 set cpo&vim
13
14 iabbrev teh the
@@ -2274,7 +2244,7 @@ Here is the resulting complete example: >
16 iabbrev wnat want
17 iabbrev synchronisation
18 \ synchronization
- 19 let s:count = 4
+ 19 var count = 4
20
21 if !hasmapto('<Plug>TypecorrAdd;')
22 map <unique> <Leader>a <Plug>TypecorrAdd;
@@ -2283,35 +2253,27 @@ Here is the resulting complete example: >
25
26 noremenu <script> Plugin.Add\ Correction <SID>Add
27
- 28 noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
+ 28 noremap <SID>Add :call <SID>Add(expand("<cword>"), true)<CR>
29
- 30 function s:Add(from, correct)
- 31 let to = input("type the correction for " .. a:from .. ": ")
- 32 exe ":iabbrev " .. a:from .. " " .. to
- 33 if a:correct | exe "normal viws\<C-R>\" \b\e" | endif
- 34 let s:count = s:count + 1
- 35 echo s:count .. " corrections now"
- 36 endfunction
+ 30 def Add(from: string, correct: bool)
+ 31 var to = input("type the correction for " .. from .. ": ")
+ 32 exe ":iabbrev " .. from .. " " .. to
+ 33 if correct | exe "normal viws\<C-R>\" \b\e" | endif
+ 34 count += 1
+ 35 echo "you now have " .. count .. " corrections"
+ 36 enddef
37
38 if !exists(":Correct")
- 39 command -nargs=1 Correct :call s:Add(<q-args>, 0)
+ 39 command -nargs=1 Correct call Add(<q-args>, false)
40 endif
41
- 42 let &cpo = s:save_cpo
- 43 unlet s:save_cpo
+ 42 &cpo = save_cpo
Line 33 wasn't explained yet. It applies the new correction to the word under
the cursor. The |:normal| command is used to use the new abbreviation. Note
that mappings and abbreviations are expanded here, even though the function
was called from a mapping defined with ":noremap".
-Using "unix" for the 'fileformat' option is recommended. The Vim scripts will
-then work everywhere. Scripts with 'fileformat' set to "dos" do not work on
-Unix. Also see |:source_crnl|. To be sure it is set right, do this before
-writing the file: >
-
- :set fileformat=unix
-
DOCUMENTATION *write-local-help*
@@ -2319,9 +2281,9 @@ It's a good idea to also write some documentation for your plugin. Especially
when its behavior can be changed by the user. See |add-local-help| for how
they are installed.
-Here is a simple example for a plugin help file, called "typecorr.txt": >
+Here is a simple example for a plugin help file, called "typecorrect.txt": >
- 1 *typecorr.txt* Plugin for correcting typing mistakes
+ 1 *typecorrect.txt* Plugin for correcting typing mistakes
2
3 If you make typing mistakes, this plugin will have them corrected
4 automatically.
@@ -2336,7 +2298,7 @@ Here is a simple example for a plugin help file, called "typecorr.txt": >
13 :Correct {word}
14 Add a correction for {word}.
15
- 16 *typecorr-settings*
+ 16 *typecorrect-settings*
17 This plugin doesn't have any settings.
The first line is actually the only one for which the format matters. It will
@@ -2347,7 +2309,7 @@ line up nicely.
You can add more tags inside ** in your help file. But be careful not to use
existing help tags. You would probably use the name of your plugin in most of
-them, like "typecorr-settings" in the example.
+them, like "typecorrect-settings" in the example.
Using references to other parts of the help in || is recommended. This makes
it easy for the user to find associated help.
@@ -2360,7 +2322,7 @@ detection snippet in a separate file. It is usually in the form of an
autocommand that sets the filetype when the file name matches a pattern.
Example: >
- au BufNewFile,BufRead *.foo set filetype=foofoo
+ au BufNewFile,BufRead *.foo setlocal filetype=foofoo
Write this single-line file as "ftdetect/foofoo.vim" in the first directory
that appears in 'runtimepath'. For Unix that would be
@@ -2375,7 +2337,7 @@ SUMMARY *plugin-special*
Summary of special things to use in a plugin:
-s:name Variables local to the script.
+var name Variable local to the script.
<SID> Script-ID, used for mappings and functions local to
the script.
@@ -2386,9 +2348,9 @@ hasmapto() Function to test if the user already defined a mapping
<Leader> Value of "mapleader", which the user defines as the
keys that plugin mappings start with.
-:map <unique> Give a warning if a mapping already exists.
+map <unique> Give a warning if a mapping already exists.
-:noremap <script> Use only mappings local to the script, not global
+noremap <script> Use only mappings local to the script, not global
mappings.
exists(":Cmd") Check if a user command already exists.
@@ -2411,19 +2373,20 @@ DISABLING
If you are writing a filetype plugin to be used by many people, they need a
chance to disable loading it. Put this at the top of the plugin: >
- " Only do this when not done yet for this buffer
+ # Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
finish
endif
- let b:did_ftplugin = 1
+ b:did_ftplugin = 1
This also needs to be used to avoid that the same plugin is executed twice for
the same buffer (happens when using an ":edit" command without arguments).
Now users can disable loading the default plugin completely by making a
-filetype plugin with only this line: >
+filetype plugin with only these lines: >
- let b:did_ftplugin = 1
+ vim9script
+ b:did_ftplugin = 1
This does require that the filetype plugin directory comes before $VIMRUNTIME
in 'runtimepath'!
@@ -2443,10 +2406,10 @@ OPTIONS
To make sure the filetype plugin only affects the current buffer use the >
- :setlocal
+ setlocal
command to set options. And only set options which are local to a buffer (see
-the help for the option to check that). When using |:setlocal| for global
+the help for the option to check that). When using `:setlocal` for global
options or options local to a window, the value will change for many buffers,
and that is not what a filetype plugin should do.
@@ -2455,14 +2418,14 @@ When an option has a value that is a list of flags or items, consider using
changed an option value already. First resetting to the default value and
then changing it is often a good idea. Example: >
- :setlocal formatoptions& formatoptions+=ro
+ setlocal formatoptions& formatoptions+=ro
MAPPINGS
To make sure mappings will only work in the current buffer use the >
- :map <buffer>
+ map <buffer>
command. This needs to be combined with the two-step mapping explained above.
An example of how to define functionality in a filetype plugin: >
@@ -2487,9 +2450,9 @@ The user must have a chance to disable the mappings in a filetype plugin,
without disabling everything. Here is an example of how this is done for a
plugin for the mail filetype: >
- " Add mappings, unless the user didn't want this.
- if !exists("no_plugin_maps") && !exists("no_mail_maps")
- " Quote text by inserting "> "
+ # Add mappings, unless the user didn't want this.
+ if !exists("g:no_plugin_maps") && !exists("g:no_mail_maps")
+ # Quote text by inserting "> "
if !hasmapto('<Plug>MailQuote;')
vmap <buffer> <LocalLeader>q <Plug>MailQuote;
nmap <buffer> <LocalLeader>q <Plug>MailQuote;
@@ -2499,8 +2462,8 @@ plugin for the mail filetype: >
endif
Two global variables are used:
-|no_plugin_maps| disables mappings for all filetype plugins
-|no_mail_maps| disables mappings for the "mail" filetype
+|g:no_plugin_maps| disables mappings for all filetype plugins
+|g:no_mail_maps| disables mappings for the "mail" filetype
USER COMMANDS
@@ -2508,14 +2471,14 @@ USER COMMANDS
To add a user command for a specific file type, so that it can only be used in
one buffer, use the "-buffer" argument to |:command|. Example: >
- :command -buffer Make make %:r.s
+ command -buffer Make make %:r.s
VARIABLES
A filetype plugin will be sourced for each buffer of the type it's for. Local
-script variables |s:var| will be shared between all invocations. Use local
-buffer variables |b:var| if you want a variable specifically for one buffer.
+script variables will be shared between all invocations. Use local buffer
+variables |b:var| if you want a variable specifically for one buffer.
FUNCTIONS
@@ -2524,11 +2487,11 @@ When defining a function, this only needs to be done once. But the filetype
plugin will be sourced every time a file with this filetype will be opened.
This construct makes sure the function is only defined once: >
- :if !exists("*s:Func")
- : function s:Func(arg)
- : ...
- : endfunction
- :endif
+ if !exists("*Func")
+ def Func(arg)
+ ...
+ enddef
+ endif
<
UNDO *undo_indent* *undo_ftplugin*
@@ -2537,7 +2500,7 @@ When the user does ":setfiletype xyz" the effect of the previous filetype
should be undone. Set the b:undo_ftplugin variable to the commands that will
undo the settings in your filetype plugin. Example: >
- let b:undo_ftplugin = "setlocal fo< com< tw< commentstring<"
+ b:undo_ftplugin = "setlocal fo< com< tw< commentstring<"
\ .. "| unlet b:match_ignorecase b:match_words b:match_skip"
Using ":setlocal" with "<" after the option name resets the option to its
@@ -2569,14 +2532,14 @@ Summary of special things to use in a filetype plugin:
<LocalLeader> Value of "maplocalleader", which the user defines as
the keys that filetype plugin mappings start with.
-:map <buffer> Define a mapping local to the buffer.
+map <buffer> Define a mapping local to the buffer.
-:noremap <script> Only remap mappings defined in this script that start
+noremap <script> Only remap mappings defined in this script that start
with <SID>.
-:setlocal Set an option for the current buffer only.
+setlocal Set an option for the current buffer only.
-:command -buffer Define a user command local to the buffer.
+command -buffer Define a user command local to the buffer.
exists("*s:Func") Check if a function was already defined.
@@ -2592,17 +2555,17 @@ load it with the |:compiler| command. The main use is to set the
Easiest is to have a look at examples. This command will edit all the default
compiler plugins: >
- :next $VIMRUNTIME/compiler/*.vim
+ next $VIMRUNTIME/compiler/*.vim
-Use |:next| to go to the next plugin file.
+Type `:next` to go to the next plugin file.
There are two special items about these files. First is a mechanism to allow
a user to overrule or add to the default file. The default files start with: >
- :if exists("current_compiler")
- : finish
- :endif
- :let current_compiler = "mine"
+ if exists("g:current_compiler")
+ finish
+ endif
+ g:current_compiler = "mine"
When you write a compiler file and put it in your personal runtime directory
(e.g., ~/.vim/compiler for Unix), you set the "current_compiler" variable to
@@ -2644,8 +2607,9 @@ mean is that it loads quickly the first time, postponing the bulk of the
script to the second time, which only happens when you actually use it. When
you always use the functionality it actually gets slower!
-Note that since Vim 7 there is an alternative: use the |autoload|
-functionality |41.15|.
+This uses a FuncUndefined autocommand. Since Vim 7 there is an alternative:
+use the |autoload| functionality |41.15|. That will also use |Vim9| script
+instead of legacy script that is used here.
The following example shows how it's done: >
@@ -2718,7 +2682,7 @@ Example: >
if !exists('*MyLibFunction')
runtime library/mylibscript.vim
endif
- call MyLibFunction(arg)
+ MyLibFunction(arg)
Here you need to know that MyLibFunction() is defined in a script
"library/mylibscript.vim" in one of the directories in 'runtimepath'.
@@ -2726,11 +2690,12 @@ Here you need to know that MyLibFunction() is defined in a script
To make this a bit simpler Vim offers the autoload mechanism. Then the
example looks like this: >
- call mylib#myfunction(arg)
+ mylib#myfunction(arg)
-That's a lot simpler, isn't it? Vim will recognize the function name and when
-it's not defined search for the script "autoload/mylib.vim" in 'runtimepath'.
-That script must define the "mylib#myfunction()" function.
+That's a lot simpler, isn't it? Vim will recognize the function name by the
+embedded "#" character and when it's not defined search for the script
+"autoload/mylib.vim" in 'runtimepath'. That script must define the
+"mylib#myfunction()" function.
You can put many other functions in the mylib.vim script, you are free to
organize your functions in library scripts. But you must use function names
@@ -2740,7 +2705,7 @@ not know what script to load.
If you get really enthusiastic and write lots of library scripts, you may
want to use subdirectories. Example: >
- call netlib#ftp#read('somefile')
+ netlib#ftp#read('somefile')
For Unix the library script used for this could be:
@@ -2748,9 +2713,9 @@ For Unix the library script used for this could be:
Where the function is defined like this: >
- function netlib#ftp#read(fname)
- " Read the file fname through ftp
- endfunction
+ def netlib#ftp#read(fname: string)
+ # Read the file fname through ftp
+ enddef
Notice that the name the function is defined with is exactly the same as the
name used for calling the function. And the part before the last '#'
@@ -2758,12 +2723,12 @@ exactly matches the subdirectory and script name.
You can use the same mechanism for variables: >
- let weekdays = dutch#weekdays
+ var weekdays = dutch#weekdays
This will load the script "autoload/dutch.vim", which should contain something
like: >
- let dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
+ var dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
\ 'donderdag', 'vrijdag', 'zaterdag']
Further reading: |autoload|.
@@ -2774,9 +2739,13 @@ Further reading: |autoload|.
Vim users will look for scripts on the Vim website: http://www.vim.org.
If you made something that is useful for others, share it!
-Vim scripts can be used on any system. There might not be a tar or gzip
-command. If you want to pack files together and/or compress them the "zip"
-utility is recommended.
+Another place is github. But there you need to know where to find it! The
+advantage is that most plugin managers fetch plugins from github. You'll have
+to use your favorite search engine to find them.
+
+Vim scripts can be used on any system. However, there might not be a tar or
+gzip command. If you want to pack files together and/or compress them the
+"zip" utility is recommended.
For utmost portability use Vim itself to pack scripts together. This can be
done with the Vimball utility. See |vimball|.