Skip to content

Add ":source ++dryrun" to check a script without running it - #21257

Closed
h-east wants to merge 3 commits into
vim:masterfrom
h-east:source-dryrun
Closed

h-east wants to merge 3 commits into
vim:masterfrom
h-east:source-dryrun

Conversation

@h-east

@h-east h-east commented Sep 9, 2026

Copy link
Copy Markdown
Contributor
Problem:  There is no way to have Vim read a script and compile its
          :def functions without running it, so that a script can be
          checked for errors without its side effects.
Solution: Add "++dryrun" to ":source": only the definitions in the
          script are executed, a declared variable gets its type but
          not its value, everything else is skipped, then the functions
          are compiled and the errors reported.  An error in a
          definition does not stop the reading.

@h-east
h-east marked this pull request as draft September 9, 2026 20:58
@h-east
h-east marked this pull request as ready for review September 9, 2026 22:32
@chrisbra

Copy link
Copy Markdown
Member

thanks, but is this really useful?

@h-east

h-east commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor Author

I'm currently building a Vim(9) script language server in Vim9 script, but I don't think it makes sense to parse everything from scratch in a overly rigid way. Since it runs inside Vim anyway, I think it's better to just query Vim directly.

@jvoisin

jvoisin commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

I'm currently building a Vim(9) script language server in Vim9 script

While being a nice achievement from a technical point of view, is Vim9 really the best languages to parse vimscript and to implement an LSP in?

h-east and others added 3 commits September 12, 2026 10:35
Problem:  There is no way to have Vim read a script and compile its
          :def functions without running it, so that a script can be
          checked for errors without its side effects.
Solution: Add "++dryrun" to ":source": only the definitions in the
          script are executed, a declared variable gets its type but
          not its value, everything else is skipped, then the functions
          are compiled and the errors reported.  An error in a
          definition does not stop the reading.  The condition of an
          ":if", ":elseif", ":while" or ":for" and an import name with
          a function call are not evaluated, and no SourceCmd,
          SourcePre or SourcePost autocommand is triggered.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Problem:  With ":source ++dryrun" compiling a :def function stops at
          the first error, the errors in the rest of the function are
          only reported after that one is fixed.
Solution: Go on with the next line after an error, the function is
          still not compiled.  A condition that fails to compile is
          replaced by a placeholder and a variable with an invalid type
          is declared as "any", so that no further errors follow from
          the first one.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Problem:  A class or enum in an autoload script cannot be defined again,
          objects made from it would refer to the old definition.  A
          dry run makes no object, but reading the script a second time
          with ":source ++dryrun" fails with E1041 all the same, and
          what follows in the class is read as if outside of it.
Solution: In a dry run, and for a class a dry run defined, delete the
          class with the other exported variables when the script is
          read again.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@h-east

h-east commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

@jvoisin The language server is a separate project, and the language it
is written in is not what this PR is about. What matters here is where
the knowledge about Vim9 script lives.

For example, clangd does not parse C or C++ on its own, it uses the
frontend of clang, the compiler, because that is the one complete
implementation of the languages. Vim9 script is in the same position:
there is no specification apart from Vim itself, the compiler in
vim9compile.c is the only complete implementation, and it changes with
the patches. A tool that reports the errors in a script has two options:
reimplement that compiler outside of Vim and chase every patch, or ask
Vim. This PR is the way to ask Vim.

@chrisbra That is what makes it useful beyond my language server.
Without this PR the only way to have Vim check a script is to ":source"
it, which runs the script level with all its side effects: mappings,
commands, options, jobs. ":source ++dryrun" defines what the script
defines and compiles the ":def" functions, and reports what does not
compile, without running anything. Any tool can use it: a lint command,
a test that checks that all files of a plugin compile, or an editor
integration written in another language. My server runs it in a
separate Vim, nothing there depends on Vim9 script.

@dkearns

dkearns commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

I haven't looked at the details of this PR yet but it seems like a good idea to me. Creating tooling for Vim script is very difficult without this capability. I'm working on a builtin to properly detect Vim9 source files, leveraging skip mode, and similarly concluded that doing this with an external parser is impractical at best.

@h-east on a related note, I have a patch somewhere to fix skipping of text-input commands (:append etc). I'll dig it up in the next couple of days and post a PR.

@h-east

h-east commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

@dkearns Thanks. Your patch for the text-input commands matters here
too: ":source ++dryrun" reuses the skip of a ":if" that is not taken, so
an ":append" at the script level of a dry run has the same problem as one
inside "if 0", the lines up to the "." are read as commands. It should
fix both at once, I will review it when it is up.

@chrisbra

Copy link
Copy Markdown
Member

Okay then, find. Thanks all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants