To: vim_dev@googlegroups.com Subject: Patch 8.2.3906 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3906 Problem: Vim9 help still contains "under development" warnings. Solution: Remove the explicit warning. Files: runtime/doc/vim9.txt *** ../vim-8.2.3905/runtime/doc/vim9.txt 2021-12-26 12:07:24.794944017 +0000 --- runtime/doc/vim9.txt 2021-12-26 18:01:52.714435250 +0000 *************** *** 1,17 **** ! *vim9.txt* For Vim version 8.2. Last change: 2021 Jan 23 VIM REFERENCE MANUAL by Bram Moolenaar - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE - Vim9 script commands and expressions. *Vim9* *vim9* Most expression help is in |eval.txt|. This file is about the new syntax and features in Vim9 script. - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE 1. What is Vim9 script? |Vim9-script| --- 1,14 ---- ! *vim9.txt* For Vim version 8.2. Last change: 2021 Dec 26 VIM REFERENCE MANUAL by Bram Moolenaar Vim9 script commands and expressions. *Vim9* *vim9* Most expression help is in |eval.txt|. This file is about the new syntax and features in Vim9 script. 1. What is Vim9 script? |Vim9-script| *************** *** 27,34 **** 1. What is Vim9 script? *Vim9-script* - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE - Vim script has been growing over time, while preserving backwards compatibility. That means bad choices from the past often can't be changed and compatibility with Vi restricts possible solutions. Execution is quite --- 24,29 ---- *************** *** 76,83 **** 2. Differences from legacy Vim script *vim9-differences* - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE - Overview ~ Brief summary of the differences you will most often encounter when using Vim9 --- 71,76 ---- *************** *** 103,111 **** writefile(['done'], 'file.txt') - You cannot use `:xit`, `:t`, `:k`, `:append`, `:change`, `:insert`, `:open`, and `:s` or `:d` with only flags. ! or curly-braces names. - A range before a command must be prefixed with a colon: > :%s/this/that - Unless mentioned specifically, the highest |scriptversion| is used. --- 96,107 ---- writefile(['done'], 'file.txt') - You cannot use `:xit`, `:t`, `:k`, `:append`, `:change`, `:insert`, `:open`, and `:s` or `:d` with only flags. ! - You cannot use curly-braces names. - A range before a command must be prefixed with a colon: > :%s/this/that + - Executing a register with "@r" does not work, you can prepend a colon or use + `:exe`: > + :exe @a - Unless mentioned specifically, the highest |scriptversion| is used. *************** *** 154,160 **** function was defined - `:disassemble` is used for the function. - a function that is compiled calls the function or uses it as a function ! reference *E1091* If compilation fails it is not tried again on the next call, instead this error is given: "E1091: Function is not compiled: {name}". --- 150,156 ---- function was defined - `:disassemble` is used for the function. - a function that is compiled calls the function or uses it as a function ! reference (so that the argument and return types can be checked) *E1091* If compilation fails it is not tried again on the next call, instead this error is given: "E1091: Function is not compiled: {name}". *************** *** 166,174 **** `:def` has no options like `:function` does: "range", "abort", "dict" or "closure". A `:def` function always aborts on an error (unless `:silent!` was ! used for the command or inside a `:try` block), does not get a range passed ! cannot be a "dict" function, and can always be a closure. ! 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, arg: string) --- 162,170 ---- `:def` has no options like `:function` does: "range", "abort", "dict" or "closure". A `:def` function always aborts on an error (unless `:silent!` was ! 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. ! *vim9-no-dict-function* 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, arg: string) *************** *** 177,182 **** --- 173,187 ---- var d = {item: 'value', func: DictFunc} d.func(d, 'item') + 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 + 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. *************** *** 194,200 **** 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: > ! def MyFunc(one = 'one', last = 'last) ... enddef MyFunc(v:none, 'LAST') # first argument uses default value 'one' --- 199,205 ---- 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: > ! def MyFunc(one = 'one', last = 'last') ... enddef MyFunc(v:none, 'LAST') # first argument uses default value 'one' *************** *** 222,230 **** def scriptname#function() # autoload When using `:function` or `:def` to specify a nested function inside a `:def` ! function, this nested function is local to the code block it is defined in. ! In a `:def` function it is not possible to define a script-local function. It ! is possible to define a global function by using the "g:" prefix. When referring to a function and no "s:" or "g:" prefix is used, Vim will search for the function: --- 227,236 ---- def scriptname#function() # autoload When using `:function` or `:def` to specify a nested function inside a `:def` ! function and no namespace was given, this nested function is local to the code ! block it is defined in. In a `:def` function it is not possible to define a ! script-local function. It is possible to define a global function by using ! the "g:" prefix. When referring to a function and no "s:" or "g:" prefix is used, Vim will search for the function: *************** *** 341,347 **** Although using a :def function probably works better. Declaring a variable with a type but without an initializer will initialize to ! zero, false or empty. 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 --- 347,355 ---- Although using a :def function probably works better. Declaring a variable with a type but without an initializer will initialize to ! 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. 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 *************** *** 351,356 **** --- 359,367 ---- `:lockvar` does not work on local variables. Use `:const` and `:final` instead. + The `exists()` and `exists_compiled()` functions do not work on local variables + or arguments. + Variables, functions and function arguments cannot shadow previously defined or imported variables and functions in the same script file. Variables may shadow Ex commands, rename the variable if needed. *************** *** 370,375 **** --- 381,412 ---- echo GlobalFunc() The "g:" prefix is not needed for auto-load functions. + *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 + + If you would do it like this you get an error at compile time that + "PluginFunc" does not exist, even when "g:loaded_plugin" does not exist: > + 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 + Since `&opt = value` is now assigning a value to option "opt", ":&" cannot be used to repeat a `:substitute` command. *vim9-unpack-ignore* *************** *** 444,449 **** --- 481,492 ---- use the command instead: > :substitute(pattern (replacement ( + 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 + Put the expression in parentheses to use the "!" for negation: > + (!expression)->Method() + Note that while variables need to be defined before they can be used, functions can be called before being defined. This is required to allow for cyclic dependencies between functions. It is slightly less efficient, *************** *** 460,466 **** var Funcref = MyFunction When using `function()` the resulting type is "func", a function with any ! number of arguments and any return type. The function can be defined later. Lambda using => instead of -> ~ --- 503,510 ---- var Funcref = MyFunction When using `function()` the resulting type is "func", a function with any ! number of arguments and any return type (including void). The function can be ! defined later if the argument is in quotes. Lambda using => instead of -> ~ *************** *** 475,481 **** var Lambda = (arg) => expression No line break is allowed in the arguments of a lambda up to and including the ! "=>". This is OK: > filter(list, (k, v) => v > 0) This does not work: > --- 519,526 ---- var Lambda = (arg) => expression No line break is allowed in the arguments of a lambda up to and including the ! "=>" (so that Vim can tell the difference between an expression in parentheses ! and lambda arguments). This is OK: > filter(list, (k, v) => v > 0) This does not work: > *************** *** 510,516 **** echom 'Handler called ' .. count }, {repeat: 3}) - 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 => { --- 555,560 ---- *************** *** 599,605 **** | echo 'match' | endif ! Note that this means that in heredoc the first line cannot be a bar: > var lines =<< trim END | this doesn't work END --- 643,649 ---- | echo 'match' | endif ! Note that this means that in heredoc the first line cannot start with a bar: > var lines =<< trim END | this doesn't work END *************** *** 607,626 **** add the "C" flag to 'cpoptions': > set cpo+=C var lines =<< trim END ! | this doesn't work 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 ! splitting up a long Ex command, comments can start with #\ instead of "\: > ! syn region Text \ start='foo' #\ comment \ end='bar' ! ! < *E1050* To make it possible for the operator at the start of the line to be recognized, it is required to put a colon before a range. This example will add "start" and print: > --- 651,675 ---- add the "C" flag to 'cpoptions': > set cpo+=C var lines =<< trim END ! | this works 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 ! splitting up a long Ex command, comments can start with '#\ ': > ! syn region Text \ start='foo' #\ comment \ end='bar' ! 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* To make it possible for the operator at the start of the line to be recognized, it is required to put a colon before a range. This example will add "start" and print: > *************** *** 716,721 **** --- 765,773 ---- arg # OK ) + White space is not allowed in a `:set` command between the option name and a + following "&", "!", "<", "=", "+=", "-=" or "^=". + No curly braces expansion ~ *************** *** 781,786 **** --- 833,848 ---- For loop ~ + The loop variable must not be declared yet: > + var i = 1 + for i in [1, 2, 3] # Error! + + It is possible to use a global variable though: > + g:i = 1 + for g:i in [1, 2, 3] + echo g:i + endfor + 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. *************** *** 951,957 **** use-feature endif enddef ! < *vim9-user-command* Another side effect of compiling a function is that the presence of a user command is checked at compile time. If the user command is defined later an error will result. This works: > --- 1013,1020 ---- use-feature endif enddef ! The `exists_compiled()` function can also be used for this. ! *vim9-user-command* Another side effect of compiling a function is that the presence of a user command is checked at compile time. If the user command is defined later an error will result. This works: > *************** *** 985,996 **** You may also find this wiki useful. It was written by an early adopter of Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md ============================================================================== 3. New style functions *fast-functions* - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE - *:def* :def[!] {name}([arguments])[: {return-type}] Define a new function by the name {name}. The body of --- 1048,1067 ---- You may also find this wiki useful. It was written by an early adopter of Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md + *:++* *:--* + 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. + ============================================================================== 3. New style functions *fast-functions* *:def* :def[!] {name}([arguments])[: {return-type}] Define a new function by the name {name}. The body of *************** *** 1047,1055 **** Note that for command line completion of {func} you can prepend "s:" to find script-local functions. ! :disa[ssemble]! {func} Like `:disassemble` but with the instructions used for profiling. Limitations ~ Local variables will not be visible to string evaluation. For example: > --- 1118,1131 ---- Note that for command line completion of {func} you can prepend "s:" to find script-local functions. ! :disa[ssemble] profile {func} ! Like `:disassemble` but with the instructions used for profiling. + :disa[ssemble] debug {func} + Like `:disassemble` but with the instructions used for + debugging. + Limitations ~ Local variables will not be visible to string evaluation. For example: > *************** *** 1101,1108 **** 4. Types *vim9-types* - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE - The following builtin types are supported: bool number --- 1177,1182 ---- *************** *** 1121,1130 **** Not supported yet: tuple ! These types can be used in declarations, but no value will have this type: ! {type}|{type} {not implemented yet} ! void ! any There is no array type, use list<{type}> instead. For a list constant an efficient implementation is used that avoids allocating lot of small pieces of --- 1195,1202 ---- Not supported yet: tuple ! These types can be used in declarations, but no simple value will actually ! have the "void" type. There is no array type, use list<{type}> instead. For a list constant an efficient implementation is used that avoids allocating lot of small pieces of *************** *** 1133,1140 **** --- 1205,1220 ---- A partial and function can be declared in more or less specific ways: func any kind of function reference, no type checking for arguments or return value + func: void any number and type of arguments, no return + value func: {type} any number and type of arguments with specific return type + + func() function with no argument, does not return a + value + func(): void same + func(): {type} function with no argument and return type + func({type}) function with argument type, does not return a value func({type}): {type} function with argument type and return type *************** *** 1223,1228 **** --- 1303,1320 ---- ['a', 'b', 'c'] list [1, 'x', 3] list + 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 + For script-local variables in Vim9 script the type is checked, also when the variable was declared in a legacy function. *************** *** 1239,1254 **** before, if the value used matches the expected type. There will sometimes be an error, thus breaking backwards compatibility. For example: - Using a number other than 0 or 1 where a boolean is expected. *E1023* ! - Using a string value when setting a number options. - Using a number where a string is expected. *E1024* ! One consequence is that the item type of a list or dict given to map() must not change. This will give an error in Vim9 script: > ! map([1, 2, 3], (i, v) => 'item ' .. i) E1012: Type mismatch; expected number but got string ! Instead use |mapnew()|. If the item type was 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 numbers. Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use |flattennew()| instead. --- 1331,1354 ---- before, if the value used matches the expected type. There will sometimes be an error, thus breaking backwards compatibility. For example: - Using a number other than 0 or 1 where a boolean is expected. *E1023* ! - Using a string value when setting a number option. - Using a number where a string is expected. *E1024* ! One consequence is that the item type of a list or dict given to |map()| must not change. This will give an error in Vim9 script: > ! echo map([1, 2, 3], (i, v) => 'item ' .. i) E1012: Type mismatch; expected number but got string ! Instead use |mapnew()|: > ! echo mapnew([1, 2, 3], (i, v) => 'item ' .. i) ! ['item 0', 'item 1', 'item 2'] ! ! If the item type was 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: > ! var mylist = [1, 2.0, '3'] ! # typename(mylist) == "list" ! map(mylist, (i, v) => 'item ' .. i) ! # typename(mylist) == "list", no error ! Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use |flattennew()| instead. *************** *** 1257,1264 **** 5. Namespace, Import and Export *vim9script* *vim9-export* *vim9-import* - THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE - A Vim9 script can be written to be imported. This means that everything in the script is local, unless exported. Those exported items, and only those items, can then be imported in another script. --- 1357,1362 ---- *************** *** 1351,1361 **** To import all exported items under a specific identifier: > import * as That from 'thatscript.vim' - {not implemented yet: using "This as That"} - Then you can use "That.EXPORTED_CONST", "That.someValue", etc. You are free to choose the name "That", but it is highly recommended to use the name of the ! script file to avoid confusion. `:import` can also be used in legacy Vim script. The imported items still become script-local, even when the "s:" prefix is not given. --- 1449,1458 ---- To import all exported items under a specific identifier: > import * as That from 'thatscript.vim' Then you can use "That.EXPORTED_CONST", "That.someValue", etc. You are free to choose the name "That", but it is highly recommended to use the name of the ! script file to avoid confusion. Also avoid command names, because the name ! will shadow them. `:import` can also be used in legacy Vim script. The imported items still become script-local, even when the "s:" prefix is not given. *************** *** 1463,1469 **** var name: string def constructor(name: string) ! this.name = name; enddef def display(): void --- 1560,1566 ---- var name: string def constructor(name: string) ! this.name = name enddef def display(): void *************** *** 1574,1580 **** - 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 ! result as a bool. TODO: to be reconsidered - 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. --- 1671,1678 ---- - 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 ! result as a bool. The |falsy-operator| was added for the mechanism to use a ! default value. - 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. *** ../vim-8.2.3905/src/version.c 2021-12-26 17:31:31.520270611 +0000 --- src/version.c 2021-12-26 18:05:26.018123404 +0000 *************** *** 751,752 **** --- 751,754 ---- { /* Add new patch number below this line */ + /**/ + 3906, /**/ -- Two percent of zero is almost nothing. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///