| 
									
										
										
										
											2022-03-19 15:18:53 +00:00
										 |  |  | *vim9.txt*	For Vim version 8.2.  Last change: 2022 Mar 18 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		  VIM REFERENCE MANUAL	  by Bram Moolenaar | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | Vim9 script commands and expressions.			*Vim9* *vim9* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Most expression help is in |eval.txt|.  This file is about the new syntax and | 
					
						
							|  |  |  | features in Vim9 script. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-02 16:39:53 +01:00
										 |  |  | 1.  What is Vim9 script?		|Vim9-script| | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 2.  Differences				|vim9-differences| | 
					
						
							|  |  |  | 3.  New style functions			|fast-functions| | 
					
						
							|  |  |  | 4.  Types				|vim9-types| | 
					
						
							|  |  |  | 5.  Namespace, Import and Export	|vim9script| | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | 6.  Future work: classes		|vim9-classes| | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 9.  Rationale				|vim9-rationale| | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 1. What is Vim9 script?					*Vim9-script* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | Vim script has been growing over time, while preserving backwards | 
					
						
							|  |  |  | compatibility.  That means bad choices from the past often can't be changed | 
					
						
							| 
									
										
										
										
											2020-06-21 22:12:03 +02:00
										 |  |  | and compatibility with Vi restricts possible solutions.  Execution is quite | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | slow, each line is parsed every time it is executed. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | The main goal of Vim9 script is to drastically improve performance.  This is | 
					
						
							|  |  |  | accomplished by compiling commands into instructions that can be efficiently | 
					
						
							|  |  |  | executed.  An increase in execution speed of 10 to 100 times can be expected. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A secondary goal is to avoid Vim-specific constructs and get closer to | 
					
						
							|  |  |  | commonly used programming languages, such as JavaScript, TypeScript and Java. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | The performance improvements can only be achieved by not being 100% backwards | 
					
						
							| 
									
										
										
										
											2020-05-26 21:20:45 +02:00
										 |  |  | compatible.  For example, making function arguments available in the | 
					
						
							|  |  |  | "a:" dictionary adds quite a lot of overhead.  In a Vim9 function this | 
					
						
							|  |  |  | dictionary is not available.  Other differences are more subtle, such as how | 
					
						
							|  |  |  | errors are handled. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | The Vim9 script syntax and semantics are used in: | 
					
						
							|  |  |  | - a function defined with the `:def` command | 
					
						
							|  |  |  | - a script file where the first command is `vim9script` | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | - an autocommand defined in the context of the above | 
					
						
							| 
									
										
										
										
											2021-02-14 12:57:36 +01:00
										 |  |  | - a command prefixed with the `vim9cmd` command modifier | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | When using `:function` in a Vim9 script file the legacy syntax is used, with | 
					
						
							|  |  |  | the highest |scriptversion|.  However, this can be confusing and is therefore | 
					
						
							|  |  |  | discouraged. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | Vim9 script and legacy Vim script can be mixed.  There is no requirement to | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | rewrite old scripts, they keep working as before.  You may want to use a few | 
					
						
							|  |  |  | `:def` functions for code that needs to be fast. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | :vim9[cmd] {cmd}				*:vim9* *:vim9cmd* *E1164* | 
					
						
							| 
									
										
										
										
											2022-02-11 20:33:48 +00:00
										 |  |  | 		Evaluate and execute {cmd} using Vim9 script syntax and | 
					
						
							|  |  |  | 		semantics.  Useful when typing a command and in a legacy | 
					
						
							|  |  |  | 		script or function. | 
					
						
							| 
									
										
										
										
											2021-02-14 12:57:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | :leg[acy] {cmd}					*:leg* *:legacy* *E1189* *E1234* | 
					
						
							| 
									
										
										
										
											2022-02-11 20:33:48 +00:00
										 |  |  | 		Evaluate and execute {cmd} using legacy script syntax and | 
					
						
							|  |  |  | 		semantics.  Only useful in a Vim9 script or a :def function. | 
					
						
							| 
									
										
										
										
											2021-04-24 14:15:41 +02:00
										 |  |  | 		Note that {cmd} cannot use local variables, since it is parsed | 
					
						
							|  |  |  | 		with legacy expression syntax. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2. Differences from legacy Vim script			*vim9-differences* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | Overview ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 							*E1146* | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | Brief summary of the differences you will most often encounter when using Vim9 | 
					
						
							|  |  |  | script and `:def` functions; details are below: | 
					
						
							|  |  |  | - Comments start with #, not ": > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	echo "hello"   # comment | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | - Using a backslash for line continuation is hardly ever needed: > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	echo "hello " | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | 	     .. yourName | 
					
						
							|  |  |  | 	     .. ", how are you?" | 
					
						
							| 
									
										
										
										
											2021-12-27 15:39:57 +00:00
										 |  |  | - White space is required in many places to improve readability. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | - Assign values without `:let` *E1126* , declare variables with `:var`: > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	var count = 0 | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | 	count += 3 | 
					
						
							|  |  |  | - Constants can be declared with `:final` and `:const`: > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	final matches = []		  # add matches | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | 	const names = ['Betty', 'Peter']  # cannot be changed | 
					
						
							|  |  |  | - `:final` cannot be used as an abbreviation of `:finally`. | 
					
						
							|  |  |  | - Variables and functions are script-local by default. | 
					
						
							|  |  |  | - Functions are declared with argument types and return type: > | 
					
						
							|  |  |  | 	def CallMe(count: number, message: string): bool | 
					
						
							|  |  |  | - Call functions without `:call`: > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	writefile(['done'], 'file.txt') | 
					
						
							| 
									
										
										
										
											2022-03-08 13:18:55 +00:00
										 |  |  | - You cannot use old Ex commands: | 
					
						
							|  |  |  | 	`:Print` | 
					
						
							|  |  |  | 	`:append` | 
					
						
							|  |  |  | 	`:change` | 
					
						
							|  |  |  | 	`:d`  directly followed by 'd' or 'p'. | 
					
						
							|  |  |  | 	`:insert` | 
					
						
							|  |  |  | 	`:k` | 
					
						
							|  |  |  | 	`:mode` | 
					
						
							|  |  |  | 	`:open` | 
					
						
							|  |  |  | 	`:s`  with only flags | 
					
						
							|  |  |  | 	`:t` | 
					
						
							|  |  |  |   	`:xit` | 
					
						
							|  |  |  | - Some commands, especially those used for flow control, cannot be shortened. | 
					
						
							|  |  |  |   E.g., `:throw` cannot be written as `:th`. *E839* | 
					
						
							| 
									
										
										
										
											2021-10-16 15:23:36 +01:00
										 |  |  | - You cannot use curly-braces names. | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | - A range before a command must be prefixed with a colon: > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	:%s/this/that | 
					
						
							| 
									
										
										
										
											2021-08-29 21:55:35 +02:00
										 |  |  | - Executing a register with "@r" does not work, you can prepend a colon or use | 
					
						
							|  |  |  |   `:exe`: > | 
					
						
							|  |  |  |   	:exe @a | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | - Unless mentioned specifically, the highest |scriptversion| is used. | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | - When defining an expression mapping, the expression will be evaluated in the | 
					
						
							|  |  |  |   context of the script where it was defined. | 
					
						
							| 
									
										
										
										
											2020-09-28 21:48:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 14:41:35 +02:00
										 |  |  | Comments starting with # ~ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 20:36:00 +02:00
										 |  |  | In legacy Vim script comments start with double quote.  In Vim9 script | 
					
						
							|  |  |  | comments start with #. > | 
					
						
							|  |  |  | 	# declarations | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var count = 0  # number of occurrences | 
					
						
							| 
									
										
										
										
											2020-04-13 14:41:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 20:36:00 +02:00
										 |  |  | The reason is that a double quote can also be the start of a string. In many | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | places, especially halfway through an expression with a line break, it's hard | 
					
						
							|  |  |  | to tell what the meaning is, since both a string and a comment can be followed | 
					
						
							|  |  |  | by arbitrary text.  To avoid confusion only # comments are recognized.  This | 
					
						
							|  |  |  | is the same as in shell scripts and Python programs. | 
					
						
							| 
									
										
										
										
											2020-07-17 20:36:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | In Vi # is a command to list text with numbers.  In Vim9 script you can use | 
					
						
							|  |  |  | `:number` for that. > | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | 	:101 number | 
					
						
							| 
									
										
										
										
											2020-07-17 20:36:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | To improve readability there must be a space between a command and the # | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | that starts a comment: > | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | 	var name = value # comment | 
					
						
							|  |  |  | 	var name = value# error! | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | <							*E1170* | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | Do not start a comment with #{, it looks like the legacy dictionary literal | 
					
						
							|  |  |  | and produces an error where this might be confusing.  #{{ or #{{{ are OK, | 
					
						
							|  |  |  | these can be used to start a fold. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | In legacy Vim script # is also used for the alternate file name.  In Vim9 | 
					
						
							|  |  |  | script you need to use %% instead.  Instead of ## use %%% (stands for all | 
					
						
							|  |  |  | arguments). | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 14:41:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Vim9 functions ~ | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1099* | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | A function defined with `:def` is compiled.  Execution is many times faster, | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | often 10 to 100 times. | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 21:20:45 +02:00
										 |  |  | Many errors are already found when compiling, before the function is executed. | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | The syntax is strict, to enforce code that is easy to read and understand. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | Compilation is done when any of these is encountered: | 
					
						
							| 
									
										
										
										
											2020-12-10 21:11:27 +01:00
										 |  |  | - the first time the function is called | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | - when the `:defcompile` command is encountered in the script after the | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  |   function was defined | 
					
						
							|  |  |  | - `:disassemble` is used for the function. | 
					
						
							|  |  |  | - a function that is compiled calls the function or uses it as a function | 
					
						
							| 
									
										
										
										
											2021-08-29 21:55:35 +02:00
										 |  |  |   reference (so that the argument and return types can be checked) | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 						*E1091* *E1191* | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | If compilation fails it is not tried again on the next call, instead this | 
					
						
							|  |  |  | error is given: "E1091: Function is not compiled: {name}". | 
					
						
							| 
									
										
										
										
											2021-05-02 17:19:11 +02:00
										 |  |  | Compilation will fail when encountering a user command that has not been | 
					
						
							|  |  |  | created yet.  In this case you can call `execute()` to invoke it at runtime. > | 
					
						
							|  |  |  | 	def MyFunc() | 
					
						
							|  |  |  | 	  execute('DefinedLater') | 
					
						
							|  |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2020-05-26 21:20:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | `:def` has no options like `:function` does: "range", "abort", "dict" or | 
					
						
							| 
									
										
										
										
											2020-12-10 21:11:27 +01:00
										 |  |  | "closure".  A `:def` function always aborts on an error (unless `:silent!` was | 
					
						
							| 
									
										
										
										
											2021-12-24 13:18:38 +00:00
										 |  |  | used for the command or the error was caught a `:try` block), does not get a | 
					
						
							|  |  |  | range passed cannot be a "dict" function, and can always be a closure. | 
					
						
							| 
									
										
										
										
											2021-08-29 21:55:35 +02:00
										 |  |  | 						*vim9-no-dict-function* | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | Later classes will be added, which replaces the "dict function" mechanism. | 
					
						
							|  |  |  | For now you will need to pass the dictionary explicitly: > | 
					
						
							|  |  |  | 	def DictFunc(d: dict<any>, arg: string) | 
					
						
							|  |  |  | 	   echo d[arg] | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	var d = {item: 'value', func: DictFunc} | 
					
						
							|  |  |  | 	d.func(d, 'item') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 20:09:51 +02:00
										 |  |  | You can call a legacy dict function though: > | 
					
						
							|  |  |  | 	func Legacy() dict | 
					
						
							|  |  |  | 	  echo self.value | 
					
						
							|  |  |  | 	endfunc | 
					
						
							|  |  |  | 	def CallLegacy() | 
					
						
							|  |  |  | 	  var d = {func: Legacy, value: 'text'} | 
					
						
							|  |  |  | 	  d.func() | 
					
						
							|  |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | <						*E1096* *E1174* *E1175* | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | The argument types and return type need to be specified.  The "any" type can | 
					
						
							|  |  |  | be used, type checking will then be done at runtime, like with legacy | 
					
						
							|  |  |  | functions. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1106* | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | Arguments are accessed by name, without "a:", just like any other language. | 
					
						
							|  |  |  | There is no "a:" dictionary or "a:000" list. | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 			*vim9-variable-arguments* *E1055* *E1160* *E1180* | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | Variable arguments are defined as the last argument, with a name and have a | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | list type, similar to TypeScript.  For example, a list of numbers: > | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	def MyFunc(...itemlist: list<number>) | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	   for item in itemlist | 
					
						
							|  |  |  | 	     ... | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | When a function argument is optional (it has a default value) passing `v:none` | 
					
						
							|  |  |  | as the argument results in using the default value.  This is useful when you | 
					
						
							|  |  |  | want to specify a value for an argument that comes after an argument that | 
					
						
							|  |  |  | should use its default value.  Example: > | 
					
						
							| 
									
										
										
										
											2021-10-16 15:23:36 +01:00
										 |  |  | 	def MyFunc(one = 'one', last = 'last') | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | 	  ... | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	MyFunc(v:none, 'LAST')  # first argument uses default value 'one' | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | < | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 					*vim9-ignored-argument* *E1181* | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | The argument "_" (an underscore) can be used to ignore the argument.  This is | 
					
						
							|  |  |  | most useful in callbacks where you don't need it, but do need to give an | 
					
						
							|  |  |  | argument to match the call.  E.g. when using map() two arguments are passed, | 
					
						
							|  |  |  | the key and the value, to ignore the key: > | 
					
						
							|  |  |  | 	map(myList, (_, v) => v * 2) | 
					
						
							|  |  |  | There is no error for using the "_" argument multiple times.  No type needs to | 
					
						
							|  |  |  | be given. | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | Functions and variables are script-local by default ~ | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 							*vim9-scopes* | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | When using `:function` or `:def` to specify a new function at the script level | 
					
						
							| 
									
										
										
										
											2022-02-11 13:29:40 +00:00
										 |  |  | in a Vim9 script, the function is local to the script.  Like prefixing "s:" in | 
					
						
							|  |  |  | legacy script.  To define a global function or variable the "g:" prefix must | 
					
						
							|  |  |  | be used.  For functions in a script that is to be imported and in an autoload | 
					
						
							|  |  |  | script "export" needs to be used. > | 
					
						
							| 
									
										
										
										
											2020-07-29 22:11:05 +02:00
										 |  |  | 	def ThisFunction()          # script-local | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	def g:ThatFunction()        # global | 
					
						
							| 
									
										
										
										
											2022-02-09 21:50:44 +00:00
										 |  |  | 	export def Function()       # for import and import autoload | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | <						*E1058* *E1075* | 
					
						
							| 
									
										
										
										
											2020-10-03 22:52:39 +02:00
										 |  |  | When using `:function` or `:def` to specify a nested function inside a `:def` | 
					
						
							| 
									
										
										
										
											2021-12-05 21:54:04 +00:00
										 |  |  | function and no namespace was given, this nested function is local to the code | 
					
						
							| 
									
										
										
										
											2022-02-26 12:25:45 +00:00
										 |  |  | block it is defined in.  It cannot be used in `function()` with a string | 
					
						
							|  |  |  | argument, pass the function reference itself: > | 
					
						
							|  |  |  | 	def Outer() | 
					
						
							|  |  |  | 	  def Inner() | 
					
						
							|  |  |  | 	    echo 'inner' | 
					
						
							|  |  |  | 	  enddef | 
					
						
							|  |  |  | 	  var Fok = function(Inner)     # OK | 
					
						
							|  |  |  | 	  var Fbad = function('Inner')  # does not work | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | It is not possible to define a script-local function.  It is possible to | 
					
						
							|  |  |  | define a global function by using the "g:" prefix. | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | When referring to a function and no "s:" or "g:" prefix is used, Vim will | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | search for the function: | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | - in the function scope, in block scopes | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | - in the script scope, possibly imported | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | Since a script-local function reference can be used without "s:" the name must | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | start with an upper case letter even when using the "s:" prefix.  In legacy | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | script "s:funcref" could be used, because it could not be referred to with | 
					
						
							|  |  |  | "funcref".  In Vim9 script it can, therefore "s:Funcref" must be used to avoid | 
					
						
							|  |  |  | that the name interferes with builtin functions. | 
					
						
							| 
									
										
										
										
											2022-02-11 13:29:40 +00:00
										 |  |  | 							*vim9-s-namespace* | 
					
						
							|  |  |  | The use of the "s:" prefix is not supported at the Vim9 script level.  All | 
					
						
							|  |  |  | functions and variables without a prefix are script-local. | 
					
						
							| 
									
										
										
										
											2022-02-22 20:43:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | In :def functions the use of "s:" depends on the script: Script-local | 
					
						
							|  |  |  | variables and functions in a legacy script do use "s:", while in a Vim9 script | 
					
						
							|  |  |  | they do not use "s:".  This matches what you see in the rest of the file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-11 13:29:40 +00:00
										 |  |  | In legacy functions the use of "s:" for script items is required, as before. | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | In all cases the function must be defined before used.  That is when it is | 
					
						
							| 
									
										
										
										
											2020-10-26 21:12:46 +01:00
										 |  |  | called, when `:defcompile` causes it to be compiled, or when code that calls | 
					
						
							|  |  |  | it is being compiled (to figure out the return type). | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 19:54:59 +02:00
										 |  |  | The result is that functions and variables without a namespace can usually be | 
					
						
							| 
									
										
										
										
											2020-05-01 16:07:38 +02:00
										 |  |  | found in the script, either defined there or imported.  Global functions and | 
					
						
							| 
									
										
										
										
											2020-08-07 19:54:59 +02:00
										 |  |  | variables could be defined anywhere (good luck finding out where!). | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1102* | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | Global functions can still be defined and deleted at nearly any time.  In | 
					
						
							| 
									
										
										
										
											2020-05-07 18:56:00 +02:00
										 |  |  | Vim9 script script-local functions are defined once when the script is sourced | 
					
						
							| 
									
										
										
										
											2020-05-26 21:20:45 +02:00
										 |  |  | and cannot be deleted or replaced. | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | When compiling a function and a function call is encountered for a function | 
					
						
							|  |  |  | that is not (yet) defined, the |FuncUndefined| autocommand is not triggered. | 
					
						
							|  |  |  | You can use an autoload function if needed, or call a legacy function and have | 
					
						
							|  |  |  | |FuncUndefined| triggered there. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | Reloading a Vim9 script clears functions and variables by default ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 						*vim9-reload* *E1149* *E1150* | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | When loading a legacy Vim script a second time nothing is removed, the | 
					
						
							|  |  |  | commands will replace existing variables and functions and create new ones. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When loading a Vim9 script a second time all existing script-local functions | 
					
						
							|  |  |  | and variables are deleted, thus you start with a clean slate.  This is useful | 
					
						
							|  |  |  | if you are developing a plugin and want to try a new version.  If you renamed | 
					
						
							|  |  |  | something you don't have to worry about the old name still hanging around. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you do want to keep items, use: > | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | 	vim9script noclear | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | You want to use this in scripts that use a `finish` command to bail out at | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | some point when loaded again.  E.g. when a buffer local option is set to a | 
					
						
							|  |  |  | function, the function does not need to be defined more than once: > | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | 	vim9script noclear | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 	setlocal completefunc=SomeFunc | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | 	if exists('*SomeFunc') | 
					
						
							| 
									
										
										
										
											2022-02-09 21:50:44 +00:00
										 |  |  | 	  finish | 
					
						
							|  |  |  | 	endif | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | 	def SomeFunc() | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 	.... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Variable declarations with :var, :final and :const ~ | 
					
						
							| 
									
										
										
										
											2022-03-08 13:18:55 +00:00
										 |  |  | 				*vim9-declaration* *:var* *E1079* | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 				*E1017* *E1020* *E1054* *E1087* *E1108* *E1124* | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Local variables need to be declared with `:var`.  Local constants need to be | 
					
						
							|  |  |  | declared with `:final` or `:const`.  We refer to both as "variables" in this | 
					
						
							|  |  |  | section. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Variables can be local to a script, function or code block: > | 
					
						
							|  |  |  | 	vim9script | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var script_var = 123 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	def SomeFunc() | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	  var func_var = script_var | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	  if cond | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	    var block_var = func_var | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	  ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The variables are only visible in the block where they are defined and nested | 
					
						
							|  |  |  | blocks.  Once the block ends the variable is no longer accessible: > | 
					
						
							|  |  |  | 	if cond | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	   var inner = 5 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	   var inner = 0 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	endif | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	echo inner  # Error! | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | The declaration must be done earlier: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var inner: number | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	if cond | 
					
						
							|  |  |  | 	   inner = 5 | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	   inner = 0 | 
					
						
							|  |  |  | 	endif | 
					
						
							|  |  |  | 	echo inner | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | <							*E1025* *E1128* | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | To intentionally hide a variable from code that follows, a block can be | 
					
						
							|  |  |  | used: > | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	   var temp = 'temp' | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	   ... | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	echo temp  # Error! | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | This is especially useful in a user command: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command -range Rename { | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  | 		 var save = @a | 
					
						
							|  |  |  | 		 @a = 'some expression' | 
					
						
							|  |  |  | 		 echo 'do something with ' .. @a | 
					
						
							|  |  |  | 		 @a = save | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | And with autocommands: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    au BufWritePre *.go { | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  | 		 var save = winsaveview() | 
					
						
							|  |  |  | 		 silent! exe ':%! some formatting command' | 
					
						
							|  |  |  | 		 winrestview(save) | 
					
						
							|  |  |  | 	   } | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Although using a :def function probably works better. | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 				*E1022* *E1103* *E1130* *E1131* *E1133* | 
					
						
							|  |  |  | 				*E1134* *E1235* | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | Declaring a variable with a type but without an initializer will initialize to | 
					
						
							| 
									
										
										
										
											2021-12-26 18:09:31 +00:00
										 |  |  | false (for bool), empty (for string, list, dict, etc.) or zero (for number, | 
					
						
							|  |  |  | any, etc.).  This matters especially when using the "any" type, the value will | 
					
						
							|  |  |  | default to the number zero. | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 						*E1016* *E1052* *E1066* | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | In Vim9 script `:let` cannot be used.  An existing variable is assigned to | 
					
						
							|  |  |  | without any command.  The same for global, window, tab, buffer and Vim | 
					
						
							| 
									
										
										
										
											2021-12-27 15:39:57 +00:00
										 |  |  | variables, because they are not really declared.  Those can also be deleted | 
					
						
							| 
									
										
										
										
											2020-08-01 17:00:03 +02:00
										 |  |  | with `:unlet`. | 
					
						
							| 
									
										
										
										
											2022-03-08 13:18:55 +00:00
										 |  |  | 							*E1065* | 
					
						
							|  |  |  | You cannot use `:va` to declare a variable, it must be written with the full | 
					
						
							|  |  |  | name `:var`.  Just to make sure it is easy to read. | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 							*E1178* | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | `:lockvar` does not work on local variables.  Use `:const` and `:final` | 
					
						
							|  |  |  | instead. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  | The `exists()` and `exists_compiled()` functions do not work on local variables | 
					
						
							|  |  |  | or arguments. | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 				*E1006* *E1041* *E1167* *E1168* *E1213* | 
					
						
							| 
									
										
										
										
											2021-02-27 16:38:07 +01:00
										 |  |  | Variables, functions and function arguments cannot shadow previously defined | 
					
						
							|  |  |  | or imported variables and functions in the same script file. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Variables may shadow Ex commands, rename the variable if needed. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | Global variables must be prefixed with "g:", also at the script level. > | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 	vim9script | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var script_local = 'text' | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | 	g:global = 'value' | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var Funcref = g:ThatFunction | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-31 15:40:56 +00:00
										 |  |  | Global functions must be prefixed with "g:": > | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | 	vim9script | 
					
						
							|  |  |  | 	def g:GlobalFunc(): string | 
					
						
							|  |  |  | 	  return 'text' | 
					
						
							|  |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2022-01-31 15:40:56 +00:00
										 |  |  | 	echo g:GlobalFunc() | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | The "g:" prefix is not needed for auto-load functions. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  | 					*vim9-function-defined-later* | 
					
						
							|  |  |  | Although global functions can be called without the "g:" prefix, they must | 
					
						
							|  |  |  | exist when compiled.  By adding the "g:" prefix the function can be defined | 
					
						
							|  |  |  | later.  Example: > | 
					
						
							|  |  |  | 	def CallPluginFunc() | 
					
						
							|  |  |  | 	  if exists('g:loaded_plugin') | 
					
						
							|  |  |  | 	    g:PluginFunc() | 
					
						
							|  |  |  | 	  endif | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-01 12:17:00 +00:00
										 |  |  | If you do it like this, you get an error at compile time that "PluginFunc" | 
					
						
							|  |  |  | does not exist, even when "g:loaded_plugin" does not exist: > | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  | 	def CallPluginFunc() | 
					
						
							|  |  |  | 	  if exists('g:loaded_plugin') | 
					
						
							|  |  |  | 	    PluginFunc()   # Error - function not found | 
					
						
							|  |  |  | 	  endif | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You can use exists_compiled() to avoid the error, but then the function would | 
					
						
							|  |  |  | not be called, even when "g:loaded_plugin" is defined later: > | 
					
						
							|  |  |  | 	def CallPluginFunc() | 
					
						
							|  |  |  | 	  if exists_compiled('g:loaded_plugin') | 
					
						
							|  |  |  | 	    PluginFunc()   # Function may never be called | 
					
						
							|  |  |  | 	  endif | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Since `&opt = value` is now assigning a value to option "opt", ":&" cannot be | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | used to repeat a `:substitute` command. | 
					
						
							| 
									
										
										
										
											2021-04-17 16:31:09 +02:00
										 |  |  | 							*vim9-unpack-ignore* | 
					
						
							| 
									
										
										
										
											2021-04-10 22:35:43 +02:00
										 |  |  | For an unpack assignment the underscore can be used to ignore a list item, | 
					
						
							|  |  |  | similar to how a function argument can be ignored: > | 
					
						
							|  |  |  | 	[a, _, c] = theList | 
					
						
							| 
									
										
										
										
											2021-04-17 16:31:09 +02:00
										 |  |  | To ignore any remaining items: > | 
					
						
							| 
									
										
										
										
											2021-04-10 22:35:43 +02:00
										 |  |  | 	[a, b; _] = longList | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | <							*E1163* *E1080* | 
					
						
							| 
									
										
										
										
											2021-04-10 22:35:43 +02:00
										 |  |  | Declaring more than one variable at a time, using the unpack notation, is | 
					
						
							| 
									
										
										
										
											2021-11-30 16:14:49 +00:00
										 |  |  | possible.  Each variable can have a type or infer it from the value: > | 
					
						
							|  |  |  | 	var [v1: number, v2] = GetValues() | 
					
						
							|  |  |  | Use this only when there is a list with values, declaring one variable per | 
					
						
							|  |  |  | line is much easier to read and change later. | 
					
						
							| 
									
										
										
										
											2021-04-10 22:35:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Constants ~ | 
					
						
							|  |  |  | 						*vim9-const* *vim9-final* | 
					
						
							|  |  |  | How constants work varies between languages.  Some consider a variable that | 
					
						
							|  |  |  | can't be assigned another value a constant.  JavaScript is an example.  Others | 
					
						
							|  |  |  | also make the value immutable, thus when a constant uses a list, the list | 
					
						
							|  |  |  | cannot be changed.  In Vim9 we can use both. | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 							*E1021* | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | `:const` is used for making both the variable and the value a constant.  Use | 
					
						
							|  |  |  | this for composite structures that you want to make sure will not be modified. | 
					
						
							|  |  |  | Example: > | 
					
						
							|  |  |  | 	const myList = [1, 2] | 
					
						
							|  |  |  | 	myList = [3, 4]		# Error! | 
					
						
							|  |  |  | 	myList[0] = 9		# Error! | 
					
						
							| 
									
										
										
										
											2021-02-27 16:38:07 +01:00
										 |  |  | 	myList->add(3)		# Error! | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | <							*:final* *E1125* | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | `:final` is used for making only the variable a constant, the value can be | 
					
						
							|  |  |  | changed.  This is well known from Java.  Example: > | 
					
						
							|  |  |  | 	final myList = [1, 2] | 
					
						
							|  |  |  | 	myList = [3, 4]		# Error! | 
					
						
							|  |  |  | 	myList[0] = 9		# OK | 
					
						
							| 
									
										
										
										
											2021-02-27 16:38:07 +01:00
										 |  |  | 	myList->add(3)		# OK | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | It is common to write constants as ALL_CAPS, but you don't have to. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The constant only applies to the value itself, not what it refers to. > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	final females = ["Mary"] | 
					
						
							|  |  |  | 	const NAMES = [["John", "Peter"], females] | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | 	NAMES[0] = ["Jack"]     # Error! | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	NAMES[0][0] = "Jack"    # Error! | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | 	NAMES[1] = ["Emma"]     # Error! | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	NAMES[1][0] = "Emma"    # OK, now females[0] == "Emma" | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Omitting :call and :eval ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 							*E1190* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Functions can be called without `:call`: > | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	writefile(lines, 'file') | 
					
						
							| 
									
										
										
										
											2020-02-04 22:53:05 +01:00
										 |  |  | Using `:call` is still possible, but this is discouraged. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | A method call without `eval` is possible, so long as the start is an | 
					
						
							| 
									
										
										
										
											2021-03-14 18:40:19 +01:00
										 |  |  | identifier or can't be an Ex command.  For a function either "(" or "->" must | 
					
						
							|  |  |  | be following, without a line break.  Examples: > | 
					
						
							| 
									
										
										
										
											2020-07-28 20:07:27 +02:00
										 |  |  | 	myList->add(123) | 
					
						
							|  |  |  | 	g:myList->add(123) | 
					
						
							|  |  |  | 	[1, 2, 3]->Process() | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | 	{a: 1, b: 2}->Process() | 
					
						
							| 
									
										
										
										
											2020-07-28 20:07:27 +02:00
										 |  |  | 	"foobar"->Process() | 
					
						
							|  |  |  | 	("foobar")->Process() | 
					
						
							|  |  |  | 	'foobar'->Process() | 
					
						
							|  |  |  | 	('foobar')->Process() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | In the rare case there is ambiguity between a function name and an Ex command, | 
					
						
							| 
									
										
										
										
											2020-08-07 19:54:59 +02:00
										 |  |  | prepend ":" to make clear you want to use the Ex command.  For example, there | 
					
						
							|  |  |  | is both the `:substitute` command and the `substitute()` function.  When the | 
					
						
							|  |  |  | line starts with `substitute(` this will use the function. Prepend a colon to | 
					
						
							|  |  |  | use the command instead: > | 
					
						
							| 
									
										
										
										
											2020-02-22 18:36:32 +01:00
										 |  |  | 	:substitute(pattern (replacement ( | 
					
						
							| 
									
										
										
										
											2020-02-21 18:42:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | If the expression starts with "!" this is interpreted as a shell command, not | 
					
						
							|  |  |  | negation of a condition.  Thus this is a shell command: > | 
					
						
							|  |  |  | 	!shellCommand->something | 
					
						
							| 
									
										
										
										
											2021-08-29 21:55:35 +02:00
										 |  |  | Put the expression in parentheses to use the "!" for negation: > | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	(!expression)->Method() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-29 22:06:30 +01:00
										 |  |  | Note that while variables need to be defined before they can be used, | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | functions can be called before being defined.  This is required to allow | 
					
						
							|  |  |  | for cyclic dependencies between functions.  It is slightly less efficient, | 
					
						
							| 
									
										
										
										
											2020-02-29 22:06:30 +01:00
										 |  |  | since the function has to be looked up by name.  And a typo in the function | 
					
						
							| 
									
										
										
										
											2020-07-28 20:07:27 +02:00
										 |  |  | name will only be found when the function is called. | 
					
						
							| 
									
										
										
										
											2020-02-29 22:06:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | Omitting function() ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A user defined function can be used as a function reference in an expression | 
					
						
							|  |  |  | without `function()`. The argument types and return type will then be checked. | 
					
						
							|  |  |  | The function must already have been defined. > | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var Funcref = MyFunction | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | When using `function()` the resulting type is "func", a function with any | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | number of arguments and any return type (including void).  The function can be | 
					
						
							| 
									
										
										
										
											2021-12-24 13:18:38 +00:00
										 |  |  | defined later if the argument is in quotes. | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | Lambda using => instead of -> ~ | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | 							*vim9-lambda* | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | In legacy script there can be confusion between using "->" for a method call | 
					
						
							|  |  |  | and for a lambda.  Also, when a "{" is found the parser needs to figure out if | 
					
						
							|  |  |  | it is the start of a lambda or a dictionary, which is now more complicated | 
					
						
							|  |  |  | because of the use of argument types. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To avoid these problems Vim9 script uses a different syntax for a lambda, | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | which is similar to JavaScript: > | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | 	var Lambda = (arg) => expression | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 	var Lambda = (arg): type => expression | 
					
						
							|  |  |  | <							*E1157* | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | No line break is allowed in the arguments of a lambda up to and including the | 
					
						
							| 
									
										
										
										
											2021-06-27 15:18:56 +02:00
										 |  |  | "=>" (so that Vim can tell the difference between an expression in parentheses | 
					
						
							| 
									
										
										
										
											2021-06-13 19:02:49 +02:00
										 |  |  | and lambda arguments).  This is OK: > | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | 	filter(list, (k, v) => | 
					
						
							|  |  |  | 			v > 0) | 
					
						
							|  |  |  | This does not work: > | 
					
						
							|  |  |  | 	filter(list, (k, v) | 
					
						
							|  |  |  | 			=> v > 0) | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | This also does not work: > | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | 	filter(list, (k, | 
					
						
							|  |  |  | 			v) => v > 0) | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | But you can use a backslash to concatenate the lines before parsing: > | 
					
						
							|  |  |  | 	filter(list, (k, | 
					
						
							|  |  |  | 		\	v) | 
					
						
							|  |  |  | 		\	=> v > 0) | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | <					*vim9-lambda-arguments* *E1172* | 
					
						
							| 
									
										
										
										
											2021-04-10 17:18:09 +02:00
										 |  |  | In legacy script a lambda could be called with any number of extra arguments, | 
					
						
							|  |  |  | there was no way to warn for not using them.  In Vim9 script the number of | 
					
						
							|  |  |  | arguments must match.  If you do want to accept any arguments, or any further | 
					
						
							|  |  |  | arguments, use "..._", which makes the function accept | 
					
						
							|  |  |  | |vim9-variable-arguments|.  Example: > | 
					
						
							|  |  |  | 	var Callback = (..._) => 'anything' | 
					
						
							|  |  |  | 	echo Callback(1, 2, 3)  # displays "anything" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | <						*inline-function* *E1171* | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | Additionally, a lambda can contain statements in {}: > | 
					
						
							|  |  |  | 	var Lambda = (arg) => { | 
					
						
							|  |  |  | 		g:was_called = 'yes' | 
					
						
							|  |  |  | 		return expression | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | This can be useful for a timer, for example: > | 
					
						
							|  |  |  | 	var count = 0 | 
					
						
							|  |  |  |  	var timer = timer_start(500, (_) => { | 
					
						
							|  |  |  | 		 count += 1 | 
					
						
							|  |  |  | 		 echom 'Handler called ' .. count | 
					
						
							|  |  |  | 	     }, {repeat: 3}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | The ending "}" must be at the start of a line.  It can be followed by other | 
					
						
							|  |  |  | characters, e.g.: > | 
					
						
							|  |  |  | 	var d = mapnew(dict, (k, v): string => { | 
					
						
							|  |  |  | 	     return 'value' | 
					
						
							|  |  |  | 	   }) | 
					
						
							|  |  |  | No command can follow the "{", only a comment can be used there. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 						*command-block* *E1026* | 
					
						
							| 
									
										
										
										
											2021-12-17 12:45:22 +00:00
										 |  |  | The block can also be used for defining a user command.  Inside the block Vim9 | 
					
						
							|  |  |  | syntax will be used. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-16 14:41:10 +00:00
										 |  |  | If the statements include a dictionary, its closing bracket must not be | 
					
						
							|  |  |  | written at the start of a line.  Otherwise, it would be parsed as the end of | 
					
						
							|  |  |  | the block.  This does not work: > | 
					
						
							|  |  |  | 	command NewCommand { | 
					
						
							| 
									
										
										
										
											2021-12-17 12:45:22 +00:00
										 |  |  | 	     g:mydict = { | 
					
						
							| 
									
										
										
										
											2021-12-16 14:41:10 +00:00
										 |  |  | 	       'key': 'value', | 
					
						
							|  |  |  | 	       }  # ERROR: will be recognized as the end of the block | 
					
						
							|  |  |  | 	   } | 
					
						
							|  |  |  | Put the '}' after the last item to avoid this: > | 
					
						
							|  |  |  | 	command NewCommand { | 
					
						
							| 
									
										
										
										
											2021-12-17 12:45:22 +00:00
										 |  |  | 	     g:mydict = { | 
					
						
							| 
									
										
										
										
											2021-12-16 14:41:10 +00:00
										 |  |  | 	       'key': 'value' } | 
					
						
							|  |  |  | 	   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | Rationale: The "}" cannot be after a command because it would require parsing | 
					
						
							|  |  |  | the commands to find it.  For consistency with that no command can follow the | 
					
						
							|  |  |  | "{".  Unfortunately this means using "() => {  command  }" does not work, line | 
					
						
							|  |  |  | breaks are always required. | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 21:14:57 +01:00
										 |  |  | 							*vim9-curly* | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | To avoid the "{" of a dictionary literal to be recognized as a statement block | 
					
						
							| 
									
										
										
										
											2021-02-27 16:38:07 +01:00
										 |  |  | wrap it in parentheses: > | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 	var Lambda = (arg) => ({key: 42}) | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 21:14:57 +01:00
										 |  |  | Also when confused with the start of a command block: > | 
					
						
							|  |  |  | 	({ | 
					
						
							|  |  |  | 	    key: value | 
					
						
							|  |  |  | 	 })->method() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 16:38:57 +02:00
										 |  |  | Automatic line continuation ~ | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 					*vim9-line-continuation* *E1097* | 
					
						
							| 
									
										
										
										
											2020-04-12 16:38:57 +02:00
										 |  |  | In many cases it is obvious that an expression continues on the next line.  In | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | those cases there is no need to prefix the line with a backslash (see | 
					
						
							|  |  |  | |line-continuation|).  For example, when a list spans multiple lines: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var mylist = [ | 
					
						
							| 
									
										
										
										
											2020-04-12 16:38:57 +02:00
										 |  |  | 		'one', | 
					
						
							|  |  |  | 		'two', | 
					
						
							|  |  |  | 		] | 
					
						
							| 
									
										
										
										
											2020-04-12 20:19:16 +02:00
										 |  |  | And when a dict spans multiple lines: > | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | 	var mydict = { | 
					
						
							| 
									
										
										
										
											2020-04-12 20:19:16 +02:00
										 |  |  | 		one: 1, | 
					
						
							|  |  |  | 		two: 2, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | With a function call: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = Func( | 
					
						
							| 
									
										
										
										
											2020-04-12 20:19:16 +02:00
										 |  |  | 			arg1, | 
					
						
							|  |  |  | 			arg2 | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | For binary operators in expressions not in [], {} or () a line break is | 
					
						
							|  |  |  | possible just before or after the operator.  For example: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var text = lead | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | 		   .. middle | 
					
						
							|  |  |  | 		   .. end | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var total = start + | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 		    end - | 
					
						
							| 
									
										
										
										
											2020-04-12 20:55:20 +02:00
										 |  |  | 		    correction | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = positive | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | 			? PosFunc(arg) | 
					
						
							|  |  |  | 			: NegFunc(arg) | 
					
						
							| 
									
										
										
										
											2020-04-12 20:55:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | For a method call using "->" and a member using a dot, a line break is allowed | 
					
						
							|  |  |  | before it: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = GetBuilder() | 
					
						
							| 
									
										
										
										
											2020-06-21 22:12:03 +02:00
										 |  |  | 			->BuilderSetWidth(333) | 
					
						
							|  |  |  | 			->BuilderSetHeight(777) | 
					
						
							|  |  |  | 			->BuilderBuild() | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = MyDict | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | 			.member | 
					
						
							| 
									
										
										
										
											2020-06-21 22:12:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | For commands that have an argument that is a list of commands, the | character | 
					
						
							|  |  |  | at the start of the line indicates line continuation: > | 
					
						
							|  |  |  | 	autocmd BufNewFile *.match if condition | 
					
						
							|  |  |  | 		|   echo 'match' | 
					
						
							|  |  |  | 		| endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-16 15:23:36 +01:00
										 |  |  | Note that this means that in heredoc the first line cannot start with a bar: > | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | 	var lines =<< trim END | 
					
						
							|  |  |  | 	   | this doesn't work | 
					
						
							|  |  |  | 	END | 
					
						
							|  |  |  | Either use an empty line at the start or do not use heredoc.  Or temporarily | 
					
						
							|  |  |  | add the "C" flag to 'cpoptions': > | 
					
						
							|  |  |  | 	set cpo+=C | 
					
						
							|  |  |  | 	var lines =<< trim END | 
					
						
							| 
									
										
										
										
											2021-10-16 15:23:36 +01:00
										 |  |  | 	   | this works | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | 	END | 
					
						
							|  |  |  | 	set cpo-=C | 
					
						
							|  |  |  | If the heredoc is inside a function 'cpoptions' must be set before :def and | 
					
						
							|  |  |  | restored after the :enddef. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In places where line continuation with a backslash is still needed, such as | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | splitting up a long Ex command, comments can start with '#\ ': > | 
					
						
							|  |  |  | 	syn region Text | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | 	      \ start='foo' | 
					
						
							|  |  |  | 	      #\ comment | 
					
						
							|  |  |  | 	      \ end='bar' | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | Like with legacy script '"\ ' is used.  This is also needed when line | 
					
						
							|  |  |  | continuation is used without a backslash and a line starts with a bar: > | 
					
						
							|  |  |  | 	au CursorHold * echom 'BEFORE bar' | 
					
						
							|  |  |  | 	      #\ some comment | 
					
						
							|  |  |  | 	      | echom 'AFTER bar' | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 							*E1050* | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | To make it possible for the operator at the start of the line to be | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | recognized, it is required to put a colon before a range.  This example will | 
					
						
							|  |  |  | add "start" and print: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = start | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | 	+ print | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | Like this: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = start + print | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | This will assign "start" and print a line: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var result = start | 
					
						
							| 
									
										
										
										
											2020-06-22 23:02:51 +02:00
										 |  |  | 	:+ print | 
					
						
							| 
									
										
										
										
											2020-04-12 16:38:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | After the range an Ex command must follow.  Without the colon you can call a | 
					
						
							|  |  |  | function without `:call`, but after a range you do need it: > | 
					
						
							|  |  |  | 	MyFunc() | 
					
						
							|  |  |  | 	:% call MyFunc() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 14:36:24 +01:00
										 |  |  | Note that the colon is not required for the |+cmd| argument: > | 
					
						
							|  |  |  | 	edit +6 fname | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 21:53:00 +02:00
										 |  |  | It is also possible to split a function header over multiple lines, in between | 
					
						
							|  |  |  | arguments: > | 
					
						
							|  |  |  | 	def MyFunc( | 
					
						
							|  |  |  | 		text: string, | 
					
						
							|  |  |  | 		separator = '-' | 
					
						
							|  |  |  | 		): string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | Since a continuation line cannot be easily recognized the parsing of commands | 
					
						
							| 
									
										
										
										
											2020-12-24 15:14:01 +01:00
										 |  |  | has been made stricter.  E.g., because of the error in the first line, the | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | second line is seen as a separate command: > | 
					
						
							|  |  |  | 	popup_create(some invalid expression, { | 
					
						
							|  |  |  | 	   exit_cb: Func}) | 
					
						
							|  |  |  | Now "exit_cb: Func})" is actually a valid command: save any changes to the | 
					
						
							|  |  |  | file "_cb: Func})" and exit.  To avoid this kind of mistake in Vim9 script | 
					
						
							|  |  |  | there must be white space between most command names and the argument. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | *E1144* | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | However, the argument of a command that is a command won't be recognized.  For | 
					
						
							|  |  |  | example, after "windo echo expr" a line break inside "expr" will not be seen. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | Notes: | 
					
						
							|  |  |  | - "enddef" cannot be used at the start of a continuation line, it ends the | 
					
						
							|  |  |  |   current function. | 
					
						
							|  |  |  | - No line break is allowed in the LHS of an assignment.  Specifically when | 
					
						
							|  |  |  |   unpacking a list |:let-unpack|. This is OK: > | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	[var1, var2] = | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 		Func() | 
					
						
							|  |  |  | <  This does not work: > | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	[var1, | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 	    var2] = | 
					
						
							|  |  |  | 		Func() | 
					
						
							|  |  |  | - No line break is allowed in between arguments of an `:echo`, `:execute` and | 
					
						
							|  |  |  |   similar commands.  This is OK: > | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	echo [1, | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 		2] [3, | 
					
						
							|  |  |  | 			4] | 
					
						
							|  |  |  | <  This does not work: > | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 	echo [1, 2] | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 		[3, 4] | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | - In some cases it is difficult for Vim to parse a command, especially when | 
					
						
							|  |  |  |   commands are used as an argument to another command, such as `windo`.  In | 
					
						
							|  |  |  |   those cases the line continuation with a backslash has to be used. | 
					
						
							| 
									
										
										
										
											2020-04-12 16:38:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-02 17:19:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | White space ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 			*E1004* *E1068* *E1069* *E1074* *E1127* *E1202* | 
					
						
							| 
									
										
										
										
											2021-05-02 17:19:11 +02:00
										 |  |  | Vim9 script enforces proper use of white space.  This is no longer allowed: > | 
					
						
							|  |  |  | 	var name=234	# Error! | 
					
						
							|  |  |  | 	var name= 234	# Error! | 
					
						
							|  |  |  | 	var name =234	# Error! | 
					
						
							|  |  |  | There must be white space before and after the "=": > | 
					
						
							|  |  |  | 	var name = 234	# OK | 
					
						
							|  |  |  | White space must also be put before the # that starts a comment after a | 
					
						
							|  |  |  | command: > | 
					
						
							|  |  |  | 	var name = 234# Error! | 
					
						
							|  |  |  | 	var name = 234 # OK | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | White space is required around most operators. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | White space is required in a sublist (list slice) around the ":", except at | 
					
						
							|  |  |  | the start and end: > | 
					
						
							|  |  |  | 	otherlist = mylist[v : count]  	# v:count has a different meaning | 
					
						
							|  |  |  | 	otherlist = mylist[:]		# make a copy of the List | 
					
						
							|  |  |  | 	otherlist = mylist[v :] | 
					
						
							|  |  |  | 	otherlist = mylist[: v] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | White space is not allowed: | 
					
						
							|  |  |  | - Between a function name and the "(": > | 
					
						
							|  |  |  | 	Func (arg)	   # Error! | 
					
						
							|  |  |  | 	Func | 
					
						
							|  |  |  | 	     \ (arg)	   # Error! | 
					
						
							|  |  |  | 	Func | 
					
						
							|  |  |  | 	      (arg)	   # Error! | 
					
						
							|  |  |  | 	Func(arg)	   # OK | 
					
						
							|  |  |  | 	Func( | 
					
						
							|  |  |  | 	      arg)	   # OK | 
					
						
							|  |  |  | 	Func( | 
					
						
							|  |  |  | 	      arg	   # OK | 
					
						
							|  |  |  | 	      ) | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | <							*E1205* | 
					
						
							| 
									
										
										
										
											2021-08-29 21:55:35 +02:00
										 |  |  | White space is not allowed in a `:set` command between the option name and a | 
					
						
							|  |  |  | following "&", "!", "<", "=", "+=", "-=" or "^=". | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-02 17:19:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | No curly braces expansion ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | |curly-braces-names| cannot be used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | Command modifiers are not ignored ~ | 
					
						
							|  |  |  | 								*E1176* | 
					
						
							|  |  |  | Using a command modifier for a command that does not use it gives an error. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | Dictionary literals ~ | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 						*vim9-literal-dict* *E1014* | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | Traditionally Vim has supported dictionary literals with a {} syntax: > | 
					
						
							|  |  |  | 	let dict = {'key': value} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 19:12:14 +01:00
										 |  |  | Later it became clear that using a simple text key is very common, thus | 
					
						
							|  |  |  | literal dictionaries were introduced in a backwards compatible way: > | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | 	let dict = #{key: value} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 19:12:14 +01:00
										 |  |  | However, this #{} syntax is unlike any existing language.  As it turns out | 
					
						
							|  |  |  | that using a literal key is much more common than using an expression, and | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | considering that JavaScript uses this syntax, using the {} form for dictionary | 
					
						
							| 
									
										
										
										
											2020-12-04 19:12:14 +01:00
										 |  |  | literals is considered a much more useful syntax.  In Vim9 script the {} form | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | uses literal keys: > | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	var dict = {key: value} | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 19:12:14 +01:00
										 |  |  | This works for alphanumeric characters, underscore and dash.  If you want to | 
					
						
							|  |  |  | use another character, use a single or double quoted string: > | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	var dict = {'key with space': value} | 
					
						
							|  |  |  | 	var dict = {"key\twith\ttabs": value} | 
					
						
							|  |  |  | 	var dict = {'': value}  		# empty key | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | <							*E1139* | 
					
						
							| 
									
										
										
										
											2020-12-04 19:12:14 +01:00
										 |  |  | In case the key needs to be an expression, square brackets can be used, just | 
					
						
							|  |  |  | like in JavaScript: > | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	var dict = {["key" .. nr]: value} | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-03 17:41:24 +01:00
										 |  |  | The key type can be string, number, bool or float.  Other types result in an | 
					
						
							|  |  |  | error.  A number can be given with and without the []: > | 
					
						
							|  |  |  | 	var dict = {123: 'without', [456]: 'with'} | 
					
						
							|  |  |  | 	echo dict | 
					
						
							|  |  |  | 	{'456': 'with', '123': 'without'} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 18:53:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 21:42:57 +01:00
										 |  |  | No :xit, :t, :k, :append, :change or :insert ~ | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1100* | 
					
						
							| 
									
										
										
										
											2020-08-01 17:00:03 +02:00
										 |  |  | These commands are too easily confused with local variable names. | 
					
						
							|  |  |  | Instead of `:x` or `:xit` you can use `:exit`. | 
					
						
							|  |  |  | Instead of `:t` you can use `:copy`. | 
					
						
							| 
									
										
										
										
											2021-02-19 21:42:57 +01:00
										 |  |  | Instead of `:k` you can use `:mark`. | 
					
						
							| 
									
										
										
										
											2020-02-04 22:53:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Comparators ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The 'ignorecase' option is not used for comparators that use strings. | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | Thus "=~" works like "=~#". | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-02 17:19:11 +02:00
										 |  |  | Abort after error ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In legacy script, when an error is encountered, Vim continues to execute | 
					
						
							|  |  |  | following lines.  This can lead to a long sequence of errors and need to type | 
					
						
							|  |  |  | CTRL-C to stop it.  In Vim9 script execution of commands stops at the first | 
					
						
							|  |  |  | error.  Example: > | 
					
						
							|  |  |  | 	vim9script | 
					
						
							|  |  |  | 	var x = does-not-exist | 
					
						
							|  |  |  | 	echo 'not executed' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | For loop ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 							*E1254* | 
					
						
							| 
									
										
										
										
											2021-12-05 21:54:04 +00:00
										 |  |  | The loop variable must not be declared yet: > | 
					
						
							| 
									
										
										
										
											2021-11-27 10:57:26 +00:00
										 |  |  | 	var i = 1 | 
					
						
							|  |  |  | 	for i in [1, 2, 3]   # Error! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-05 21:54:04 +00:00
										 |  |  | It is possible to use a global variable though: > | 
					
						
							|  |  |  | 	g:i = 1 | 
					
						
							|  |  |  | 	for g:i in [1, 2, 3] | 
					
						
							|  |  |  | 	  echo g:i | 
					
						
							|  |  |  | 	endfor | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | Legacy Vim script has some tricks to make a for loop over a list handle | 
					
						
							|  |  |  | deleting items at the current or previous item.  In Vim9 script it just uses | 
					
						
							|  |  |  | the index, if items are deleted then items in the list will be skipped. | 
					
						
							|  |  |  | Example legacy script: > | 
					
						
							|  |  |  | 	let l = [1, 2, 3, 4] | 
					
						
							|  |  |  | 	for i in l | 
					
						
							|  |  |  | 	   echo i | 
					
						
							|  |  |  | 	   call remove(l, index(l, i)) | 
					
						
							|  |  |  | 	endfor | 
					
						
							|  |  |  | Would echo: | 
					
						
							|  |  |  | 	1 | 
					
						
							|  |  |  | 	2 | 
					
						
							|  |  |  | 	3 | 
					
						
							|  |  |  | 	4 | 
					
						
							|  |  |  | In compiled Vim9 script you get: | 
					
						
							|  |  |  | 	1 | 
					
						
							|  |  |  | 	3 | 
					
						
							|  |  |  | Generally, you should not change the list that is iterated over.  Make a copy | 
					
						
							|  |  |  | first if needed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Conditions and expressions ~ | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 						*vim9-boolean* | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | Conditions and expressions are mostly working like they do in other languages. | 
					
						
							|  |  |  | Some values are different from legacy Vim script: | 
					
						
							|  |  |  | 	value		legacy Vim script	Vim9 script ~ | 
					
						
							|  |  |  | 	0		falsy			falsy | 
					
						
							|  |  |  | 	1		truthy			truthy | 
					
						
							|  |  |  | 	99		truthy			Error! | 
					
						
							|  |  |  | 	"0"		falsy			Error! | 
					
						
							|  |  |  | 	"99"		truthy			Error! | 
					
						
							|  |  |  | 	"text"		falsy			Error! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For the "??" operator and when using "!" then there is no error, every value | 
					
						
							|  |  |  | is either falsy or truthy.  This is mostly like JavaScript, except that an | 
					
						
							|  |  |  | empty list and dict is falsy: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type		truthy when ~ | 
					
						
							| 
									
										
										
										
											2021-01-02 16:39:53 +01:00
										 |  |  | 	bool		true, v:true or 1 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	number		non-zero | 
					
						
							|  |  |  | 	float		non-zero | 
					
						
							|  |  |  | 	string		non-empty | 
					
						
							|  |  |  | 	blob		non-empty | 
					
						
							|  |  |  | 	list		non-empty (different from JavaScript) | 
					
						
							|  |  |  | 	dictionary	non-empty (different from JavaScript) | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 	func		when there is a function name | 
					
						
							| 
									
										
										
										
											2021-01-02 16:39:53 +01:00
										 |  |  | 	special		true or v:true | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	job		when not NULL | 
					
						
							|  |  |  | 	channel		when not NULL | 
					
						
							|  |  |  | 	class		when not NULL | 
					
						
							| 
									
										
										
										
											2021-01-02 16:39:53 +01:00
										 |  |  | 	object		when not NULL (TODO: when isTrue() returns true) | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-03 22:52:39 +02:00
										 |  |  | The boolean operators "||" and "&&" expect the values to be boolean, zero or | 
					
						
							|  |  |  | one: > | 
					
						
							|  |  |  | 	1 || false   == true | 
					
						
							|  |  |  | 	0 || 1       == true | 
					
						
							|  |  |  | 	0 || false   == false | 
					
						
							|  |  |  | 	1 && true    == true | 
					
						
							|  |  |  | 	0 && 1       == false | 
					
						
							|  |  |  | 	8 || 0	     Error! | 
					
						
							|  |  |  | 	'yes' && 0   Error! | 
					
						
							|  |  |  | 	[] || 99     Error! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When using "!" for inverting, there is no error for using any type and the | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | result is a boolean.  "!!" can be used to turn any value into boolean: > | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	!'yes'			== false | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | 	!![]			== false | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	!![1, 2, 3]		== true | 
					
						
							| 
									
										
										
										
											2020-10-03 22:52:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | When using "`.."` for string concatenation arguments of simple types are | 
					
						
							| 
									
										
										
										
											2020-10-04 16:06:05 +02:00
										 |  |  | always converted to string: > | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	'hello ' .. 123  == 'hello 123' | 
					
						
							| 
									
										
										
										
											2021-01-02 16:39:53 +01:00
										 |  |  | 	'hello ' .. v:true  == 'hello true' | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-27 15:39:57 +00:00
										 |  |  | Simple types are Number, Float, Special and Bool.  For other types |string()| | 
					
						
							|  |  |  | should be used. | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 						*false* *true* *null* *E1034* | 
					
						
							| 
									
										
										
										
											2022-03-08 13:18:55 +00:00
										 |  |  | In Vim9 script one can use the following predefined values: > | 
					
						
							|  |  |  | 	true | 
					
						
							|  |  |  | 	false | 
					
						
							|  |  |  | 	null | 
					
						
							|  |  |  | 	null_blob | 
					
						
							|  |  |  | 	null_channel | 
					
						
							|  |  |  | 	null_dict | 
					
						
							|  |  |  | 	null_function | 
					
						
							|  |  |  | 	null_job | 
					
						
							|  |  |  | 	null_list | 
					
						
							|  |  |  | 	null_partial | 
					
						
							|  |  |  | 	null_string | 
					
						
							|  |  |  | `true` is the same as `v:true`, `false` the same as `v:false`, `null` the same | 
					
						
							|  |  |  | as `v:null`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | While `null` has the type "special", the other "null_" types have the type | 
					
						
							|  |  |  | indicated by their name.  Quite often a null value is handled the same as an | 
					
						
							|  |  |  | empty value, but not always.  The values can be useful to clear a script-local | 
					
						
							|  |  |  | variable, since they cannot be deleted with `:unlet`.  E.g.: > | 
					
						
							|  |  |  | 	var theJob = job_start(...) | 
					
						
							|  |  |  | 	# let the job do its work | 
					
						
							|  |  |  | 	theJob = null_job | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The values can also be useful as the default value for an argument: > | 
					
						
							|  |  |  | 	def MyFunc(b: blob = null_blob) | 
					
						
							|  |  |  | 	   if b == null_blob | 
					
						
							|  |  |  | 	      # b argument was not given | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-19 15:18:53 +00:00
										 |  |  | It is possible to compare `null`  with any value, this will not give a type | 
					
						
							|  |  |  | error.  However, comparing `null` with a number, float or bool will always | 
					
						
							|  |  |  | result in `false`.  This is different from legacy script, where comparing | 
					
						
							|  |  |  | `null` with zero or `false` would return `true`. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-08 13:18:55 +00:00
										 |  |  | When converting a boolean to a string `false` and `true` are used, not | 
					
						
							|  |  |  | `v:false` and `v:true` like in legacy script.  `v:none` has no `none` | 
					
						
							|  |  |  | replacement, it has no equivalent in other languages. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 18:40:19 +01:00
										 |  |  | Indexing a string with [idx] or taking a slice with [idx : idx] uses character | 
					
						
							|  |  |  | indexes instead of byte indexes.  Composing characters are included. | 
					
						
							|  |  |  | Example: > | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | 	echo 'bár'[1] | 
					
						
							|  |  |  | In legacy script this results in the character 0xc3 (an illegal byte), in Vim9 | 
					
						
							|  |  |  | script this results in the string 'á'. | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | A negative index is counting from the end, "[-1]" is the last character. | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | To exclude the last character use |slice()|. | 
					
						
							| 
									
										
										
										
											2021-03-29 22:14:55 +02:00
										 |  |  | To count composing characters separately use |strcharpart()|. | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | If the index is out of range then an empty string results. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In legacy script "++var" and "--var" would be silently accepted and have no | 
					
						
							|  |  |  | effect.  This is an error in Vim9 script. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Numbers starting with zero are not considered to be octal, only numbers | 
					
						
							|  |  |  | starting with "0o" are octal: "0o744". |scriptversion-4| | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | What to watch out for ~ | 
					
						
							|  |  |  | 							*vim9-gotchas* | 
					
						
							|  |  |  | Vim9 was designed to be closer to often used programming languages, but at the | 
					
						
							|  |  |  | same time tries to support the legacy Vim commands.  Some compromises had to | 
					
						
							|  |  |  | be made.  Here is a summary of what might be unexpected. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Ex command ranges need to be prefixed with a colon. > | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	->		  legacy Vim: shifts the previous line to the right | 
					
						
							|  |  |  | 	->func()	  Vim9: method call in a continuation line | 
					
						
							|  |  |  | 	:->		  Vim9: shifts the previous line to the right | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	%s/a/b		  legacy Vim: substitute on all lines | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | 	x = alongname | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	     % another	  Vim9: modulo operator in a continuation line | 
					
						
							|  |  |  | 	:%s/a/b		  Vim9: substitute on all lines | 
					
						
							|  |  |  | 	't		  legacy Vim: jump to mark t | 
					
						
							|  |  |  | 	'text'->func()	  Vim9: method call | 
					
						
							|  |  |  | 	:'t		  Vim9: jump to mark t | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 19:54:59 +02:00
										 |  |  | Some Ex commands can be confused with assignments in Vim9 script: > | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	g:name = value    # assignment | 
					
						
							|  |  |  | 	:g:pattern:cmd	  # :global command | 
					
						
							| 
									
										
										
										
											2020-08-07 19:54:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-13 15:04:34 +01:00
										 |  |  | To avoid confusion between a `:global` or `:substitute` command and an | 
					
						
							|  |  |  | expression or assignment, a few separators cannot be used when these commands | 
					
						
							|  |  |  | are abbreviated to a single character: ':', '-' and '.'. > | 
					
						
							|  |  |  | 	g:pattern:cmd	  # invalid command - ERROR | 
					
						
							|  |  |  | 	s:pattern:repl	  # invalid command - ERROR | 
					
						
							|  |  |  | 	g-pattern-cmd	  # invalid command - ERROR | 
					
						
							|  |  |  | 	s-pattern-repl	  # invalid command - ERROR | 
					
						
							|  |  |  | 	g.pattern.cmd	  # invalid command - ERROR | 
					
						
							|  |  |  | 	s.pattern.repl	  # invalid command - ERROR | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Also, there cannot be a space between the command and the separator: > | 
					
						
							|  |  |  | 	g /pattern/cmd	  # invalid command - ERROR | 
					
						
							|  |  |  | 	s /pattern/repl	  # invalid command - ERROR | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | Functions defined with `:def` compile the whole function.  Legacy functions | 
					
						
							|  |  |  | can bail out, and the following lines are not parsed: > | 
					
						
							|  |  |  | 	func Maybe() | 
					
						
							|  |  |  | 	  if !has('feature') | 
					
						
							|  |  |  | 	    return | 
					
						
							|  |  |  | 	  endif | 
					
						
							|  |  |  | 	  use-feature | 
					
						
							|  |  |  | 	endfunc | 
					
						
							|  |  |  | Vim9 functions are compiled as a whole: > | 
					
						
							|  |  |  | 	def Maybe() | 
					
						
							|  |  |  | 	  if !has('feature') | 
					
						
							|  |  |  | 	    return | 
					
						
							|  |  |  | 	  endif | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 	  use-feature  # May give a compilation error | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | 	enddef | 
					
						
							|  |  |  | For a workaround, split it in two functions: > | 
					
						
							|  |  |  | 	func Maybe() | 
					
						
							|  |  |  | 	  if has('feature') | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | 	    call MaybeInner() | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | 	  endif | 
					
						
							|  |  |  | 	endfunc | 
					
						
							|  |  |  | 	if has('feature') | 
					
						
							|  |  |  | 	  def MaybeInner() | 
					
						
							|  |  |  | 	    use-feature | 
					
						
							|  |  |  | 	  enddef | 
					
						
							|  |  |  | 	endif | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | Or put the unsupported code inside an `if` with a constant expression that | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | evaluates to false: > | 
					
						
							|  |  |  | 	def Maybe() | 
					
						
							|  |  |  | 	  if has('feature') | 
					
						
							|  |  |  | 	    use-feature | 
					
						
							|  |  |  | 	  endif | 
					
						
							|  |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  | The `exists_compiled()` function can also be used for this. | 
					
						
							|  |  |  | 							*vim9-user-command* | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | Another side effect of compiling a function is that the presence of a user | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | command is checked at compile time.  If the user command is defined later an | 
					
						
							|  |  |  | error will result.  This works: > | 
					
						
							|  |  |  | 	command -nargs=1 MyCommand echom <q-args> | 
					
						
							|  |  |  | 	def Works() | 
					
						
							|  |  |  | 	  MyCommand 123 | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | This will give an error for "MyCommand" not being defined: > | 
					
						
							|  |  |  | 	def Works() | 
					
						
							|  |  |  | 	  command -nargs=1 MyCommand echom <q-args> | 
					
						
							|  |  |  | 	  MyCommand 123 | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | A workaround is to invoke the command indirectly with `:execute`: > | 
					
						
							|  |  |  | 	def Works() | 
					
						
							|  |  |  | 	  command -nargs=1 MyCommand echom <q-args> | 
					
						
							|  |  |  | 	  execute 'MyCommand 123' | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | Note that for unrecognized commands there is no check for "|" and a following | 
					
						
							|  |  |  | command.  This will give an error for missing `endif`: > | 
					
						
							|  |  |  | 	def Maybe() | 
					
						
							|  |  |  | 	  if has('feature') | use-feature | endif | 
					
						
							|  |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2020-06-30 20:38:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | Other differences ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Patterns are used like 'magic' is set, unless explicitly overruled. | 
					
						
							|  |  |  | The 'edcompatible' option value is not used. | 
					
						
							|  |  |  | The 'gdefault' option value is not used. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | You may also find this wiki useful.  It was written by an early adopter of | 
					
						
							| 
									
										
										
										
											2021-03-13 13:28:13 +01:00
										 |  |  | Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-27 15:18:56 +02:00
										 |  |  | 							*:++* *:--* | 
					
						
							|  |  |  | The ++ and -- commands have been added.  They are very similar to adding or | 
					
						
							|  |  |  | subtracting one: > | 
					
						
							|  |  |  | 		++var | 
					
						
							|  |  |  | 		var += 1 | 
					
						
							|  |  |  | 		--var | 
					
						
							|  |  |  | 		var -= 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Using ++var or --var in an expression is not supported yet. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3. New style functions					*fast-functions* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 							*:def* *E1028* | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | :def[!] {name}([arguments])[: {return-type}] | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 			Define a new function by the name {name}.  The body of | 
					
						
							|  |  |  | 			the function follows in the next lines, until the | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 			matching `:enddef`. *E1073* | 
					
						
							|  |  |  | 							*E1011* | 
					
						
							|  |  |  | 			The {name} must be less than 100 bytes long. | 
					
						
							|  |  |  | 					*E1003* *E1027* *E1056* *E1059* | 
					
						
							|  |  |  | 			The type of value used with `:return` must match | 
					
						
							|  |  |  | 			{return-type}.  When {return-type} is omitted or is | 
					
						
							|  |  |  | 			"void" the function is not expected to return | 
					
						
							|  |  |  | 			anything. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1077* *E1123* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 			{arguments} is a sequence of zero or more argument | 
					
						
							|  |  |  | 			declarations.  There are three forms: | 
					
						
							|  |  |  | 				{name}: {type} | 
					
						
							|  |  |  | 				{name} = {value} | 
					
						
							|  |  |  | 				{name}: {type} = {value} | 
					
						
							|  |  |  | 			The first form is a mandatory argument, the caller | 
					
						
							|  |  |  | 			must always provide them. | 
					
						
							|  |  |  | 			The second and third form are optional arguments. | 
					
						
							|  |  |  | 			When the caller omits an argument the {value} is used. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 			The function will be compiled into instructions when | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | 			called, or when `:disassemble` or `:defcompile` is | 
					
						
							|  |  |  | 			used.  Syntax and type errors will be produced at that | 
					
						
							|  |  |  | 			time. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | 			It is possible to nest `:def` inside another `:def` or | 
					
						
							|  |  |  | 			`:function` up to about 50 levels deep. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1117* | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 			[!] is used as with `:function`.  Note that | 
					
						
							|  |  |  | 			script-local functions cannot be deleted or redefined | 
					
						
							|  |  |  | 			later in Vim9 script.  They can only be removed by | 
					
						
							|  |  |  | 			reloading the same script. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 					*:enddef* *E1057* *E1152* *E1173* | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | :enddef			End of a function defined with `:def`. It should be on | 
					
						
							|  |  |  | 			a line by its own. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | You may also find this wiki useful.  It was written by an early adopter of | 
					
						
							| 
									
										
										
										
											2021-03-14 18:40:19 +01:00
										 |  |  | Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 18:42:43 +01:00
										 |  |  | If the script the function is defined in is Vim9 script, then script-local | 
					
						
							|  |  |  | variables can be accessed without the "s:" prefix.  They must be defined | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | before the function is compiled.  If the script the function is defined in is | 
					
						
							|  |  |  | legacy script, then script-local variables must be accessed with the "s:" | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | prefix if they do not exist at the time of compiling. | 
					
						
							| 
									
										
										
										
											2020-02-21 18:42:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 21:20:45 +02:00
										 |  |  | 						*:defc* *:defcompile* | 
					
						
							|  |  |  | :defc[ompile]		Compile functions defined in the current script that | 
					
						
							|  |  |  | 			were not compiled yet. | 
					
						
							|  |  |  | 			This will report errors found during the compilation. | 
					
						
							| 
									
										
										
										
											2020-02-21 18:42:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-15 21:41:42 +01:00
										 |  |  | 						*:disa* *:disassemble* | 
					
						
							|  |  |  | :disa[ssemble] {func}	Show the instructions generated for {func}. | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 			This is for debugging and testing. *E1061* | 
					
						
							| 
									
										
										
										
											2020-02-29 22:06:30 +01:00
										 |  |  | 			Note that for command line completion of {func} you | 
					
						
							|  |  |  | 			can prepend "s:" to find script-local functions. | 
					
						
							| 
									
										
										
										
											2020-02-15 21:41:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 19:02:49 +02:00
										 |  |  | :disa[ssemble] profile {func} | 
					
						
							|  |  |  | 			Like `:disassemble` but with the instructions used for | 
					
						
							| 
									
										
										
										
											2021-01-25 21:14:57 +01:00
										 |  |  | 			profiling. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 19:02:49 +02:00
										 |  |  | :disa[ssemble] debug {func} | 
					
						
							|  |  |  | 			Like `:disassemble` but with the instructions used for | 
					
						
							|  |  |  | 			debugging. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | Limitations ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Local variables will not be visible to string evaluation.  For example: > | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 	def MapList(): list<string> | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	  var list = ['aa', 'bb', 'cc', 'dd'] | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 	  return range(1, 2)->map('list[v:val]') | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The map argument is a string expression, which is evaluated without the | 
					
						
							|  |  |  | function scope.  Instead, use a lambda: > | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 	def MapList(): list<string> | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	  var list = ['aa', 'bb', 'cc', 'dd'] | 
					
						
							| 
									
										
										
										
											2021-10-16 15:23:36 +01:00
										 |  |  | 	  return range(1, 2)->map((_, v) => list[v]) | 
					
						
							| 
									
										
										
										
											2020-07-10 22:00:53 +02:00
										 |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-01 09:27:20 +00:00
										 |  |  | For commands that are not compiled, such as `:edit`, backtick expansion can be | 
					
						
							|  |  |  | used and it can use the local scope.  Example: > | 
					
						
							| 
									
										
										
										
											2020-12-26 15:39:31 +01:00
										 |  |  | 	def Replace() | 
					
						
							| 
									
										
										
										
											2021-12-01 09:27:20 +00:00
										 |  |  | 	  var fname = 'blah.txt' | 
					
						
							|  |  |  | 	  edit `=fname` | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | Closures defined in a loop will share the same context.  For example: > | 
					
						
							|  |  |  | 	var flist: list<func> | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	for i in range(5) | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | 	  var inloop = i | 
					
						
							|  |  |  | 	  flist[i] = () => inloop | 
					
						
							|  |  |  | 	endfor | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	echo range(5)->map((i, _) => flist[i]()) | 
					
						
							|  |  |  | 	# Result: [4, 4, 4, 4, 4] | 
					
						
							| 
									
										
										
										
											2022-03-19 15:18:53 +00:00
										 |  |  | <							*E1271* | 
					
						
							|  |  |  | A closure must be compiled in the context that it is defined in, so that | 
					
						
							|  |  |  | variables in that context can be found.  This mostly happens correctly, except | 
					
						
							|  |  |  | when a function is marked for debugging with `breakadd` after it was compiled. | 
					
						
							|  |  |  | Make sure the define the breakpoint before compiling the outerh function. | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | The "inloop" variable will exist only once, all closures put in the list refer | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | to the same instance, which in the end will have the value 4.  This is | 
					
						
							|  |  |  | efficient, also when looping many times.  If you do want a separate context | 
					
						
							|  |  |  | for each closure call a function to define it: > | 
					
						
							|  |  |  | 	def GetClosure(i: number): func | 
					
						
							|  |  |  | 	  var infunc = i | 
					
						
							|  |  |  | 	  return () => infunc | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var flist: list<func> | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	for i in range(5) | 
					
						
							|  |  |  | 	  flist[i] = GetClosure(i) | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | 	endfor | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	echo range(5)->map((i, _) => flist[i]()) | 
					
						
							|  |  |  | 	# Result: [0, 1, 2, 3, 4] | 
					
						
							| 
									
										
										
										
											2021-03-31 20:07:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | In some situations, especially when calling a Vim9 closure from legacy | 
					
						
							|  |  |  | context, the evaluation will fail.  *E1248* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Converting a function from legacy to Vim9 ~ | 
					
						
							|  |  |  | 					*convert_legacy_function_to_vim9* | 
					
						
							|  |  |  | These are the most changes that need to be made to convert a legacy function | 
					
						
							|  |  |  | to a Vim9 function: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Change `func` or `function` to `def`. | 
					
						
							|  |  |  | - Change `endfunc` or `endfunction` to `enddef`. | 
					
						
							|  |  |  | - Add types to the function arguments. | 
					
						
							|  |  |  | - If the function returns something, add the return type. | 
					
						
							|  |  |  | - Change comments to start with # instead of ". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   For example, a legacy function: > | 
					
						
							|  |  |  | 	func MyFunc(text) | 
					
						
							|  |  |  | 	  " function body | 
					
						
							|  |  |  | 	endfunc | 
					
						
							|  |  |  | <  Becomes: > | 
					
						
							|  |  |  | 	def MyFunc(text: string): number | 
					
						
							|  |  |  | 	  # function body | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Remove "a:" used for arguments. E.g.: > | 
					
						
							|  |  |  | 	return len(a:text) | 
					
						
							|  |  |  | <  Becomes: > | 
					
						
							|  |  |  | 	return len(text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Change `let` used to declare a variable to `var`. | 
					
						
							|  |  |  | - Remove `let` used to assign a value to a variable.  This is for local | 
					
						
							|  |  |  |   variables already declared and b: w: g: and t: variables. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   For example, legacy function: > | 
					
						
							|  |  |  | 	  let lnum = 1 | 
					
						
							|  |  |  | 	  let lnum += 3 | 
					
						
							|  |  |  | 	  let b:result = 42 | 
					
						
							|  |  |  | <  Becomes: > | 
					
						
							|  |  |  | 	  var lnum = 1 | 
					
						
							|  |  |  | 	  lnum += 3 | 
					
						
							|  |  |  | 	  b:result = 42 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Insert white space in expressions where needed. | 
					
						
							|  |  |  | - Change "." used for concatenation to "..". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   For example, legacy function: > | 
					
						
							|  |  |  | 	  echo line(1).line(2) | 
					
						
							|  |  |  | <  Becomes: > | 
					
						
							|  |  |  | 	  echo line(1) .. line(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - line continuation does not always require a backslash: > | 
					
						
							|  |  |  |   	echo ['one', | 
					
						
							|  |  |  | 		\ 'two', | 
					
						
							|  |  |  | 		\ 'three' | 
					
						
							|  |  |  | 		\ ] | 
					
						
							|  |  |  | <  Becomes: > | 
					
						
							|  |  |  | 	echo ['one', | 
					
						
							|  |  |  | 		'two', | 
					
						
							|  |  |  | 		'three' | 
					
						
							|  |  |  | 		] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4. Types					*vim9-types* | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 					*E1008* *E1009* *E1010* *E1012* | 
					
						
							|  |  |  | 					*E1013* *E1029* *E1030* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | The following builtin types are supported: | 
					
						
							|  |  |  | 	bool | 
					
						
							|  |  |  | 	number | 
					
						
							|  |  |  | 	float | 
					
						
							|  |  |  | 	string | 
					
						
							|  |  |  | 	blob | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | 	list<{type}> | 
					
						
							|  |  |  | 	dict<{type}> | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	job | 
					
						
							|  |  |  | 	channel | 
					
						
							| 
									
										
										
										
											2020-03-14 08:19:51 +01:00
										 |  |  | 	func | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 	func: {type} | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | 	func({type}, ...) | 
					
						
							|  |  |  | 	func({type}, ...): {type} | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 	void | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Not supported yet: | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | 	tuple<a: {type}, b: {type}, ...> | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | These types can be used in declarations, but no simple value will actually | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | have the "void" type.  Trying to use a void (e.g. a function without a | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | return value) results in error *E1031*  *E1186* . | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | There is no array type, use list<{type}> instead.  For a list constant an | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | efficient implementation is used that avoids allocating lot of small pieces of | 
					
						
							|  |  |  | memory. | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | 							*E1005* *E1007* | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | A partial and function can be declared in more or less specific ways: | 
					
						
							|  |  |  | func				any kind of function reference, no type | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | 				checking for arguments or return value | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | func: void			any number and type of arguments, no return | 
					
						
							|  |  |  | 				value | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | func: {type}			any number and type of arguments with specific | 
					
						
							|  |  |  | 				return type | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func()				function with no argument, does not return a | 
					
						
							|  |  |  | 				value | 
					
						
							|  |  |  | func(): void			same | 
					
						
							|  |  |  | func(): {type}			function with no argument and return type | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | func({type})			function with argument type, does not return | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | 				a value | 
					
						
							| 
									
										
										
										
											2020-04-10 22:10:56 +02:00
										 |  |  | func({type}): {type}		function with argument type and return type | 
					
						
							|  |  |  | func(?{type})			function with type of optional argument, does | 
					
						
							|  |  |  | 				not return a value | 
					
						
							|  |  |  | func(...{type})			function with type of variable number of | 
					
						
							|  |  |  | 				arguments, does not return a value | 
					
						
							|  |  |  | func({type}, ?{type}, ...{type}): {type} | 
					
						
							|  |  |  | 				function with: | 
					
						
							|  |  |  | 				- type of mandatory argument | 
					
						
							|  |  |  | 				- type of optional argument | 
					
						
							|  |  |  | 				- type of variable number of arguments | 
					
						
							|  |  |  | 				- return type | 
					
						
							| 
									
										
										
										
											2020-04-03 21:59:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | If the return type is "void" the function does not return a value. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The reference can also be a |Partial|, in which case it stores extra arguments | 
					
						
							|  |  |  | and/or a dictionary, which are not visible to the caller.  Since they are | 
					
						
							|  |  |  | called in the same way the declaration is the same. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Custom types can be defined with `:type`: > | 
					
						
							|  |  |  | 	:type MyList list<string> | 
					
						
							| 
									
										
										
										
											2020-08-09 17:22:04 +02:00
										 |  |  | Custom types must start with a capital letter, to avoid name clashes with | 
					
						
							|  |  |  | builtin types added later, similarly to user functions. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | {not implemented yet} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | And classes and interfaces can be used as types: > | 
					
						
							|  |  |  | 	:class MyClass | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	:var mine: MyClass | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	:interface MyInterface | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	:var mine: MyInterface | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	:class MyTemplate<Targ> | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	:var mine: MyTemplate<number> | 
					
						
							|  |  |  | 	:var mine: MyTemplate<string> | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	:class MyInterface<Targ> | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	:var mine: MyInterface<number> | 
					
						
							|  |  |  | 	:var mine: MyInterface<string> | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | {not implemented yet} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Variable types and type casting	~ | 
					
						
							|  |  |  | 							*variable-types* | 
					
						
							| 
									
										
										
										
											2020-08-09 19:02:50 +02:00
										 |  |  | Variables declared in Vim9 script or in a `:def` function have a type, either | 
					
						
							|  |  |  | specified explicitly or inferred from the initialization. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Global, buffer, window and tab page variables do not have a specific type, the | 
					
						
							|  |  |  | value can be changed at any time, possibly changing the type.  Therefore, in | 
					
						
							|  |  |  | compiled code the "any" type is assumed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This can be a problem when the "any" type is undesired and the actual type is | 
					
						
							|  |  |  | expected to always be the same.  For example, when declaring a list: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var l: list<number> = [1, g:two] | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | At compile time Vim doesn't know the type of "g:two" and the expression type | 
					
						
							|  |  |  | becomes list<any>.  An instruction is generated to check the list type before | 
					
						
							|  |  |  | doing the assignment, which is a bit inefficient. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 						*type-casting* *E1104* | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | To avoid this, use a type cast: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var l: list<number> = [1, <number>g:two] | 
					
						
							| 
									
										
										
										
											2020-12-23 13:56:35 +01:00
										 |  |  | The compiled code will then only check that "g:two" is a number and give an | 
					
						
							|  |  |  | error if it isn't.  This is called type casting. | 
					
						
							| 
									
										
										
										
											2020-08-09 19:02:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | The syntax of a type cast is:  "<" {type} ">".  There cannot be white space | 
					
						
							|  |  |  | after the "<" or before the ">" (to avoid them being confused with | 
					
						
							|  |  |  | smaller-than and bigger-than operators). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The semantics is that, if needed, a runtime type check is performed.  The | 
					
						
							|  |  |  | value is not actually changed.  If you need to change the type, e.g. to change | 
					
						
							|  |  |  | it to a string, use the |string()| function.  Or use |str2nr()| to convert a | 
					
						
							|  |  |  | string to a number. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Type inference ~ | 
					
						
							|  |  |  | 							*type-inference* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | In general: Whenever the type is clear it can be omitted.  For example, when | 
					
						
							|  |  |  | declaring a variable and giving it a value: > | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var name = 0		# infers number type | 
					
						
							|  |  |  | 	var name = 'hello'	# infers string type | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 17:22:04 +02:00
										 |  |  | The type of a list and dictionary comes from the common type of the values. | 
					
						
							|  |  |  | If the values all have the same type, that type is used for the list or | 
					
						
							|  |  |  | dictionary.  If there is a mix of types, the "any" type is used. > | 
					
						
							|  |  |  | 	[1, 2, 3]	list<number> | 
					
						
							|  |  |  | 	['a', 'b', 'c']	list<string> | 
					
						
							|  |  |  | 	[1, 'x', 3]	list<any> | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | The common type of function references, if they do not all have the same | 
					
						
							|  |  |  | number of arguments, uses "(...)" to indicate the number of arguments is not | 
					
						
							|  |  |  | specified.  For example: > | 
					
						
							|  |  |  | 	def Foo(x: bool) | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	def Bar(x: bool, y: bool) | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	var funclist = [Foo, Bar] | 
					
						
							|  |  |  | 	echo funclist->typename() | 
					
						
							|  |  |  | Results in: | 
					
						
							|  |  |  | 	list<func(...)> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | For script-local variables in Vim9 script the type is checked, also when the | 
					
						
							|  |  |  | variable was declared in a legacy function. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 21:50:44 +00:00
										 |  |  | When a type has been declared this is attached to a List or Dictionary.  When | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | later some expression attempts to change the type an error will be given: > | 
					
						
							|  |  |  | 	var ll: list<number> = [1, 2, 3] | 
					
						
							| 
									
										
										
										
											2022-01-31 15:40:56 +00:00
										 |  |  | 	ll->extend(['x'])  # Error, 'x' is not a number | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 21:50:44 +00:00
										 |  |  | If the type is not declared then it is allowed to change: > | 
					
						
							| 
									
										
										
										
											2022-01-31 15:40:56 +00:00
										 |  |  | 	[1, 2, 3]->extend(['x'])  # result: [1, 2, 3, 'x'] | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 21:50:44 +00:00
										 |  |  | For a variable declaration an inferred type matters: > | 
					
						
							|  |  |  | 	var ll = [1, 2, 3] | 
					
						
							|  |  |  | 	ll->extend(['x'])  # Error, 'x' is not a number | 
					
						
							|  |  |  | That is because the declaration looks like a list of numbers, thus is | 
					
						
							|  |  |  | equivalent to: > | 
					
						
							|  |  |  | 	var ll: list<number> = [1, 2, 3] | 
					
						
							|  |  |  | If you do want a more permissive list you need to declare the type: > | 
					
						
							|  |  |  | 	var ll: list<any = [1, 2, 3] | 
					
						
							|  |  |  | 	ll->extend(['x'])  # OK | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Stricter type checking ~ | 
					
						
							|  |  |  | 							*type-checking* | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | In legacy Vim script, where a number was expected, a string would be | 
					
						
							|  |  |  | automatically converted to a number.  This was convenient for an actual number | 
					
						
							| 
									
										
										
										
											2021-04-07 21:07:20 +02:00
										 |  |  | such as "123", but leads to unexpected problems (and no error message) if the | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | string doesn't start with a number.  Quite often this leads to hard-to-find | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | bugs. e.g.: > | 
					
						
							|  |  |  | 	echo 123 == '123' | 
					
						
							|  |  |  | <	1 ~ | 
					
						
							|  |  |  | With an accidental space: > | 
					
						
							|  |  |  | 	echo 123 == ' 123' | 
					
						
							|  |  |  | <	0 ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 							*E1206* *E1210* *E1212* | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | In Vim9 script this has been made stricter.  In most places it works just as | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | before if the value used matches the expected type.  There will sometimes be | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | an error, thus breaking backwards compatibility.  For example: | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | - Using a number other than 0 or 1 where a boolean is expected.  *E1023* | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | - Using a string value when setting a number option. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | - Using a number where a string is expected.   *E1024* *E1105* | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-16 15:23:36 +01:00
										 |  |  | One consequence is that the item type of a list or dict given to |map()| must | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | not change, if the type was declared.  This will give an error in Vim9 | 
					
						
							|  |  |  | script: > | 
					
						
							|  |  |  | 	var mylist: list<number> = [1, 2, 3] | 
					
						
							|  |  |  | 	echo map(mylist, (i, v) => 'item ' .. i) | 
					
						
							|  |  |  | <	E1012: Type mismatch; expected number but got string in map() ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Instead use |mapnew()|, it creates a new list: > | 
					
						
							|  |  |  | 	var mylist: list<number> = [1, 2, 3] | 
					
						
							|  |  |  | 	echo mapnew(mylist, (i, v) => 'item ' .. i) | 
					
						
							|  |  |  | <	['item 0', 'item 1', 'item 2'] ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If the item type was not declared or determined to be "any" it can change to a | 
					
						
							|  |  |  | more specific type.  E.g. when a list of mixed types gets changed to a list of | 
					
						
							|  |  |  | strings: > | 
					
						
							| 
									
										
										
										
											2021-07-07 20:26:08 +02:00
										 |  |  | 	var mylist = [1, 2.0, '3'] | 
					
						
							|  |  |  | 	# typename(mylist) == "list<any>" | 
					
						
							|  |  |  | 	map(mylist, (i, v) => 'item ' .. i) | 
					
						
							|  |  |  | 	# typename(mylist) == "list<string>", no error | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | There is a subtle difference between using a list constant directly and | 
					
						
							| 
									
										
										
										
											2022-02-22 20:43:36 +00:00
										 |  |  | through a variable declaration.  Because of type inference, when using a list | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | constant to initialize a variable, this also sets the declared type: > | 
					
						
							|  |  |  | 	var mylist = [1, 2, 3] | 
					
						
							|  |  |  | 	# typename(mylist) == "list<number>" | 
					
						
							|  |  |  | 	echo map(mylist, (i, v) => 'item ' .. i)  # Error! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When using the list constant directly, the type is not declared and is allowed | 
					
						
							|  |  |  | to change: > | 
					
						
							|  |  |  | 	echo map([1, 2, 3], (i, v) => 'item ' .. i)  # OK | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The reasoning behind this is that when a type is declared and the list is | 
					
						
							|  |  |  | passed around and changed, the declaration must always hold.  So that you can | 
					
						
							|  |  |  | rely on the type to match the declared type.  For a constant this is not | 
					
						
							|  |  |  | needed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								*E1158* | 
					
						
							| 
									
										
										
										
											2021-02-27 16:38:07 +01:00
										 |  |  | Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use | 
					
						
							| 
									
										
										
										
											2022-02-20 19:48:20 +00:00
										 |  |  | |flattennew()| instead.  Since |flatten()| is intended to always change the | 
					
						
							|  |  |  | type, it can not be used in Vim9 script. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 			 *E1211* *E1217* *E1218* *E1219* *E1220* *E1221* | 
					
						
							|  |  |  | 			 *E1222* *E1223* *E1224* *E1225* *E1226* *E1227* | 
					
						
							|  |  |  | 			 *E1228* *E1238* *E1250* *E1251* *E1252* *E1253* | 
					
						
							|  |  |  | 			 *E1256* | 
					
						
							|  |  |  | Types are checked for most builtin functions to make it easier to spot | 
					
						
							|  |  |  | mistakes. | 
					
						
							| 
									
										
										
										
											2021-01-11 19:40:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 5. Namespace, Import and Export | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 					*vim9script* *vim9-export* *vim9-import* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | A Vim9 script can be written to be imported.  This means that some items are | 
					
						
							|  |  |  | intentionally exported, made available to other scripts.  When the exporting | 
					
						
							|  |  |  | script is imported in another script, these exported items can then be used in | 
					
						
							|  |  |  | that script.  All the other items remain script-local in the exporting script | 
					
						
							|  |  |  | and cannot be accessed by the importing script. | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This mechanism exists for writing a script that can be sourced (imported) by | 
					
						
							|  |  |  | other scripts, while making sure these other scripts only have access to what | 
					
						
							|  |  |  | you want them to.  This also avoids using the global namespace, which has a | 
					
						
							|  |  |  | risc of name collisions.  For example when you have two plugins with similar | 
					
						
							|  |  |  | functionality. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | You can cheat by using the global namespace explicitly.  That should be done | 
					
						
							|  |  |  | only for things that really are global. | 
					
						
							| 
									
										
										
										
											2020-08-30 17:20:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Namespace ~ | 
					
						
							| 
									
										
										
										
											2020-12-28 20:53:21 +01:00
										 |  |  | 							*vim9-namespace* | 
					
						
							| 
									
										
										
										
											2020-02-04 22:53:05 +01:00
										 |  |  | To recognize a file that can be imported the `vim9script` statement must | 
					
						
							| 
									
										
										
										
											2021-02-17 21:57:03 +01:00
										 |  |  | appear as the first statement in the file (see |vim9-mix| for an exception). | 
					
						
							|  |  |  | It tells Vim to interpret the script in its own namespace, instead of the | 
					
						
							|  |  |  | global namespace.  If a file starts with: > | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	vim9script | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	var myvar = 'yes' | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Then "myvar" will only exist in this file.  While without `vim9script` it would | 
					
						
							|  |  |  | be available as `g:myvar` from any other script and function. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | 							*E1101* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | The variables at the file level are very much like the script-local "s:" | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | variables in legacy Vim script, but the "s:" is omitted.  And they cannot be | 
					
						
							|  |  |  | deleted. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-20 19:52:53 +02:00
										 |  |  | In Vim9 script the global "g:" namespace can still be used as before.  And the | 
					
						
							|  |  |  | "w:", "b:" and "t:" namespaces.  These have in common that variables are not | 
					
						
							|  |  |  | declared and they can be deleted. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | A side effect of `:vim9script` is that the 'cpoptions' option is set to the | 
					
						
							|  |  |  | Vim default value, like with: > | 
					
						
							|  |  |  | 	:set cpo&vim | 
					
						
							|  |  |  | One of the effects is that |line-continuation| is always enabled. | 
					
						
							| 
									
										
										
										
											2021-03-17 17:46:00 +01:00
										 |  |  | The original value of 'cpoptions' is restored at the end of the script, while | 
					
						
							|  |  |  | flags added or removed in the script are also added to or removed from the | 
					
						
							|  |  |  | original value to get the same effect.  The order of flags may change. | 
					
						
							| 
									
										
										
										
											2021-12-26 12:07:30 +00:00
										 |  |  | In the |vimrc| file sourced on startup this does not happen. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 21:57:03 +01:00
										 |  |  | 							*vim9-mix* | 
					
						
							|  |  |  | There is one way to use both legacy and Vim9 syntax in one script file: > | 
					
						
							|  |  |  | 	" comments may go here | 
					
						
							|  |  |  | 	if !has('vim9script') | 
					
						
							|  |  |  | 	   " legacy script commands go here | 
					
						
							|  |  |  | 	   finish | 
					
						
							|  |  |  | 	endif | 
					
						
							|  |  |  | 	vim9script | 
					
						
							|  |  |  | 	# Vim9 script commands go here | 
					
						
							|  |  |  | This allows for writing a script that takes advantage of the Vim9 script | 
					
						
							| 
									
										
										
										
											2021-02-27 16:38:07 +01:00
										 |  |  | syntax if possible, but will also work on a Vim version without it. | 
					
						
							| 
									
										
										
										
											2021-02-17 21:57:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | This can only work in two ways: | 
					
						
							|  |  |  | 1. The "if" statement evaluates to false, the commands up to `endif` are | 
					
						
							|  |  |  |    skipped and `vim9script` is then the first command actually executed. | 
					
						
							|  |  |  | 2. The "if" statement evaluates to true, the commands up to `endif` are | 
					
						
							|  |  |  |    executed and `finish` bails out before reaching `vim9script`. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Export ~ | 
					
						
							|  |  |  | 							*:export* *:exp* | 
					
						
							| 
									
										
										
										
											2020-07-26 17:00:44 +02:00
										 |  |  | Exporting an item can be written as: > | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	export const EXPORTED_CONST = 1234 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 	export var someValue = ... | 
					
						
							|  |  |  | 	export final someValue = ... | 
					
						
							|  |  |  | 	export const someValue = ... | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	export def MyFunc() ... | 
					
						
							|  |  |  | 	export class MyClass ... | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | 	export interface MyClass ... | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | <							*E1043* *E1044* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | As this suggests, only constants, variables, `:def` functions and classes can | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | be exported. {not implemented yet: class, interface} | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 							*E1042* | 
					
						
							|  |  |  | `:export` can only be used in Vim9 script, at the script level. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Import ~ | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 					*:import* *:imp* *E1094* *E1047* *E1262* | 
					
						
							|  |  |  | 					*E1048* *E1049* *E1053* *E1071* *E1236* | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | The exported items can be imported in another Vim9 script: > | 
					
						
							|  |  |  | 	import "myscript.vim" | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | This makes each item available as "myscript.item". | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 						*:import-as* *E1257* *E1261* | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | In case the name is long or ambiguous, another name can be specified: > | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | 	import "thatscript.vim" as that | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | <						*E1060* *E1258* *E1259* *E1260* | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | Then you can use "that.EXPORTED_CONST", "that.someValue", etc.  You are free | 
					
						
							|  |  |  | to choose the name "that".  Use something that will be recognized as referring | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | to the imported script.  Avoid command names, command modifiers and builtin | 
					
						
							|  |  |  | function names, because the name will shadow them. | 
					
						
							|  |  |  | If the name starts with a capital letter it can also shadow global user | 
					
						
							|  |  |  | commands and functions.  Also, you cannot use the name for something else in | 
					
						
							|  |  |  | the script, such as a function or variable name. | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | In case the dot in the name is undesired, a local reference can be made for a | 
					
						
							|  |  |  | function: > | 
					
						
							|  |  |  | 	var LongFunc = that.LongFuncName | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This also works for constants: > | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | 	const MAXLEN = that.MAX_LEN_OF_NAME | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | This does not work for variables, since the value would be copied once and | 
					
						
							|  |  |  | when changing the variable the copy will change, not the original variable. | 
					
						
							|  |  |  | You will need to use the full name, with the dot. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-23 12:07:04 +00:00
										 |  |  | The full syntax of the command is: | 
					
						
							|  |  |  | 	import {filename} [as {name}] | 
					
						
							|  |  |  | Where {filename} is an expression that must evaluate to a string.  Without the | 
					
						
							|  |  |  | "as {name}" part it must end in ".vim".  {name} must consist of letters, | 
					
						
							|  |  |  | digits and '_', like |internal-variables|. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | `:import` can also be used in legacy Vim script.  The imported items still | 
					
						
							|  |  |  | become script-local, even when the "s:" prefix is not given. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-18 18:21:38 +02:00
										 |  |  | `:import` can not be used in a function.  Imported items are intended to exist | 
					
						
							|  |  |  | at the script level and only imported once. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | The script name after `import` can be: | 
					
						
							|  |  |  | - A relative path, starting "." or "..".  This finds a file relative to the | 
					
						
							|  |  |  |   location of the script file itself.  This is useful to split up a large | 
					
						
							|  |  |  |   plugin into several files. | 
					
						
							|  |  |  | - An absolute path, starting with "/" on Unix or "D:/" on MS-Windows.  This | 
					
						
							| 
									
										
										
										
											2020-10-26 21:12:46 +01:00
										 |  |  |   will rarely be used. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | - A path not being relative or absolute.  This will be found in the | 
					
						
							|  |  |  |   "import" subdirectories of 'runtimepath' entries.  The name will usually be | 
					
						
							|  |  |  |   longer and unique, to avoid loading the wrong file. | 
					
						
							| 
									
										
										
										
											2021-08-14 21:25:52 +02:00
										 |  |  |   Note that "after/import" is not used. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | If the name does not end in ".vim" then the use of "as name" is required. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Once a vim9 script file has been imported, the result is cached and used the | 
					
						
							|  |  |  | next time the same script is imported.  It will not be read again. | 
					
						
							| 
									
										
										
										
											2022-01-06 21:10:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | It is not allowed to import the same script twice, also when using two | 
					
						
							|  |  |  | different "as" names. | 
					
						
							| 
									
										
										
										
											2022-01-08 21:51:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | When using the imported name the dot and the item name must be in the same | 
					
						
							|  |  |  | line, there can be no line break: > | 
					
						
							|  |  |  | 	echo that. | 
					
						
							|  |  |  | 		name   # Error! | 
					
						
							|  |  |  | 	echo that | 
					
						
							|  |  |  | 		.name  # Error! | 
					
						
							|  |  |  | <							*:import-cycle* | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | The `import` commands are executed when encountered.  If script A imports | 
					
						
							|  |  |  | script B, and B (directly or indirectly) imports A, this will be skipped over. | 
					
						
							|  |  |  | At this point items in A after "import B" will not have been processed and | 
					
						
							|  |  |  | defined yet.  Therefore cyclic imports can exist and not result in an error | 
					
						
							|  |  |  | directly, but may result in an error for items in A after "import B" not being | 
					
						
							|  |  |  | defined.  This does not apply to autoload imports, see the next section. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | Importing an autoload script ~ | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  | 							*vim9-autoload* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | For optimal startup speed, loading scripts should be postponed until they are | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  | actually needed.  Using the autoload mechanism is recommended: | 
					
						
							| 
									
										
										
										
											2022-02-04 16:09:54 +00:00
										 |  |  | 							*E1264* | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 1. In the plugin define user commands, functions and/or mappings that refer to | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  |    items imported from an autoload script. > | 
					
						
							|  |  |  | 	import autoload 'for/search.vim' | 
					
						
							|  |  |  | 	command -nargs=1 SearchForStuff search.Stuff(<f-args>) | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | <   This goes in .../plugin/anyname.vim.  "anyname.vim" can be freely chosen. | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  |    The "SearchForStuff" command is now available to the user. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  |    The "autoload" argument to `:import` means that the script is not loaded | 
					
						
							|  |  |  |    until one of the items is actually used.  The script will be found under | 
					
						
							|  |  |  |    the "autoload" directory in 'runtimepath' instead of the "import" | 
					
						
							|  |  |  |    directory. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2. In the autoload script put the bulk of the code. > | 
					
						
							| 
									
										
										
										
											2022-01-18 16:26:24 +00:00
										 |  |  | 	vim9script | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  | 	export def Stuff(arg: string) | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	  ... | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  | <   This goes in .../autoload/for/search.vim. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-18 16:26:24 +00:00
										 |  |  |    Putting the "search.vim" script under the "/autoload/for/" directory has | 
					
						
							|  |  |  |    the effect that "for#search#" will be prefixed to every exported item.  The | 
					
						
							|  |  |  |    prefix is obtained from the file name, as you would to manually in a | 
					
						
							|  |  |  |    legacy autoload script.  Thus the exported function can be found with | 
					
						
							|  |  |  |    "for#search#Stuff", but you would normally use `import autoload` and not | 
					
						
							| 
									
										
										
										
											2022-03-19 15:18:53 +00:00
										 |  |  |    use the prefix (which has the side effect of loading the autoload script | 
					
						
							|  |  |  |    when compiling a function that encounters this name). | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    You can split up the functionality and import other scripts from the | 
					
						
							|  |  |  |    autoload script as you like.  This way you can share code between plugins. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | For defining a mapping that uses the imported autoload script the special key | 
					
						
							|  |  |  | |<ScriptCmd>| is useful.  It allows for a command in a mapping to use the | 
					
						
							|  |  |  | script context of where the mapping was defined. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-12 21:34:49 +02:00
										 |  |  | When compiling a `:def` function and a function in an autoload script is | 
					
						
							|  |  |  | encountered, the script is not loaded until the `:def` function is called. | 
					
						
							| 
									
										
										
										
											2022-01-09 21:36:37 +00:00
										 |  |  | This also means you get any errors only at runtime, since the argument and | 
					
						
							| 
									
										
										
										
											2022-03-19 15:18:53 +00:00
										 |  |  | return types are not known yet.  If you would use the name with '#' characters | 
					
						
							|  |  |  | then the autoload script IS loaded. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Be careful to not refer to an item in an autoload script that does trigger | 
					
						
							|  |  |  | loading it unintentionally.  For example, when setting an option that takes a | 
					
						
							|  |  |  | function name, make sure to use a string, not a function reference: > | 
					
						
							|  |  |  | 	import autoload 'qftf.vim' | 
					
						
							|  |  |  | 	&quickfixtextfunc = 'qftf.Func'  # autoload script NOT loaded | 
					
						
							|  |  |  | 	&quickfixtextfunc = qftf.Func    # autoload script IS loaded | 
					
						
							|  |  |  | On the other hand, it can be useful to load the script early, at a time when | 
					
						
							|  |  |  | any errors should be given. | 
					
						
							| 
									
										
										
										
											2020-08-12 21:34:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | For testing the |test_override()| function can be used to have the | 
					
						
							|  |  |  | `import autoload` load the script right away, so that the items and types can | 
					
						
							|  |  |  | be checked without waiting for them to be actually used: > | 
					
						
							|  |  |  | 	test_override('autoload', 1) | 
					
						
							|  |  |  | Reset it later with: > | 
					
						
							|  |  |  | 	test_override('autoload', 0) | 
					
						
							|  |  |  | Or: > | 
					
						
							|  |  |  | 	test_override('ALL', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Import in legacy Vim script ~ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | If an `import` statement is used in legacy Vim script, the script-local "s:" | 
					
						
							| 
									
										
										
										
											2022-01-16 14:46:06 +00:00
										 |  |  | namespace will be used for the imported items, even when "s:" is not | 
					
						
							|  |  |  | specified. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 6. Future work: classes					*vim9-classes* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Above "class" was mentioned a few times, but it has not been implemented yet. | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Most of Vim9 script can be created without this functionality, and since | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | implementing classes is going to be a lot of work, it is left for the future. | 
					
						
							|  |  |  | For now we'll just make sure classes can be added later. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Thoughts: | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | - `class` / `endclass`, the whole class must be in one file | 
					
						
							|  |  |  | - Class names are always CamelCase (to avoid a name clash with builtin types) | 
					
						
							|  |  |  | - A single constructor called "constructor" | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | - Single inheritance with `class ThisClass extends BaseClass` | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | - `abstract class` (class with incomplete implementation) | 
					
						
							|  |  |  | - `interface` / `endinterface` (abstract class without any implementation) | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | - `class SomeClass implements SomeInterface` | 
					
						
							|  |  |  | - Generics for class: `class <Tkey, Tentry>` | 
					
						
							|  |  |  | - Generics for function: `def <Tkey> GetLast(key: Tkey)` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | Again, much of this is from TypeScript with a slightly different syntax. | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Some things that look like good additions: | 
					
						
							|  |  |  | - Use a class as an interface (like Dart) | 
					
						
							|  |  |  | - Extend a class with methods, using an import (like Dart) | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | - Mixins | 
					
						
							|  |  |  | - For testing: Mock mechanism | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | An important class that will be provided is "Promise".  Since Vim is single | 
					
						
							|  |  |  | threaded, connecting asynchronous operations is a natural way of allowing | 
					
						
							|  |  |  | plugins to do their work without blocking the user.  It's a uniform way to | 
					
						
							|  |  |  | invoke callbacks and handle timeouts and errors. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-08 21:35:07 +00:00
										 |  |  | Some commands have already been reserved: | 
					
						
							|  |  |  | 	*:class* | 
					
						
							|  |  |  | 	*:endclass* | 
					
						
							|  |  |  | 	*:abstract* | 
					
						
							|  |  |  | 	*:enum* | 
					
						
							|  |  |  | 	*:endenum* | 
					
						
							|  |  |  | 	*:interface* | 
					
						
							|  |  |  | 	*:endinterface* | 
					
						
							|  |  |  | 	*:static* | 
					
						
							|  |  |  | 	*:type* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | Some examples: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	abstract class Person  | 
					
						
							|  |  |  | 	    static const prefix = 'xxx' | 
					
						
							|  |  |  | 	    var name: string | 
					
						
							|  |  |  | 	     | 
					
						
							|  |  |  | 	    def constructor(name: string) | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 		this.name = name | 
					
						
							| 
									
										
										
										
											2021-06-12 14:53:05 +02:00
										 |  |  | 	    enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    def display(): void | 
					
						
							|  |  |  | 		echo name | 
					
						
							|  |  |  | 	    enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    abstract def find(string): Person | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 9. Rationale						*vim9-rationale* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The :def command ~ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Plugin writers have asked for much faster Vim script.  Investigations have | 
					
						
							| 
									
										
										
										
											2020-02-04 22:53:05 +01:00
										 |  |  | shown that keeping the existing semantics of function calls make this close to | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | impossible, because of the overhead involved with calling a function, setting | 
					
						
							|  |  |  | up the local function scope and executing lines.  There are many details that | 
					
						
							|  |  |  | need to be handled, such as error messages and exceptions.  The need to create | 
					
						
							|  |  |  | a dictionary for a: and l: scopes, the a:000 list and several others add too | 
					
						
							|  |  |  | much overhead that cannot be avoided. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Therefore the `:def` method to define a new-style function had to be added, | 
					
						
							|  |  |  | which allows for a function with different semantics.  Most things still work | 
					
						
							|  |  |  | as before, but some parts do not.  A new way to define a function was | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | considered the best way to separate the legacy style code from Vim9 style code. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Using "def" to define a function comes from Python. Other languages use | 
					
						
							|  |  |  | "function" which clashes with legacy Vim script. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Type checking ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When compiling lines of Vim commands into instructions as much as possible | 
					
						
							|  |  |  | should be done at compile time.  Postponing it to runtime makes the execution | 
					
						
							|  |  |  | slower and means mistakes are found only later.  For example, when | 
					
						
							|  |  |  | encountering the "+" character and compiling this into a generic add | 
					
						
							| 
									
										
										
										
											2021-01-18 19:55:44 +01:00
										 |  |  | instruction, at runtime the instruction would have to inspect the type of the | 
					
						
							|  |  |  | arguments and decide what kind of addition to do.  And when the type is | 
					
						
							|  |  |  | dictionary throw an error.  If the types are known to be numbers then an "add | 
					
						
							|  |  |  | number" instruction can be used, which is faster.  The error can be given at | 
					
						
							|  |  |  | compile time, no error handling is needed at runtime, since adding two numbers | 
					
						
							|  |  |  | cannot fail. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | The syntax for types, using <type> for compound types, is similar to Java.  It | 
					
						
							|  |  |  | is easy to understand and widely used.  The type names are what were used in | 
					
						
							|  |  |  | Vim before, with some additions such as "void" and "bool". | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | Removing clutter and weirdness ~ | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | Once decided that `:def` functions have different syntax than legacy functions, | 
					
						
							|  |  |  | we are free to add improvements to make the code more familiar for users who | 
					
						
							|  |  |  | know popular programming languages.  In other words: remove weird things that | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | only Vim does. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | We can also remove clutter, mainly things that were done to make Vim script | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | backwards compatible with the good old Vi commands. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | Examples: | 
					
						
							|  |  |  | - Drop `:call` for calling a function and `:eval` for manipulating data. | 
					
						
							|  |  |  | - Drop using a leading backslash for line continuation, automatically figure | 
					
						
							|  |  |  |   out where an expression ends. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | However, this does require that some things need to change: | 
					
						
							|  |  |  | - Comments start with # instead of ", to avoid confusing them with strings. | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  |   This is good anyway, it is known from several popular languages. | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | - Ex command ranges need to be prefixed with a colon, to avoid confusion with | 
					
						
							|  |  |  |   expressions (single quote can be a string or a mark, "/" can be divide or a | 
					
						
							|  |  |  |   search command, etc.). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Goal is to limit the differences.  A good criteria is that when the old syntax | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | is accidentally used you are very likely to get an error message. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Syntax and semantics from popular languages ~ | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Script writers have complained that the Vim script syntax is unexpectedly | 
					
						
							|  |  |  | different from what they are used to.  To reduce this complaint popular | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | languages are used as an example.  At the same time, we do not want to abandon | 
					
						
							|  |  |  | the well-known parts of legacy Vim script. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | For many things TypeScript is followed.  It's a recent language that is | 
					
						
							|  |  |  | gaining popularity and has similarities with Vim script.  It also has a | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | mix of static typing (a variable always has a known value type) and dynamic | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | typing (a variable can have different types, this changes at runtime).  Since | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | legacy Vim script is dynamically typed and a lot of existing functionality | 
					
						
							|  |  |  | (esp. builtin functions) depends on that, while static typing allows for much | 
					
						
							|  |  |  | faster execution, we need to have this mix in Vim9 script. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | There is no intention to completely match TypeScript syntax and semantics.  We | 
					
						
							|  |  |  | just want to take those parts that we can use for Vim and we expect Vim users | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | will be happy with.  TypeScript is a complex language with its own history, | 
					
						
							|  |  |  | advantages and disadvantages.  To get an idea of the disadvantages read the | 
					
						
							|  |  |  | book: "JavaScript: The Good Parts".  Or find the article "TypeScript: the good | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | parts" and read the "Things to avoid" section. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | People familiar with other languages (Java, Python, etc.) will also find | 
					
						
							|  |  |  | things in TypeScript that they do not like or do not understand.  We'll try to | 
					
						
							|  |  |  | avoid those things. | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Specific items from TypeScript we avoid: | 
					
						
							|  |  |  | - Overloading "+", using it both for addition and string concatenation.  This | 
					
						
							|  |  |  |   goes against legacy Vim script and often leads to mistakes.  For that reason | 
					
						
							|  |  |  |   we will keep using ".." for string concatenation.  Lua also uses ".." this | 
					
						
							|  |  |  |   way.  And it allows for conversion to string for more values. | 
					
						
							|  |  |  | - TypeScript can use an expression like "99 || 'yes'" in a condition, but | 
					
						
							|  |  |  |   cannot assign the value to a boolean.  That is inconsistent and can be | 
					
						
							|  |  |  |   annoying.  Vim recognizes an expression with && or || and allows using the | 
					
						
							| 
									
										
										
										
											2021-12-26 18:09:31 +00:00
										 |  |  |   result as a bool.  The |falsy-operator| was added for the mechanism to use a | 
					
						
							|  |  |  |   default value. | 
					
						
							| 
									
										
										
										
											2020-09-14 21:39:44 +02:00
										 |  |  | - TypeScript considers an empty string as Falsy, but an empty list or dict as | 
					
						
							|  |  |  |   Truthy.  That is inconsistent.  In Vim an empty list and dict are also | 
					
						
							|  |  |  |   Falsy. | 
					
						
							|  |  |  | - TypeScript has various "Readonly" types, which have limited usefulness, | 
					
						
							|  |  |  |   since a type cast can remove the immutable nature.  Vim locks the value, | 
					
						
							|  |  |  |   which is more flexible, but is only checked at runtime. | 
					
						
							| 
									
										
										
										
											2022-01-29 22:20:48 +00:00
										 |  |  | - TypeScript has a complicated "import" statement that does not match how the | 
					
						
							|  |  |  |   Vim import mechanism works.  A much simpler mechanism is used instead, which | 
					
						
							|  |  |  |   matches that the imported script is only sourced once. | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Declarations ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Legacy Vim script uses `:let` for every assignment, while in Vim9 declarations | 
					
						
							|  |  |  | are used.  That is different, thus it's good to use a different command: | 
					
						
							|  |  |  | `:var`.  This is used in many languages.  The semantics might be slightly | 
					
						
							|  |  |  | different, but it's easily recognized as a declaration. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 14:36:24 +01:00
										 |  |  | Using `:const`  for constants is common, but the semantics varies.  Some | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | languages only make the variable immutable, others also make the value | 
					
						
							|  |  |  | immutable.  Since "final" is well known from Java for only making the variable | 
					
						
							|  |  |  | immutable we decided to use that.  And then `:const` can be used for making | 
					
						
							|  |  |  | both immutable.  This was also used in legacy Vim script and the meaning is | 
					
						
							|  |  |  | almost the same. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | What we end up with is very similar to Dart: > | 
					
						
							|  |  |  | 	:var name	# mutable variable and value | 
					
						
							|  |  |  | 	:final name	# immutable variable, mutable value | 
					
						
							|  |  |  | 	:const name	# immutable variable and value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Since legacy and Vim9 script will be mixed and global variables will be | 
					
						
							|  |  |  | shared, optional type checking is desirable.  Also, type inference will avoid | 
					
						
							|  |  |  | the need for specifying the type in many cases.  The TypeScript syntax fits | 
					
						
							|  |  |  | best for adding types to declarations: > | 
					
						
							|  |  |  | 	var name: string	  # string type is specified | 
					
						
							|  |  |  | 	... | 
					
						
							|  |  |  | 	name = 'John' | 
					
						
							|  |  |  | 	const greeting = 'hello'  # string type is inferred | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is how we put types in a declaration: > | 
					
						
							|  |  |  | 	var mylist: list<string> | 
					
						
							|  |  |  | 	final mylist: list<string> = ['foo'] | 
					
						
							|  |  |  | 	def Func(arg1: number, arg2: string): bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Two alternatives were considered: | 
					
						
							|  |  |  | 1. Put the type before the name, like Dart: > | 
					
						
							|  |  |  | 	var list<string> mylist | 
					
						
							|  |  |  | 	final list<string> mylist = ['foo'] | 
					
						
							|  |  |  | 	def Func(number arg1, string arg2) bool | 
					
						
							|  |  |  | 2. Put the type after the variable name, but do not use a colon, like Go: > | 
					
						
							|  |  |  | 	var mylist list<string> | 
					
						
							|  |  |  | 	final mylist list<string> = ['foo'] | 
					
						
							|  |  |  | 	def Func(arg1 number, arg2 string) bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The first is more familiar for anyone used to C or Java.  The second one | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | doesn't really have an advantage over the first, so let's discard the second. | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Since we use type inference the type can be left out when it can be inferred | 
					
						
							|  |  |  | from the value.  This means that after `var` we don't know if a type or a name | 
					
						
							|  |  |  | follows.  That makes parsing harder, not only for Vim but also for humans. | 
					
						
							|  |  |  | Also, it will not be allowed to use a variable name that could be a type name, | 
					
						
							|  |  |  | using `var string string` is too confusing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The chosen syntax, using a colon to separate the name from the type, adds | 
					
						
							|  |  |  | punctuation, but it actually makes it easier to recognize the parts of a | 
					
						
							|  |  |  | declaration. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Expressions ~ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | Expression evaluation was already close to what other languages are doing. | 
					
						
							|  |  |  | Some details are unexpected and can be improved.  For example a boolean | 
					
						
							|  |  |  | condition would accept a string, convert it to a number and check if the | 
					
						
							|  |  |  | number is non-zero.  This is unexpected and often leads to mistakes, since | 
					
						
							|  |  |  | text not starting with a number would be converted to zero, which is | 
					
						
							| 
									
										
										
										
											2020-10-26 21:12:46 +01:00
										 |  |  | considered false.  Thus using a string for a condition would often not give an | 
					
						
							|  |  |  | error and be considered false.  That is confusing. | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 14:36:24 +01:00
										 |  |  | In Vim9 type checking is stricter to avoid mistakes.  Where a condition is | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | used, e.g. with the `:if` command and the `||` operator, only boolean-like | 
					
						
							|  |  |  | values are accepted: | 
					
						
							|  |  |  | 	true:  `true`, `v:true`, `1`, `0 < 9` | 
					
						
							|  |  |  | 	false: `false`, `v:false`, `0`, `0 > 9` | 
					
						
							|  |  |  | Note that the number zero is false and the number one is true.  This is more | 
					
						
							| 
									
										
										
										
											2020-10-26 21:12:46 +01:00
										 |  |  | permissive than most other languages.  It was done because many builtin | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | functions return these values. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you have any type of value and want to use it as a boolean, use the `!!` | 
					
						
							|  |  |  | operator: | 
					
						
							| 
									
										
										
										
											2021-05-30 20:54:13 +02:00
										 |  |  | 	true: `!!'text'`, `!![99]`, `!!{'x': 1}`, `!!99` | 
					
						
							| 
									
										
										
										
											2020-10-11 13:57:40 +02:00
										 |  |  | 	false: `!!''`, `!![]`, `!!{}` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | From a language like JavaScript we have this handy construct: > | 
					
						
							|  |  |  | 	GetName() || 'unknown' | 
					
						
							|  |  |  | However, this conflicts with only allowing a boolean for a condition. | 
					
						
							|  |  |  | Therefore the "??" operator was added: > | 
					
						
							|  |  |  | 	GetName() ?? 'unknown' | 
					
						
							|  |  |  | Here you can explicitly express your intention to use the value as-is and not | 
					
						
							|  |  |  | result in a boolean. This is called the |falsy-operator|. | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | Import and Export ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A problem of legacy Vim script is that by default all functions and variables | 
					
						
							|  |  |  | are global.  It is possible to make them script-local, but then they are not | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | available in other scripts.  This defies the concept of a package that only | 
					
						
							|  |  |  | exports selected items and keeps the rest local. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:55:18 +02:00
										 |  |  | In Vim9 script a mechanism very similar to the JavaScript import and export | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | mechanism is supported.  It is a variant to the existing `:source` command | 
					
						
							|  |  |  | that works like one would expect: | 
					
						
							|  |  |  | - Instead of making everything global by default, everything is script-local, | 
					
						
							|  |  |  |   unless exported. | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | - When importing a script the symbols that are imported are explicitly listed, | 
					
						
							|  |  |  |   avoiding name conflicts and failures if functionality is added later. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | - The mechanism allows for writing a big, long script with a very clear API: | 
					
						
							|  |  |  |   the exported function(s) and class(es). | 
					
						
							|  |  |  | - By using relative paths loading can be much faster for an import inside of a | 
					
						
							|  |  |  |   package, no need to search many directories. | 
					
						
							|  |  |  | - Once an import has been used, it can be cached and loading it again can be | 
					
						
							|  |  |  |   avoided. | 
					
						
							|  |  |  | - The Vim-specific use of "s:" to make things script-local can be dropped. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | When sourcing a Vim9 script from a legacy script, only the items defined | 
					
						
							|  |  |  | globally can be used, not the exported items.  Alternatives considered: | 
					
						
							|  |  |  | - All the exported items become available as script-local items.  This makes | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   it uncontrollable what items get defined and likely soon leads to trouble. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | - Use the exported items and make them global.  Disadvantage is that it's then | 
					
						
							|  |  |  |   not possible to avoid name clashes in the global namespace. | 
					
						
							|  |  |  | - Completely disallow sourcing a Vim9 script, require using `:import`.  That | 
					
						
							|  |  |  |   makes it difficult to use scripts for testing, or sourcing them from the | 
					
						
							|  |  |  |   command line to try them out. | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | Note that you can also use `:import` in legacy Vim script, see above. | 
					
						
							| 
									
										
										
										
											2020-06-14 17:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | Compiling functions early ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Functions are compiled when called or when `:defcompile` is used.  Why not | 
					
						
							|  |  |  | compile them early, so that syntax and type errors are reported early? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The functions can't be compiled right away when encountered, because there may | 
					
						
							|  |  |  | be forward references to functions defined later.  Consider defining functions | 
					
						
							|  |  |  | A, B and C, where A calls B, B calls C, and C calls A again.  It's impossible | 
					
						
							|  |  |  | to reorder the functions to avoid forward references. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An alternative would be to first scan through the file to locate items and | 
					
						
							|  |  |  | figure out their type, so that forward references are found, and only then | 
					
						
							|  |  |  | execute the script and compile the functions.  This means the script has to be | 
					
						
							|  |  |  | parsed twice, which is slower, and some conditions at the script level, such | 
					
						
							|  |  |  | as checking if a feature is supported, are hard to use.  An attempt was made | 
					
						
							|  |  |  | to see if it works, but it turned out to be impossible to make work nicely. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | It would be possible to compile all the functions at the end of the script. | 
					
						
							|  |  |  | The drawback is that if a function never gets called, the overhead of | 
					
						
							|  |  |  | compiling it counts anyway.  Since startup speed is very important, in most | 
					
						
							|  |  |  | cases it's better to do it later and accept that syntax and type errors are | 
					
						
							|  |  |  | only reported then.  In case these errors should be found early, e.g. when | 
					
						
							|  |  |  | testing, the `:defcompile` command will help out. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-26 15:09:30 +02:00
										 |  |  | Why not use an embedded language? ~ | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Vim supports interfaces to Perl, Python, Lua, Tcl and a few others.  But | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | these interfaces have never become widely used, for various reasons.  When | 
					
						
							|  |  |  | Vim9 was designed a decision was made to make these interfaces lower priority | 
					
						
							|  |  |  | and concentrate on Vim script. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Still, plugin writers may find other languages more familiar, want to use | 
					
						
							|  |  |  | existing libraries or see a performance benefit.  We encourage plugin authors | 
					
						
							|  |  |  | to write code in any language and run it as an external tool, using jobs and | 
					
						
							|  |  |  | channels.  We can try to make this easier somehow. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | Using an external tool also has disadvantages.  An alternative is to convert | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | the tool into Vim script.  For that to be possible without too much | 
					
						
							|  |  |  | translation, and keeping the code fast at the same time, the constructs of the | 
					
						
							|  |  |  | tool need to be supported.  Since most languages support classes the lack of | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | support for classes in Vim is then a problem. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 18:50:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Classes ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vim supports a kind-of object oriented programming by adding methods to a | 
					
						
							|  |  |  | dictionary.  With some care this can be made to work, but it does not look | 
					
						
							|  |  |  | like real classes.  On top of that, it's quite slow, because of the use of | 
					
						
							|  |  |  | dictionaries. | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | The support of classes in Vim9 script is a "minimal common functionality" of | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | class support in most languages.  It works much like Java, which is the most | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | popular programming language. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  vim:tw=78:ts=8:noet:ft=help:norl: |