From afce081b90c1e2c50c3507758c7558a0dfa1f33e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 15:18:03 +0200 Subject: Adding upstream version 2:8.2.2434. Signed-off-by: Daniel Baumann --- runtime/doc/usr_41.txt | 2761 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2761 insertions(+) create mode 100644 runtime/doc/usr_41.txt (limited to 'runtime/doc/usr_41.txt') diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt new file mode 100644 index 0000000..965a977 --- /dev/null +++ b/runtime/doc/usr_41.txt @@ -0,0 +1,2761 @@ +*usr_41.txt* For Vim version 8.2. Last change: 2021 Jan 13 + + 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. + + If you are familiar with Python, you can find a comparison between + Python and Vim script here, with pointers to other documents: + https://gist.github.com/yegappan/16d964a37ead0979b05e655aa036cad0 + And if you are familiar with JavaScript: + https://w0rp.com/blog/post/vim-script-for-the-javascripter/ + +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. +Note: this is how it works in legacy Vim script, which is what we discuss in +this file. In Vim9 script it's a bit different, see |usr_46.txt|. + +The example was given to explain the commands, but would you really want to +make such a loop, it can be written much more compact: > + + :for i in range(1, 4) + : echo "count is" i + :endfor + +We won't explain how |:for| and |range()| work until later. Follow the links +if you are impatient. + + +FOUR KINDS OF NUMBERS + +Numbers can be decimal, hexadecimal, octal or binary. A hexadecimal number +starts with "0x" or "0X". For example "0x1f" is decimal 31. An octal number +starts with a zero. "017" is decimal 15. A binary number starts with "0b" or +"0B". For example "0b101" is decimal 5. Careful: don't put a zero before a +decimal number, it will be interpreted as an octal number! + The ":echo" command always prints decimal numbers. Example: > + + :echo 0x7f 0o36 +< 127 30 ~ + +A number is made negative with a minus sign. This also works for hexadecimal, +octal and binary numbers. A minus sign is also used for subtraction. Compare +this with the previous example: > + + :echo 0x7f -0o36 +< 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 - 0o36 + +============================================================================== +*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 + \n , line break + \r , + \e + \b , backspace + \" " + \\ \, backslash + \ + \ CTRL-W + +The last two are just examples. The "\" 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 ".." (see |expr6|). 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 \" + +This inserts "new text " in the current line. Notice the use of the special +key "\". This avoids having to enter a real 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 number value + list2str() get a character string from a list of numbers + char2nr() get number value of a character + str2list() get list of numbers from a string + 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 + charclass() class of a character + match() position where a pattern matches in a string + matchend() position where a pattern match ends in a string + matchfuzzy() fuzzy matches a string in a list of strings + matchfuzzypos() fuzzy matches a string in a list of strings + 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 + setcellwidths() set character cell width overrides + 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 + slice() take a slice of a string, using char index in + Vim9 script + strgetchar() get character from a string using char index + expand() expand special keywords + expandcmd() expand a command like done for `:edit` + iconv() convert text from one encoding to another + byteidx() byte index of a character in a string + byteidxcomp() like byteidx() but count composing characters + charidx() character index of a byte in a string + repeat() repeat a string multiple times + eval() evaluate a string expression + execute() execute an Ex command and get the output + win_execute() like execute() but in a specified window + trim() trim characters from a string + gettext() lookup message translation + +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 + extendnew() make a new List and append items + 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 + mapnew() make a new List with changed items + reduce() reduce a List to a value + slice() take a slice of a List + 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 + flatten() flatten a List + +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 + extendnew() make a new Dictionary and append items + filter() remove selected entries from a Dictionary + map() change each Dictionary entry + mapnew() make a new Dictionary with changed items + 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 + isinf() check for infinity + 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 + rand() get a pseudo-random number + srand() initialize seed used by rand() + +Variables: *var-functions* + type() type of a variable as a number + typename() type of a variable as text + 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 + screenpos() screen row and col of a text character + getcurpos() get position of the cursor + getpos() get position of cursor, mark, etc. + setpos() set position of cursor, mark, etc. + getmarklist() list of global/local marks + 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 + screenchars() get character codes at a screen line/row + screenstring() get string of characters at a screen line/row + charcol() character number of the cursor or a mark + getcharpos() get character position of cursor, mark, etc. + setcharpos() set character position of cursor, mark, etc. + getcursorcharpos() get character position of the cursor + setcursorcharpos() set character position of the cursor + +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 + searchcount() get number of matches before/after the cursor + 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 + +Working with text in another buffer: + 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 + + *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| or |:tcd| + tempname() get the name of a temporary file + mkdir() create a new directory + chdir() change current working 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 + environ() get all environment variables + getenv() get one environment variable + setenv() set an environment variable + hostname() name of the system + readfile() read a file into a List of lines + readblob() read a file into a Blob + readdir() get a List of file names in a directory + readdirex() get a List of file information in a directory + 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 + strptime() convert a date/time string to time + 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 + bufadd() add a file to the list of buffers + bufexists() check if a buffer exists + buflisted() check if a buffer exists and is listed + bufload() ensure a buffer is loaded + 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 + listener_add() add a callback to listen to changes + listener_flush() invoke listener callbacks + listener_remove() remove a listener callback + win_findbuf() find windows containing a buffer + win_getid() get window ID of a window + win_gettype() get type of 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 + win_splitmove() move window to a split of another window + 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 + complete_info() get current completion information + pumvisible() check if the popup menu is displayed + pum_getpos() position and size of popup menu if visible + +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 + getmousepos() get last known mouse position + echoraw() output characters as-is + 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 + balloon_gettext() get the text in the 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 and Menus: *mapping-functions* + hasmapto() check if a mapping exists + mapcheck() check if a matching mapping exists + maparg() get rhs of a mapping + mapset() restore a mapping + menu_info() get information about a menu item + 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_garbagecollect_soon() set a flag to free memory soon + test_getvalue() get value of an internal variable + 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_function() return a null Funcref + 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_setmouse() set the mouse position + 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 + test_refcount() return an expression's reference count + test_srand_seed() set the seed value for srand() + test_unknown() return a value with unknown type + test_void() return a value with void type + +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() evaluate an expression over channel + ch_evalraw() evaluate 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_placelist() place a list of signs + sign_undefine() undefine a sign + sign_unplace() unplace a sign + sign_unplacelist() unplace a list of signs + +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 + term_setapi() set terminal JSON API function name prefix + +Popup window: *popup-window-functions* + popup_create() create popup centered in the screen + popup_atcursor() create popup just above the cursor position, + closes when the cursor moves away + popup_beval() at the position indicated by v:beval_ + variables, closes when the mouse moves away + popup_notification() show a notification for three seconds + popup_dialog() create popup centered with padding and border + popup_menu() prompt for selecting an item from a list + popup_hide() hide a popup temporarily + popup_show() show a previously hidden popup + popup_move() change the position and size of a popup + popup_setoptions() override options of a popup + popup_settext() replace the popup buffer contents + popup_close() close one popup + popup_clear() close all popups + popup_filter_menu() select from a list of items + popup_filter_yesno() block until 'y' or 'n' is pressed + popup_getoptions() get current options for a popup + popup_getpos() get actual position and size of a popup + popup_findinfo() get window ID for popup info window + popup_findpreview() get window ID for popup preview window + popup_list() get list of all popup window IDs + popup_locate() get popup window ID from its screen position + +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_getprompt() get the effective prompt text for a buffer + 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 + +Text Properties: *text-property-functions* + prop_add() attach a property at a position + prop_clear() remove all properties from a line or lines + prop_find() search for a property + prop_list() return a list of all properties in a line + prop_remove() remove a property from a line + prop_type_add() add/define a property type + prop_type_change() change properties of a type + prop_type_delete() remove a text property type + prop_type_get() return the properties of a type + prop_type_list() return a list of all property types + +Sound: *sound-functions* + sound_clear() stop playing all sounds + sound_playevent() play an event's sound + sound_playfile() play a sound file + sound_stop() stop playing a sound + +Various: *various-functions* + mode() get current editing mode + state() get current busy state + 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 + getimstatus() check if IME status is active + interrupt() interrupt script execution + windowsversion() get MS-Windows version + terminalprops() properties of the terminal + + 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 + getreginfo() get information about 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 + rubyeval() evaluate |Ruby| 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: > + + { : , ...} + +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 +character is used. For MS-Windows and the like, is used. This is +important when using mappings that end in a . 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 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 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 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 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 MS-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 + +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 +item can be used: > + + 22 map a TypecorrAdd; + +The "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 is used, this will cause an error message if the mapping +already happened to exist. |:map-| + +But what if the user wants to define his own key sequence? We can allow that +with this mechanism: > + + 21 if !hasmapto('TypecorrAdd;') + 22 map a TypecorrAdd; + 23 endif + +This checks if a mapping to "TypecorrAdd;" already exists, and only +defines the mapping from "a" if it doesn't. The user then has a +chance of putting this in his vimrc file: > + + map ,c 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. + + 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