12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639 |
- *usr_41.txt* Nvim
- 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.
- 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 "0o", "0O" or a zero and another digit. "0o17" is
- decimal 15.
- A binary number starts with "0b" or "0B". For example "0b101" is decimal 5.
- A decimal number is just digits. Careful: don't put a zero before a decimal
- number, it will be interpreted as an octal number!
- 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 has been processed to the end, the local variables declared
- there will not be deleted. Functions defined in the script can use them.
- 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 ".." (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 \<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 below: |function-list|.
- 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 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: |builtin-function-list|.
- Use CTRL-] on the function name to jump to detailed help on it.
- String manipulation: *string-functions*
- nr2char() get a character by its number value
- 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
- keytrans() translate internal keycodes to a form that
- can be used by |:map|
- 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
- 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
- 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
- reduce() reduce a List to a value
- 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
- 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
- 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
- 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
- virtcol2col() byte index of a text character on screen
- 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
- *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
- readdir() get a List of file names 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
- 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_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_move_separator() move window vertical separator
- win_move_statusline() move window status line
- 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*
- getcmdcompltype() get the type of the current command line
- completion
- getcmdline() get the current command line
- getcmdpos() get position of the cursor in the command line
- getcmdscreenpos() get screen position of the cursor in the
- command line
- setcmdline() set the current 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
- fullcommand() get full command name
- 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
- 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*
- digraph_get() get |digraph|
- digraph_getlist() get all |digraph|s
- digraph_set() register |digraph|
- digraph_setlist() register multiple |digraph|s
- 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
- 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
- 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_nobeep() assert that a command does not cause a beep
- assert_fails() assert that a command fails
- assert_report() report a test failure
- 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
- wait() wait for a condition
- 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
- Context Stack: *ctx-functions*
- ctxget() return context at given index from top
- ctxpop() pop and restore top context
- ctxpush() push given context
- ctxset() set context at given index from top
- ctxsize() return context stack size
- 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
- 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
- py3eval() evaluate |Python| expression
- pyeval() evaluate |Python| expression
- 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: >
- {<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 and execution is aborted.
- 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 Vim scripts it is
- recommended to always use the Unix fileformat. Lines are then separated with
- the Newline character. This also works on any other system. That way you can
- copy your Vim scripts from MS-Windows to Unix and they still work. See
- |:source_crnl|. To be sure it is set right, do this before writing the file:
- >
- :setlocal fileformat=unix
- When using "dos" fileformat, lines are separated with CR-NL, two characters.
- The CR character causes various problems, better avoid this.
- WHITE SPACE
- Blank lines are allowed in a script and ignored.
- Leading whitespace characters (blanks and TABs) are ignored, except when using
- |:let-heredoc| without "trim".
- Trailing whitespace is often ignored, but not always. One command that
- includes it is `map`. You have to watch out for that, it can cause hard to
- understand mistakes. A generic solution is to never use trailing white space,
- unless you really need it.
- 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 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 <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 their own plugin they want 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 they want
- 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 their 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 their 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 also maps <SID>Add, it will get another script ID and
- thus define another mapping.
- Note that instead of s:Add() we use <SID>Add() here. That is because the
- mapping is typed by the user, thus outside of the script. The <SID> is
- translated to the script ID, so that Vim knows in which script to look for
- 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".
- We add a semicolon as the terminator. 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 they defined themself 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
- "~/.config/nvim/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
- "~/.config/nvim/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) they want 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., ~/.config/nvim/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 ~/.config/nvim/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:
- ~/.config/nvim/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: https://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.
- ==============================================================================
- Next chapter: |usr_42.txt| Add new menus
- Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl:
|