Repository navigation
Conversation
Use Vim9 syntax inside :def functions even in a legacy script, and legacy syntax inside :function bodies in a Vim9 script, instead of a single file-wide flag. In Vim9 syntax a double quote no longer starts a comment. Also parse "vim9script noclear" and treat :final as :finally in legacy script.
In Vim9 syntax:
- a colon is only part of a name after a one letter scope (g:name)
- there are no curly-braces names
- {key: val} uses literal keys, [expr] gives an expression key
- "." is a member access, never a concatenation
- an expression continues on the next line inside brackets, after an
operator, or when the next line starts with an operator; comments and
empty lines in between are skipped
Add the Vim9 lambda syntax "(args) => expr" with optional argument and
return types, and lambdas with a block of statements "(args) => {" ... "}".
Add tuples "(a, b)" (NODE_TUPLE) and type casts "<type>expr" (NODE_CAST).
In Vim9 syntax recognize, like find_ex_command() in Vim:
- assignments without :let (NODE_ASSIGN), including "++var" and "--var"
- function calls without :call and expressions without :eval
- generic function calls "Func<type>(args)"
- "{" ... "}" blocks (NODE_BLOCK)
A range must be preceded by a colon. "name = expr" is an assignment when
the name was declared or is not an Ex command.
Share one parser for :var, :final and Vim9 :const that handles a missing initializer, unpacking with optional types "var [a: number, _; rest]" and heredocs. Also parse typed :for loop variables and the "func: type" type.
Parse the arguments with Vim9 syntax also in a legacy script, allow them
to span lines with comments, and accept generic type parameters
"def Func<T>(", constructor arguments "this.name" and repeated "_".
Parse the file name as an expression and store whether it is an autoload import (.autoload) and the name after "as" (.alias). .str keeps the text of the arguments.
Add NODE_CLASS, NODE_INTERFACE, NODE_ENUM with NODE_ENUMVALUE for the enum values, and NODE_TYPE for :type. :public, :static and :abstract wrap the following command like :export. Methods in an interface and abstract methods have no body.
Add interpolated strings $"text {expr}" (NODE_INTERPOLATION), the falsy
operator "??" (NODE_FALSY) and "0o" octal numbers, which are available in
legacy script too. In Vim9 script allow quotes between digits.
:vim9cmd and :legacy are command modifiers that select the syntax for the command. :defer (NODE_DEFER) and :echowindow (NODE_ECHOWINDOW) take expressions.
"command Name {" and "autocmd Event pat {" start a block of commands in
Vim9 syntax up to "}". The block is stored in .block of the EXCMD node.
Like Vim, accept a double quote comment after a command also in Vim9 script, e.g. "endif \"}}}", and skip the colon before a range after a command modifier: "silent! :%delete _".
Add :clipreset, :iput, :pbuffer, :redrawtabpanel, :this, :uniq and :wlrestore.
Like Vim, ignore lines starting with "\ (legacy) or #\ (Vim9) in between lines continued with a backslash.
Like Vim, accept "call Func()->Method()": the expression must start with a function call, which may be followed by method calls.
"^\+\+" in a JavaScript string is "^++", which is not a valid regular expression, so parsing an invalid ++opt argument like "x ++" threw a SyntaxError instead of E474.
Like Vim, :enddef at the start of a line ends the function and is not a continuation line, so "var x =" before it is an incomplete line instead of taking "enddef" as the value.
a:pos and a local "pos" are different variables in Vim script, but both become "pos" in Python and JavaScript. Rename the arguments that have the name of a local variable: is_vim9_command() checked the command at the wrong position, so "foo = 1" was an Ex command in Python and JavaScript, and tuples got the position of the wrong token.
A variable alone on a line has no effect, unless an operator on the next line continues the expression. So "new" is the :new command, also when a variable "new" was declared somewhere in the script.
Author
|
@mattn Care to have a look? |
Like Vim, give an error for :append, :change, :insert, :k, :mode, :open, :t, :xit and :Print in Vim9 script, instead of parsing them as commands.
5 of 9 tasks
jclsn
force-pushed
the
feat/complete-vim9-support
branch
from
October 20, 2026 11:06
da15310 to
961e6f6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I made some good use of my tokens.
This is complete vim9scipt support. Including tests.