summaryrefslogtreecommitdiffstats
path: root/runtime/doc/usr_41.txt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 02:44:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 02:44:24 +0000
commit8baab3c8d7a6f22888bd581cd5c6098fd2e4b5a8 (patch)
tree3537e168b860f2742f6029d70501b5ed7d15d345 /runtime/doc/usr_41.txt
parentInitial commit. (diff)
downloadvim-8baab3c8d7a6f22888bd581cd5c6098fd2e4b5a8.tar.xz
vim-8baab3c8d7a6f22888bd581cd5c6098fd2e4b5a8.zip
Adding upstream version 2:8.1.0875.upstream/2%8.1.0875upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'runtime/doc/usr_41.txt')
-rw-r--r--runtime/doc/usr_41.txt2632
1 files changed, 2632 insertions, 0 deletions
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
new file mode 100644
index 0000000..07d11f8
--- /dev/null
+++ b/runtime/doc/usr_41.txt
@@ -0,0 +1,2632 @@
+*usr_41.txt* For Vim version 8.1. Last change: 2019 Jan 29
+
+ VIM USER MANUAL - by Bram Moolenaar
+
+ Write 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.
+
+|41.1| Introduction
+|41.2| Variables
+|41.3| Expressions
+|41.4| Conditionals
+|41.5| Executing an expression
+|41.6| Using functions
+|41.7| Defining a function
+|41.8| Lists and Dictionaries
+|41.9| Exceptions
+|41.10| Various remarks
+|41.11| Writing a plugin
+|41.12| Writing a filetype plugin
+|41.13| Writing a compiler plugin
+|41.14| Writing a plugin that loads quickly
+|41.15| Writing library scripts
+|41.16| Distributing Vim scripts
+
+ Next chapter: |usr_42.txt| Add new menus
+ Previous chapter: |usr_40.txt| Make new commands
+Table of contents: |usr_toc.txt|
+
+==============================================================================
+*41.1* Introduction *vim-script-intro* *script*
+
+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
+<
+ 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 ~
+ 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.
+ 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"
+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.
+
+
+THREE KINDS OF NUMBERS
+
+Numbers can be decimal, hexadecimal or octal. 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. 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
+and octal 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.2* Variables
+
+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.
+ 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!
+
+
+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: >
+
+ :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.3* Expressions
+
+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.4* Conditionals
+
+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 !~ '\.$'
+ : 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-==|.
+
+
+MORE LOOPING
+
+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
+ loop continues.
+ :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
+
+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|.
+
+==============================================================================
+*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
+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
+
+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
+
+The ":execute" command can only execute colon commands. The ":normal" command
+executes Normal mode commands. However, its argument is not an expression but
+the literal command characters. Example: >
+
+ :normal gg=G
+
+This jumps to the first line and formats all lines with the "=" operator.
+ To make ":normal" work with an expression, combine ":execute" with it.
+Example: >
+
+ :execute "normal " . normal_commands
+
+The variable "normal_commands" must contain the Normal mode commands.
+ 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: >
+
+ :execute "normal Inew text \<Esc>"
+
+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.
+
+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)
+
+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|.
+
+A function is called with the ":call" command. The parameters are passed in
+between parentheses separated by commas. Example: >
+
+ :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.
+
+A function can be called in an expression. Example: >
+
+ :let line = getline(".")
+ :let repl = substitute(line, '\a', "*", "g")
+ :call 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
+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: >
+
+ :substitute/\a/*/g
+
+Using the functions becomes more interesting when you do more work before and
+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.
+
+String manipulation: *string-functions*
+ nr2char() get a character by its ASCII value
+ char2nr() get ASCII value of a character
+ str2nr() convert a string to a Number
+ str2float() convert a string to a Float
+ printf() format a string according to % items
+ escape() escape characters in a string with a '\'
+ shellescape() escape a string for use with a shell command
+ fnameescape() escape a file name for use with a Vim command
+ tr() translate characters from one set to another
+ strtrans() translate a string to make it printable
+ tolower() turn a string to lowercase
+ toupper() turn a string to uppercase
+ match() position where a pattern matches in a string
+ matchend() position where a pattern match ends in a string
+ matchstr() match of a pattern in a string
+ matchstrpos() match and positions of a pattern in a string
+ matchlist() like matchstr() and also return submatches
+ stridx() first index of a short string in a long string
+ strridx() last index of a short string in a long string
+ strlen() length of a string in bytes
+ strchars() length of a string in characters
+ strwidth() size of string when displayed
+ strdisplaywidth() size of string when displayed, deals with tabs
+ substitute() substitute a pattern match with a string
+ submatch() get a specific match in ":s" and substitute()
+ strpart() get part of a string using byte index
+ strcharpart() get part of a string using char index
+ strgetchar() get character from a string using char index
+ expand() expand special keywords
+ iconv() convert text from one encoding to another
+ byteidx() byte index of a character in a string
+ byteidxcomp() like byteidx() but count composing characters
+ repeat() repeat a string multiple times
+ eval() evaluate a string expression
+ execute() execute an Ex command and get the output
+ trim() trim characters from a string
+
+List manipulation: *list-functions*
+ get() get an item without error for wrong index
+ len() number of items in a List
+ empty() check if List is empty
+ insert() insert an item somewhere in a List
+ add() append an item to a List
+ extend() append a List to a List
+ remove() remove one or more items from a List
+ copy() make a shallow copy of a List
+ deepcopy() make a full copy of a List
+ filter() remove selected items from a List
+ map() change each List item
+ sort() sort a List
+ reverse() reverse the order of a List
+ uniq() remove copies of repeated adjacent items
+ split() split a String into a List
+ join() join List items into a String
+ range() return a List with a sequence of numbers
+ string() String representation of a List
+ call() call a function with List as arguments
+ index() index of a value in a List
+ max() maximum value in a List
+ min() minimum value in a List
+ count() count number of times a value appears in a List
+ repeat() repeat a List multiple times
+
+Dictionary manipulation: *dict-functions*
+ get() get an entry without an error for a wrong key
+ len() number of entries in a Dictionary
+ has_key() check whether a key appears in a Dictionary
+ empty() check if Dictionary is empty
+ remove() remove an entry from a Dictionary
+ extend() add entries from one Dictionary to another
+ filter() remove selected entries from a Dictionary
+ map() change each Dictionary entry
+ keys() get List of Dictionary keys
+ values() get List of Dictionary values
+ items() get List of Dictionary key-value pairs
+ copy() make a shallow copy of a Dictionary
+ deepcopy() make a full copy of a Dictionary
+ string() String representation of a Dictionary
+ max() maximum value in a Dictionary
+ min() minimum value in a Dictionary
+ count() count number of times a value appears
+
+Floating point computation: *float-functions*
+ float2nr() convert Float to Number
+ abs() absolute value (also works for Number)
+ round() round off
+ ceil() round up
+ floor() round down
+ trunc() remove value after decimal point
+ fmod() remainder of division
+ exp() exponential
+ log() natural logarithm (logarithm to base e)
+ log10() logarithm to base 10
+ pow() value of x to the exponent y
+ sqrt() square root
+ sin() sine
+ cos() cosine
+ tan() tangent
+ asin() arc sine
+ acos() arc cosine
+ atan() arc tangent
+ atan2() arc tangent
+ sinh() hyperbolic sine
+ cosh() hyperbolic cosine
+ tanh() hyperbolic tangent
+ isnan() check for not a number
+
+Other computation: *bitwise-function*
+ and() bitwise AND
+ invert() bitwise invert
+ or() bitwise OR
+ xor() bitwise XOR
+ sha256() SHA-256 hash
+
+Variables: *var-functions*
+ type() type of a variable
+ islocked() check if a variable is locked
+ funcref() get a Funcref for a function reference
+ function() get a Funcref for a function name
+ getbufvar() get a variable value from a specific buffer
+ setbufvar() set a variable in a specific buffer
+ getwinvar() get a variable from specific window
+ gettabvar() get a variable from specific tab page
+ gettabwinvar() get a variable from specific window & tab page
+ setwinvar() set a variable in a specific window
+ settabvar() set a variable in a specific tab page
+ settabwinvar() set a variable in a specific window & tab page
+ garbagecollect() possibly free memory
+
+Cursor and mark position: *cursor-functions* *mark-functions*
+ col() column number of the cursor or a mark
+ virtcol() screen column of the cursor or a mark
+ line() line number of the cursor or mark
+ wincol() window column number of the cursor
+ winline() window line number of the cursor
+ cursor() position the cursor at a line/column
+ screencol() get screen column of the cursor
+ screenrow() get screen row of the cursor
+ getcurpos() get position of the cursor
+ getpos() get position of cursor, mark, etc.
+ setpos() set position of cursor, mark, etc.
+ byte2line() get line number at a specific byte count
+ line2byte() byte count at a specific line
+ diff_filler() get the number of filler lines above a line
+ screenattr() get attribute at a screen line/row
+ screenchar() get character code at a screen line/row
+
+Working with text in the current buffer: *text-functions*
+ getline() get a line or list of lines from the buffer
+ setline() replace a line in the buffer
+ append() append line or list of lines in the buffer
+ indent() indent of a specific line
+ cindent() indent according to C indenting
+ lispindent() indent according to Lisp indenting
+ nextnonblank() find next non-blank line
+ prevnonblank() find previous non-blank line
+ search() find a match for a pattern
+ searchpos() find a match for a pattern
+ searchpair() find the other end of a start/skip/end
+ searchpairpos() find the other end of a start/skip/end
+ searchdecl() search for the declaration of a name
+ getcharsearch() return character search information
+ setcharsearch() set character search information
+
+ *system-functions* *file-functions*
+System functions and manipulation of files:
+ glob() expand wildcards
+ globpath() expand wildcards in a number of directories
+ glob2regpat() convert a glob pattern into a search pattern
+ findfile() find a file in a list of directories
+ finddir() find a directory in a list of directories
+ resolve() find out where a shortcut points to
+ fnamemodify() modify a file name
+ pathshorten() shorten directory names in a path
+ simplify() simplify a path without changing its meaning
+ executable() check if an executable program exists
+ exepath() full path of an executable program
+ filereadable() check if a file can be read
+ filewritable() check if a file can be written to
+ getfperm() get the permissions of a file
+ setfperm() set the permissions of a file
+ getftype() get the kind of a file
+ isdirectory() check if a directory exists
+ getfsize() get the size of a file
+ getcwd() get the current working directory
+ haslocaldir() check if current window used |:lcd|
+ tempname() get the name of a temporary file
+ mkdir() create a new directory
+ delete() delete a file
+ rename() rename a file
+ system() get the result of a shell command as a string
+ systemlist() get the result of a shell command as a list
+ hostname() name of the system
+ readfile() read a file into a List of lines
+ writefile() write a List of lines or Blob into a file
+
+Date and Time: *date-functions* *time-functions*
+ getftime() get last modification time of a file
+ localtime() get current time in seconds
+ strftime() convert time to a string
+ reltime() get the current or elapsed time accurately
+ reltimestr() convert reltime() result to a string
+ reltimefloat() convert reltime() result to a Float
+
+ *buffer-functions* *window-functions* *arg-functions*
+Buffers, windows and the argument list:
+ argc() number of entries in the argument list
+ argidx() current position in the argument list
+ arglistid() get id of the argument list
+ argv() get one entry from the argument list
+ bufexists() check if a buffer exists
+ buflisted() check if a buffer exists and is listed
+ bufloaded() check if a buffer exists and is loaded
+ bufname() get the name of a specific buffer
+ bufnr() get the buffer number of a specific buffer
+ tabpagebuflist() return List of buffers in a tab page
+ tabpagenr() get the number of a tab page
+ tabpagewinnr() like winnr() for a specified tab page
+ winnr() get the window number for the current window
+ bufwinid() get the window ID of a specific buffer
+ bufwinnr() get the window number of a specific buffer
+ winbufnr() get the buffer number of a specific window
+ getbufline() get a list of lines from the specified buffer
+ setbufline() replace a line in the specified buffer
+ appendbufline() append a list of lines in the specified buffer
+ deletebufline() delete lines from a specified buffer
+ win_findbuf() find windows containing a buffer
+ win_getid() get window ID of a window
+ win_gotoid() go to window with ID
+ win_id2tabwin() get tab and window nr from window ID
+ win_id2win() get window nr from window ID
+ getbufinfo() get a list with buffer information
+ gettabinfo() get a list with tab page information
+ getwininfo() get a list with window information
+ getchangelist() get a list of change list entries
+ getjumplist() get a list of jump list entries
+ swapinfo() information about a swap file
+ swapname() get the swap file path of a buffer
+
+Command line: *command-line-functions*
+ getcmdline() get the current command line
+ getcmdpos() get position of the cursor in the command line
+ setcmdpos() set position of the cursor in the command line
+ getcmdtype() return the current command-line type
+ getcmdwintype() return the current command-line window type
+ getcompletion() list of command-line completion matches
+
+Quickfix and location lists: *quickfix-functions*
+ getqflist() list of quickfix errors
+ setqflist() modify a quickfix list
+ getloclist() list of location list items
+ setloclist() modify a location list
+
+Insert mode completion: *completion-functions*
+ complete() set found matches
+ complete_add() add to found matches
+ complete_check() check if completion should be aborted
+ pumvisible() check if the popup menu is displayed
+
+Folding: *folding-functions*
+ foldclosed() check for a closed fold at a specific line
+ foldclosedend() like foldclosed() but return the last line
+ foldlevel() check for the fold level at a specific line
+ foldtext() generate the line displayed for a closed fold
+ foldtextresult() get the text displayed for a closed fold
+
+Syntax and highlighting: *syntax-functions* *highlighting-functions*
+ clearmatches() clear all matches defined by |matchadd()| and
+ the |:match| commands
+ getmatches() get all matches defined by |matchadd()| and
+ the |:match| commands
+ hlexists() check if a highlight group exists
+ hlID() get ID of a highlight group
+ synID() get syntax ID at a specific position
+ synIDattr() get a specific attribute of a syntax ID
+ synIDtrans() get translated syntax ID
+ synstack() get list of syntax IDs at a specific position
+ synconcealed() get info about concealing
+ diff_hlID() get highlight ID for diff mode at a position
+ matchadd() define a pattern to highlight (a "match")
+ matchaddpos() define a list of positions to highlight
+ matcharg() get info about |:match| arguments
+ matchdelete() delete a match defined by |matchadd()| or a
+ |:match| command
+ setmatches() restore a list of matches saved by
+ |getmatches()|
+
+Spelling: *spell-functions*
+ spellbadword() locate badly spelled word at or after cursor
+ spellsuggest() return suggested spelling corrections
+ soundfold() return the sound-a-like equivalent of a word
+
+History: *history-functions*
+ histadd() add an item to a history
+ histdel() delete an item from a history
+ histget() get an item from a history
+ histnr() get highest index of a history list
+
+Interactive: *interactive-functions*
+ browse() put up a file requester
+ browsedir() put up a directory requester
+ confirm() let the user make a choice
+ getchar() get a character from the user
+ getcharmod() get modifiers for the last typed character
+ feedkeys() put characters in the typeahead queue
+ input() get a line from the user
+ inputlist() let the user pick an entry from a list
+ inputsecret() get a line from the user without showing it
+ inputdialog() get a line from the user in a dialog
+ inputsave() save and clear typeahead
+ inputrestore() restore typeahead
+
+GUI: *gui-functions*
+ getfontname() get name of current font being used
+ getwinpos() position of the Vim window
+ getwinposx() X position of the Vim window
+ getwinposy() Y position of the Vim window
+ balloon_show() set the balloon content
+ balloon_split() split a message for a balloon
+
+Vim server: *server-functions*
+ serverlist() return the list of server names
+ remote_startserver() run a server
+ remote_send() send command characters to a Vim server
+ remote_expr() evaluate an expression in a Vim server
+ server2client() send a reply to a client of a Vim server
+ remote_peek() check if there is a reply from a Vim server
+ remote_read() read a reply from a Vim server
+ foreground() move the Vim window to the foreground
+ remote_foreground() move the Vim server window to the foreground
+
+Window size and position: *window-size-functions*
+ winheight() get height of a specific window
+ winwidth() get width of a specific window
+ win_screenpos() get screen position of a window
+ winlayout() get layout of windows in a tab page
+ winrestcmd() return command to restore window sizes
+ winsaveview() get view of current window
+ winrestview() restore saved view of current window
+
+Mappings: *mapping-functions*
+ hasmapto() check if a mapping exists
+ mapcheck() check if a matching mapping exists
+ maparg() get rhs of a mapping
+ wildmenumode() check if the wildmode is active
+
+Testing: *test-functions*
+ assert_equal() assert that two expressions values are equal
+ assert_equalfile() assert that two file contents are equal
+ assert_notequal() assert that two expressions values are not equal
+ assert_inrange() assert that an expression is inside a range
+ assert_match() assert that a pattern matches the value
+ assert_notmatch() assert that a pattern does not match the value
+ assert_false() assert that an expression is false
+ assert_true() assert that an expression is true
+ assert_exception() assert that a command throws an exception
+ assert_beeps() assert that a command beeps
+ assert_fails() assert that a command fails
+ assert_report() report a test failure
+ test_alloc_fail() make memory allocation fail
+ test_autochdir() enable 'autochdir' during startup
+ test_override() test with Vim internal overrides
+ test_garbagecollect_now() free memory right now
+ test_ignore_error() ignore a specific error message
+ test_null_blob() return a null Blob
+ test_null_channel() return a null Channel
+ test_null_dict() return a null Dict
+ test_null_job() return a null Job
+ test_null_list() return a null List
+ test_null_partial() return a null Partial function
+ test_null_string() return a null String
+ test_settime() set the time Vim uses internally
+ test_feedinput() add key sequence to input buffer
+ test_option_not_set() reset flag indicating option was set
+ test_scrollbar() simulate scrollbar movement in the GUI
+
+Inter-process communication: *channel-functions*
+ ch_canread() check if there is something to read
+ ch_open() open a channel
+ ch_close() close a channel
+ ch_close_in() close the in part of a channel
+ ch_read() read a message from a channel
+ ch_readblob() read a Blob from a channel
+ ch_readraw() read a raw message from a channel
+ ch_sendexpr() send a JSON message over a channel
+ ch_sendraw() send a raw message over a channel
+ ch_evalexpr() evaluates an expression over channel
+ ch_evalraw() evaluates a raw string over channel
+ ch_status() get status of a channel
+ ch_getbufnr() get the buffer number of a channel
+ ch_getjob() get the job associated with a channel
+ ch_info() get channel information
+ ch_log() write a message in the channel log file
+ ch_logfile() set the channel log file
+ ch_setoptions() set the options for a channel
+ json_encode() encode an expression to a JSON string
+ json_decode() decode a JSON string to Vim types
+ js_encode() encode an expression to a JSON string
+ js_decode() decode a JSON string to Vim types
+
+Jobs: *job-functions*
+ job_start() start a job
+ job_stop() stop a job
+ job_status() get the status of a job
+ job_getchannel() get the channel used by a job
+ job_info() get information about a job
+ job_setoptions() set options for a job
+
+Signs: *sign-functions*
+ sign_define() define or update a sign
+ sign_getdefined() get a list of defined signs
+ sign_getplaced() get a list of placed signs
+ sign_jump() jump to a sign
+ sign_place() place a sign
+ sign_undefine() undefine a sign
+ sign_unplace() unplace a sign
+
+Terminal window: *terminal-functions*
+ term_start() open a terminal window and run a job
+ term_list() get the list of terminal buffers
+ term_sendkeys() send keystrokes to a terminal
+ term_wait() wait for screen to be updated
+ term_getjob() get the job associated with a terminal
+ term_scrape() get row of a terminal screen
+ term_getline() get a line of text from a terminal
+ term_getattr() get the value of attribute {what}
+ term_getcursor() get the cursor position of a terminal
+ term_getscrolled() get the scroll count of a terminal
+ term_getaltscreen() get the alternate screen flag
+ term_getsize() get the size of a terminal
+ term_getstatus() get the status of a terminal
+ term_gettitle() get the title of a terminal
+ term_gettty() get the tty name of a terminal
+ term_setansicolors() set 16 ANSI colors, used for GUI
+ term_getansicolors() get 16 ANSI colors, used for GUI
+ term_dumpdiff() display difference between two screen dumps
+ term_dumpload() load a terminal screen dump in a window
+ term_dumpwrite() dump contents of a terminal screen to a file
+ term_setkill() set signal to stop job in a terminal
+ term_setrestore() set command to restore a terminal
+ term_setsize() set the size of a terminal
+
+Timers: *timer-functions*
+ timer_start() create a timer
+ timer_pause() pause or unpause a timer
+ timer_stop() stop a timer
+ timer_stopall() stop all timers
+ timer_info() get information about timers
+
+Tags: *tag-functions*
+ taglist() get list of matching tags
+ tagfiles() get a list of tags files
+ gettagstack() get the tag stack of a window
+ settagstack() modify the tag stack of a window
+
+Prompt Buffer: *promptbuffer-functions*
+ prompt_setcallback() set prompt callback for a buffer
+ prompt_setinterrupt() set interrupt callback for a buffer
+ prompt_setprompt() set the prompt text for a buffer
+
+Various: *various-functions*
+ mode() get current editing mode
+ visualmode() last visual mode used
+ exists() check if a variable, function, etc. exists
+ has() check if a feature is supported in Vim
+ changenr() return number of most recent change
+ cscope_connection() check if a cscope connection exists
+ did_filetype() check if a FileType autocommand was used
+ eventhandler() check if invoked by an event handler
+ getpid() get process ID of Vim
+
+ libcall() call a function in an external library
+ libcallnr() idem, returning a number
+
+ undofile() get the name of the undo file
+ undotree() return the state of the undo tree
+
+ getreg() get contents of a register
+ getregtype() get type of a register
+ setreg() set contents and type of a register
+ reg_executing() return the name of the register being executed
+ reg_recording() return the name of the register being recorded
+
+ shiftwidth() effective value of 'shiftwidth'
+
+ wordcount() get byte/word/char count of buffer
+
+ luaeval() evaluate Lua expression
+ mzeval() evaluate |MzScheme| expression
+ perleval() evaluate Perl expression (|+perl|)
+ py3eval() evaluate Python expression (|+python3|)
+ pyeval() evaluate Python expression (|+python|)
+ pyxeval() evaluate |python_x| expression
+ debugbreak() interrupt a program being debugged
+
+==============================================================================
+*41.7* Defining a function
+
+Vim enables you to define your own functions. The basic function declaration
+begins as follows: >
+
+ :function {name}({var1}, {var2}, ...)
+ : {body}
+ :endfunction
+<
+ Note:
+ Function names must begin with a capital letter.
+
+Let's define a short function to return the smaller of two numbers. It starts
+with this line: >
+
+ :function Min(num1, num2)
+
+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:
+ >
+ : if a:num1 < a: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
+
+The variable "smaller" is a local variable. Variables used inside a function
+are local unless prefixed by something like "g:", "a:", 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.
+
+You now use the ":return" statement to return the smallest number to the user.
+Finally, you end the function: >
+
+ : return smaller
+ :endfunction
+
+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
+
+For people who like short functions, this does the same thing: >
+
+ :function Min(num1, num2)
+ : if a:num1 < a:num2
+ : return a:num1
+ : endif
+ : return a:num2
+ :endfunction
+
+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)
+
+Only now will the function be executed and the lines be interpreted 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.
+
+When a function reaches ":endfunction" or ":return" is used without an
+argument, the function returns zero.
+
+To redefine a function that already exists, use the ! for the ":function"
+command: >
+
+ :function! Min(num1, num2, num3)
+
+
+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: >
+
+ :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()
+
+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: >
+
+ :function Number()
+ : echo "line " . line(".") . " contains: " . getline(".")
+ :endfunction
+
+If you call this function with: >
+
+ :10,15call Number()
+
+The function will be called six times.
+
+
+VARIABLE NUMBER OF ARGUMENTS
+
+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, ...)
+
+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: >
+
+ :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
+
+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 also use the a:000 variable, it is a List of all the "..." arguments.
+See |a:000|.
+
+
+LISTING FUNCTIONS
+
+The ":function" command lists the names and arguments of all user-defined
+functions: >
+
+ :function
+< function Show(start, ...) ~
+ function GetVimIndent() ~
+ function SetSyn(name) ~
+
+To see what a function does, use its name as an argument for ":function": >
+
+ :function SetSyn
+< 1 if &syntax == '' ~
+ 2 let &syntax = a:name ~
+ 3 endif ~
+ endfunction ~
+
+
+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
+calls. Set it to 15 or higher to see every executed line.
+
+
+DELETING A FUNCTION
+
+To delete the Show() function: >
+
+ :delfunction Show
+
+You get an error when the function doesn't exist.
+
+
+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, [])
+< Wrong! ~
+
+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.
+
+==============================================================================
+*41.8* Lists and Dictionaries
+
+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,
+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']
+
+The List items are enclosed in square brackets and separated by commas. To
+create an empty List: >
+
+ :let alist = []
+
+You can add items to a List with the add() function: >
+
+ :let alist = []
+ :call add(alist, 'foo')
+ :call add(alist, 'bar')
+ :echo alist
+< ['foo', 'bar'] ~
+
+List concatenation is done with +: >
+
+ :echo alist + ['foo', 'bar']
+< ['foo', 'bar', 'foo', 'bar'] ~
+
+Or, if you want to extend a List directly: >
+
+ :let alist = ['one']
+ :call extend(alist, ['two', 'three'])
+ :echo alist
+< ['one', 'two', 'three'] ~
+
+Notice that using add() will have a different effect: >
+
+ :let alist = ['one']
+ :call add(alist, ['two', 'three'])
+ :echo alist
+< ['one', ['two', 'three']] ~
+
+The second argument of add() is added as a single item.
+
+
+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
+< one ~
+ two ~
+ three ~
+
+This will loop over each element in List "alist", assigning the value to
+variable "n". The generic form of a for loop is: >
+
+ :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
+< 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
+< 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
+
+This looks into lines 1 to 20 (inclusive) and echoes any date found in there.
+
+
+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'}
+
+Now you can lookup words by putting the key in square brackets: >
+
+ :echo uk2nl['two']
+< twee ~
+
+The generic form for defining a Dictionary is: >
+
+ {<key> : <value>, ...}
+
+An empty Dictionary is one without any keys: >
+
+ {}
+
+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
+< three ~
+ one ~
+ two ~
+
+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
+< one ~
+ three ~
+ two ~
+
+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|.
+
+==============================================================================
+*41.9* Exceptions
+
+Let's start with an example: >
+
+ :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
+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
+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
+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
+
+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".
+
+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
+
+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
+always executed. This makes sure you don't leave the temporary file behind.
+
+More information about exception handling can be found in the reference
+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.
+
+The end-of-line character depends on the system. For Unix a single <NL>
+character is used. For MS-DOS, Windows, OS/2 and the like, <CR><LF> is used.
+This is important when using mappings that end in a <CR>. See |:source_crnl|.
+
+
+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
+
+the whitespace immediately before the "=" sign is ignored. But there can be
+no whitespace after the "=" sign!
+
+To include a whitespace character in the value of an option, it must be
+escaped by a "\" (backslash) as in the following example: >
+
+ :set tags=my\ nice\ file
+
+The same example written as: >
+
+ :set tags=my nice file
+
+will issue an error, because it is interpreted as: >
+
+ :set tags=my
+ :set nice
+ :set file
+
+
+COMMENTS
+
+The character " (the double quote mark) 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.
+
+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
+
+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: >
+
+ :abbrev dev development|" shorthand
+ :map <F3> o#include|" insert include
+ :execute cmd |" 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
+
+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
+
+To spot these problems, you can set the 'list' option when editing vimrc
+files.
+
+For Unix there is one special way to comment a line, that allows making a Vim
+script executable: >
+ #!/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: >
+
+ :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
+not visible.
+
+And this is the same as what happens when one uses a comment after an 'unmap'
+command: >
+
+ :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
+
+
+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: >
+
+ map ,p ma"aYHmbgg"aP`bzt`a
+
+What this does: >
+ ma"aYHmbgg"aP`bzt`a
+< ma set mark a at cursor position
+ "aY yank current line into register a
+ Hmb go to top line in window and set mark b there
+ gg go to first line in file
+ "aP put the yanked line above it
+ `b go back to top line in display
+ zt position the text in the window as before
+ `a go back to saved cursor position
+
+
+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
+
+ function XXX_one(a)
+ ... body of function ...
+ endfun
+
+ function XXX_two(b)
+ ... body of function ...
+ endfun
+
+ let XXX_loaded = 1
+
+==============================================================================
+*41.11* Writing a plugin *write-plugin*
+
+You can write a Vim script in such a way that many people can use it. This is
+called a plugin. Vim users can drop your script in their plugin directory and
+use its features right away |add-plugin|.
+
+There are actually two types of plugins:
+
+ global plugins: For all types of files.
+filetype plugins: Only for files of a specific type.
+
+In this section the first type is explained. Most items are also relevant for
+writing filetype plugins. The specifics for filetype plugins are in the next
+section |write-filetype-plugin|.
+
+
+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 Windows systems.
+
+A script that corrects typing mistakes could be called "typecorr.vim". We
+will use it here as an example.
+
+For the plugin to work for everybody, it should follow a few guidelines. This
+will be explained step-by-step. The complete example plugin is at the end.
+
+
+BODY
+
+Let's start with the body of the plugin, the lines that do the actual work: >
+
+ 14 iabbrev teh the
+ 15 iabbrev otehr other
+ 16 iabbrev wnat want
+ 17 iabbrev synchronisation
+ 18 \ synchronization
+ 19 let s:count = 4
+
+The actual list should be much longer, of course.
+
+The line numbers have only been added to explain a few things, don't put them
+in your plugin file!
+
+
+HEADER
+
+You will probably add new corrections to the plugin and soon have several
+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>
+
+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.
+
+
+LINE CONTINUATION, 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
+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
+ 12 set cpo&vim
+ ..
+ 42 let &cpo = s:save_cpo
+ 43 unlet s:save_cpo
+
+We first store the old value of 'cpoptions' in the s: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
+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
+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: >
+
+ 6 if exists("g:loaded_typecorr")
+ 7 finish
+ 8 endif
+ 9 let g:loaded_typecorr = 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.
+
+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).
+
+Using "finish" stops Vim from reading the rest of the file, it's much quicker
+than using if-endif around the whole file.
+
+
+MAPPING
+
+Now let's make the plugin more interesting: We will add a mapping that adds a
+correction for the word under the cursor. We could just pick a key sequence
+for this mapping, but the user might already use it for something else. To
+allow the user to define which keys a mapping in a plugin uses, the <Leader>
+item can be used: >
+
+ 22 map <unique> <Leader>a <Plug>TypecorrAdd
+
+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: >
+
+ let 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.
+
+Note that <unique> is used, this will cause an error message if the mapping
+already happened to exist. |:map-<unique>|
+
+But what if the user wants to define his own key sequence? We can allow that
+with this mechanism: >
+
+ 21 if !hasmapto('<Plug>TypecorrAdd')
+ 22 map <unique> <Leader>a <Plug>TypecorrAdd
+ 23 endif
+
+This checks if a mapping to "<Plug>TypecorrAdd" already exists, and only
+defines the mapping from "<Leader>a" if it doesn't. The user then has a
+chance of putting this in his vimrc file: >
+
+ map ,c <Plug>TypecorrAdd
+
+Then the mapped key sequence will be ",c" instead of "_a" or "\a".
+
+
+PIECES
+
+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:".
+
+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
+ ..
+ 36 endfunction
+
+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.
+
+<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>
+
+Thus when a user types "\a", this sequence is invoked: >
+
+ \a -> <Plug>TypecorrAdd -> <SID>Add -> :call <SID>Add()
+
+If another script would also map <SID>Add, it would 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
+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).
+
+We can also add a menu entry to do the same as the mapping: >
+
+ 26 noremenu <script> Plugin.Add\ Correction <SID>Add
+
+The "Plugin" menu is recommended for adding menu items for plugins. In this
+case only one item is used. When adding more items, creating a submenu is
+recommended. For example, "Plugin.CVS" could be used for a plugin that offers
+CVS operations "Plugin.CVS.checkin", "Plugin.CVS.checkout", etc.
+
+Note that in line 28 ":noremap" is used to avoid that any other mappings cause
+trouble. Someone may have remapped ":call", for example. In line 24 we also
+use ":noremap", but we do want "<SID>Add" to be remapped. This is why
+"<script>" is used here. This only allows mappings which are local to the
+script. |:map-<script>| The same is done in line 26 for ":noremenu".
+|:menu-<script>|
+
+
+<SID> AND <Plug> *using-<Plug>*
+
+Both <SID> and <Plug> are used to avoid that mappings of typed keys interfere
+with mappings that are only to be used from other mappings. Note the
+difference between using <SID> and <Plug>:
+
+<Plug> is visible outside of the script. It is used for mappings which the
+ user might want to map a key sequence to. <Plug> is a special code
+ that a typed key will never produce.
+ To make it very unlikely that other plugins use the same sequence of
+ characters, use this structure: <Plug> scriptname mapname
+ In our example the scriptname is "Typecorr" and the mapname is "Add".
+ This results in "<Plug>TypecorrAdd". Only the first character of
+ scriptname and mapname is uppercase, so that we can see where mapname
+ starts.
+
+<SID> is the script ID, a unique identifier for a script.
+ Internally Vim translates <SID> to "<SNR>123_", where "123" can be any
+ number. Thus a function "<SID>Add()" will have a name "<SNR>11_Add()"
+ in one script, and "<SNR>22_Add()" in another. You can see this if
+ you use the ":function" command to get a list of functions. The
+ translation of <SID> in mappings is exactly the same, that's how you
+ can call a script-local function from a mapping.
+
+
+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)
+ 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|
+
+
+SCRIPT VARIABLES
+
+When a variable starts with "s:" it is a script variable. It can only be used
+inside a script. Outside the script it's not visible. This avoids trouble
+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: >
+
+ 19 let s:count = 4
+ ..
+ 30 function s:Add(from, correct)
+ ..
+ 34 let s:count = s:count + 1
+ 35 echo s:count . " corrections now"
+ 36 endfunction
+
+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
+where the function was called, since it has been defined in the script, it
+will use the local variables from this script.
+
+
+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
+ 12 set cpo&vim
+ 13
+ 14 iabbrev teh the
+ 15 iabbrev otehr other
+ 16 iabbrev wnat want
+ 17 iabbrev synchronisation
+ 18 \ synchronization
+ 19 let s:count = 4
+ 20
+ 21 if !hasmapto('<Plug>TypecorrAdd')
+ 22 map <unique> <Leader>a <Plug>TypecorrAdd
+ 23 endif
+ 24 noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
+ 25
+ 26 noremenu <script> Plugin.Add\ Correction <SID>Add
+ 27
+ 28 noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<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
+ 37
+ 38 if !exists(":Correct")
+ 39 command -nargs=1 Correct :call s:Add(<q-args>, 0)
+ 40 endif
+ 41
+ 42 let &cpo = s:save_cpo
+ 43 unlet s: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*
+
+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": >
+
+ 1 *typecorr.txt* Plugin for correcting typing mistakes
+ 2
+ 3 If you make typing mistakes, this plugin will have them corrected
+ 4 automatically.
+ 5
+ 6 There are currently only a few corrections. Add your own if you like.
+ 7
+ 8 Mappings:
+ 9 <Leader>a or <Plug>TypecorrAdd
+ 10 Add a correction for the word under the cursor.
+ 11
+ 12 Commands:
+ 13 :Correct {word}
+ 14 Add a correction for {word}.
+ 15
+ 16 *typecorr-settings*
+ 17 This plugin doesn't have any settings.
+
+The first line is actually the only one for which the format matters. It will
+be extracted from the help file to be put in the "LOCAL ADDITIONS:" section of
+help.txt |local-additions|. The first "*" must be in the first column of the
+first line. After adding your help file do ":help" and check that the entries
+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.
+
+Using references to other parts of the help in || is recommended. This makes
+it easy for the user to find associated help.
+
+
+FILETYPE DETECTION *plugin-filetype*
+
+If your filetype is not already detected by Vim, you should create a filetype
+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
+
+Write this single-line file as "ftdetect/foofoo.vim" in the first directory
+that appears in 'runtimepath'. For Unix that would be
+"~/.vim/ftdetect/foofoo.vim". The convention is to use the name of the
+filetype for the script name.
+
+You can make more complicated checks if you like, for example to inspect the
+contents of the file to recognize the language. Also see |new-filetype|.
+
+
+SUMMARY *plugin-special*
+
+Summary of special things to use in a plugin:
+
+s:name Variables local to the script.
+
+<SID> Script-ID, used for mappings and functions local to
+ the script.
+
+hasmapto() Function to test if the user already defined a mapping
+ for functionality the script offers.
+
+<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.
+
+:noremap <script> Use only mappings local to the script, not global
+ mappings.
+
+exists(":Cmd") Check if a user command already exists.
+
+==============================================================================
+*41.12* Writing a filetype plugin *write-filetype-plugin* *ftplugin*
+
+A filetype plugin is like a global plugin, except that it sets options and
+defines mappings for the current buffer only. See |add-filetype-plugin| for
+how this type of plugin is used.
+
+First read the section on global plugins above |41.11|. All that is said there
+also applies to filetype plugins. There are a few extras, which are explained
+here. The essential thing is that a filetype plugin should only have an
+effect on the current buffer.
+
+
+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
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ let 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: >
+
+ let b:did_ftplugin = 1
+
+This does require that the filetype plugin directory comes before $VIMRUNTIME
+in 'runtimepath'!
+
+If you do want to use the default plugin, but overrule one of the settings,
+you can write the different setting in a script: >
+
+ setlocal textwidth=70
+
+Now write this in the "after" directory, so that it gets sourced after the
+distributed "vim.vim" ftplugin |after-directory|. For Unix this would be
+"~/.vim/after/ftplugin/vim.vim". Note that the default plugin will have set
+"b:did_ftplugin", but it is ignored here.
+
+
+OPTIONS
+
+To make sure the filetype plugin only affects the current buffer use the >
+
+ :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
+options or options local to a window, the value will change for many buffers,
+and that is not what a filetype plugin should do.
+
+When an option has a value that is a list of flags or items, consider using
+"+=" and "-=" to keep the existing value. Be aware that the user may have
+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
+
+
+MAPPINGS
+
+To make sure mappings will only work in the current buffer use the >
+
+ :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: >
+
+ if !hasmapto('<Plug>JavaImport')
+ map <buffer> <unique> <LocalLeader>i <Plug>JavaImport
+ endif
+ noremap <buffer> <unique> <Plug>JavaImport oimport ""<Left><Esc>
+
+|hasmapto()| is used to check if the user has already defined a map to
+<Plug>JavaImport. If not, then the filetype plugin defines the default
+mapping. This starts with |<LocalLeader>|, which allows the user to select
+the key(s) he wants filetype plugin mappings to start with. The default is a
+backslash.
+"<unique>" is used to give an error message if the mapping already exists or
+overlaps with an existing mapping.
+|:noremap| is used to avoid that any other mappings that the user has defined
+interferes. You might want to use ":noremap <script>" to allow remapping
+mappings defined in this script that start with <SID>.
+
+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 "> "
+ if !hasmapto('<Plug>MailQuote')
+ vmap <buffer> <LocalLeader>q <Plug>MailQuote
+ nmap <buffer> <LocalLeader>q <Plug>MailQuote
+ endif
+ vnoremap <buffer> <Plug>MailQuote :s/^/> /<CR>
+ nnoremap <buffer> <Plug>MailQuote :.,$s/^/> /<CR>
+ endif
+
+Two global variables are used:
+|no_plugin_maps| disables mappings for all filetype plugins
+|no_mail_maps| disables mappings for the "mail" filetype
+
+
+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
+
+
+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.
+
+
+FUNCTIONS
+
+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
+<
+
+UNDO *undo_indent* *undo_ftplugin*
+
+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<"
+ \ . "| unlet b:match_ignorecase b:match_words b:match_skip"
+
+Using ":setlocal" with "<" after the option name resets the option to its
+global value. That is mostly the best way to reset the option value.
+
+This does require removing the "C" flag from 'cpoptions' to allow line
+continuation, as mentioned above |use-cpo-save|.
+
+For undoing the effect of an indent script, the b:undo_indent variable should
+be set accordingly.
+
+
+FILE NAME
+
+The filetype must be included in the file name |ftplugin-name|. Use one of
+these three forms:
+
+ .../ftplugin/stuff.vim
+ .../ftplugin/stuff_foo.vim
+ .../ftplugin/stuff/bar.vim
+
+"stuff" is the filetype, "foo" and "bar" are arbitrary names.
+
+
+SUMMARY *ftplugin-special*
+
+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.
+
+:noremap <script> Only remap mappings defined in this script that start
+ with <SID>.
+
+:setlocal Set an option for the current buffer only.
+
+:command -buffer Define a user command local to the buffer.
+
+exists("*s:Func") Check if a function was already defined.
+
+Also see |plugin-special|, the special things used for all plugins.
+
+==============================================================================
+*41.13* Writing a compiler plugin *write-compiler-plugin*
+
+A compiler plugin sets options for use with a specific compiler. The user can
+load it with the |:compiler| command. The main use is to set the
+'errorformat' and 'makeprg' options.
+
+Easiest is to have a look at examples. This command will edit all the default
+compiler plugins: >
+
+ :next $VIMRUNTIME/compiler/*.vim
+
+Use |: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"
+
+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
+make the default file skip the settings.
+ *:CompilerSet*
+The second mechanism is to use ":set" for ":compiler!" and ":setlocal" for
+":compiler". Vim defines the ":CompilerSet" user command for this. However,
+older Vim versions don't, thus your plugin should define it then. This is an
+example: >
+
+ if exists(":CompilerSet") != 2
+ command -nargs=* CompilerSet setlocal <args>
+ endif
+ CompilerSet errorformat& " use the default 'errorformat'
+ CompilerSet makeprg=nmake
+
+When you write a compiler plugin for the Vim distribution or for a system-wide
+runtime directory, use the mechanism mentioned above. When
+"current_compiler" was already set by a user plugin nothing will be done.
+
+When you write a compiler plugin to overrule settings from a default plugin,
+don't check "current_compiler". This plugin is supposed to be loaded
+last, thus it should be in a directory at the end of 'runtimepath'. For Unix
+that could be ~/.vim/after/compiler.
+
+==============================================================================
+*41.14* Writing a plugin that loads quickly *write-plugin-quickload*
+
+A plugin may grow and become quite long. The startup delay may become
+noticeable, while you hardly ever use the plugin. Then it's time for a
+quickload plugin.
+
+The basic idea is that the plugin is loaded twice. The first time user
+commands and mappings are defined that offer the functionality. The second
+time the functions that implement the functionality are defined.
+
+It may sound surprising that quickload means loading a script twice. What we
+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|.
+
+The following example shows how it's done: >
+
+ " Vim global plugin for demonstrating quick loading
+ " Last Change: 2005 Feb 25
+ " Maintainer: Bram Moolenaar <Bram@vim.org>
+ " License: This file is placed in the public domain.
+
+ if !exists("s:did_load")
+ command -nargs=* BNRead call BufNetRead(<f-args>)
+ map <F19> :call BufNetWrite('something')<CR>
+
+ let s:did_load = 1
+ exe 'au FuncUndefined BufNet* source ' . expand('<sfile>')
+ finish
+ endif
+
+ function BufNetRead(...)
+ echo 'BufNetRead(' . string(a:000) . ')'
+ " read functionality here
+ endfunction
+
+ function BufNetWrite(...)
+ echo 'BufNetWrite(' . string(a:000) . ')'
+ " write functionality here
+ endfunction
+
+When the script is first loaded "s:did_load" is not set. The commands between
+the "if" and "endif" will be executed. This ends in a |:finish| command, thus
+the rest of the script is not executed.
+
+The second time the script is loaded "s:did_load" exists and the commands
+after the "endif" are executed. This defines the (possible long)
+BufNetRead() and BufNetWrite() functions.
+
+If you drop this script in your plugin directory Vim will execute it on
+startup. This is the sequence of events that happens:
+
+1. The "BNRead" command is defined and the <F19> key is mapped when the script
+ is sourced at startup. A |FuncUndefined| autocommand is defined. The
+ ":finish" command causes the script to terminate early.
+
+2. The user types the BNRead command or presses the <F19> key. The
+ BufNetRead() or BufNetWrite() function will be called.
+
+3. Vim can't find the function and triggers the |FuncUndefined| autocommand
+ event. Since the pattern "BufNet*" matches the invoked function, the
+ command "source fname" will be executed. "fname" will be equal to the name
+ of the script, no matter where it is located, because it comes from
+ expanding "<sfile>" (see |expand()|).
+
+4. The script is sourced again, the "s:did_load" variable exists and the
+ functions are defined.
+
+Notice that the functions that are loaded afterwards match the pattern in the
+|FuncUndefined| autocommand. You must make sure that no other plugin defines
+functions that match this pattern.
+
+==============================================================================
+*41.15* Writing library scripts *write-library-script*
+
+Some functionality will be required in several places. When this becomes more
+than a few lines you will want to put it in one script and use it from many
+scripts. We will call that one script a library script.
+
+Manually loading a library script is possible, so long as you avoid loading it
+when it's already done. You can do this with the |exists()| function.
+Example: >
+
+ if !exists('*MyLibFunction')
+ runtime library/mylibscript.vim
+ endif
+ call MyLibFunction(arg)
+
+Here you need to know that MyLibFunction() is defined in a script
+"library/mylibscript.vim" in one of the directories in 'runtimepath'.
+
+To make this a bit simpler Vim offers the autoload mechanism. Then the
+example looks like this: >
+
+ call 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.
+
+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
+where the part before the '#' matches the script name. Otherwise Vim would
+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')
+
+For Unix the library script used for this could be:
+
+ ~/.vim/autoload/netlib/ftp.vim
+
+Where the function is defined like this: >
+
+ function netlib#ftp#read(fname)
+ " Read the file fname through ftp
+ endfunction
+
+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 '#'
+exactly matches the subdirectory and script name.
+
+You can use the same mechanism for variables: >
+
+ let weekdays = dutch#weekdays
+
+This will load the script "autoload/dutch.vim", which should contain something
+like: >
+
+ let dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
+ \ 'donderdag', 'vrijdag', 'zaterdag']
+
+Further reading: |autoload|.
+
+==============================================================================
+*41.16* Distributing Vim scripts *distribute-script*
+
+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.
+
+For utmost portability use Vim itself to pack scripts together. This can be
+done with the Vimball utility. See |vimball|.
+
+It's good if you add a line to allow automatic updating. See |glvs-plugins|.
+
+==============================================================================
+
+Next chapter: |usr_42.txt| Add new menus
+
+Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl: