// EMACS-VIML — ENGINEERING REPORT

Emacs major mode for VimL (vimlrs) · font-lock for keywords, ex commands, scope/special vars, builtins, function defs · run via vimlrs · LSP via vimlrs --lsp (eglot + lsp-mode) · verified with batch face assertions

>_EXECUTIVE SUMMARY

emacs-viml is the Emacs major mode for VimL (Vimscript), targeting the vimlrs standalone interpreter — a Rust port of Neovim's eval engine on fusevm. vimlrs-mode derives from prog-mode and provides font-lock, a syntax table, block-keyword-aware indentation, filetype detection, a buffer runner (vimlrs FILE via compile), eldoc + completion for builtin functions, and an LSP client that launches vimlrs --lsp.

Design principle: the highlighted surface is VimL's actual surface as the interpreter accepts it — statement keywords, ex commands, scope-namespaced variables, special v: variables, built-in functions, and function definitions. Because vimlrs ports a fixed finite builtin set (unlike the sibling stryke with its ~10,450 generated builtins), the lists are plain regexp-opt alternations in vimlrs-mode.el; no generated hash-table stdlib is required. The mode is named vimlrs-mode so it never clashes with Emacs' built-in vimrc-mode.

94
Builtin functions
34
Statement keywords
29
Ex commands
18
Special v: variables
2
LSP clients (eglot + lsp-mode)
3
Shebangs (vim / nvim / vimlrs)
19
Face assertions
27.1
Min Emacs version

~WHY NO GENERATED STDLIB

The sibling emacs-stryke generates a 170 KB stryke-stdlib.el of hash tables because a single regexp-opt over stryke's ~10,450 builtins overflows Emacs' regexp compiler (invalid-regexp "Regular expression too big"). VimL as ported by vimlrs has no such problem: its surface is fixed — 34 statement keywords, 29 ex commands, 18 special v: variables, and 94 built-in functions — comfortably within the regexp-size limit. So vimlrs-mode.el uses plain regexp-opt alternations, and vimlrs-stdlib.el holds only the hand-authored builtin-function signatures used for eldoc and completion-at-point. The command-position " comment (which the in-expression double-quoted string must not be mistaken for) is resolved with a syntax-propertize rule that only fires at line start or after a | bar.

ComponentDetail
vimlrs-mode.elMajor mode — syntax table ("/' strings, : in scope symbols, command-position " comments), font-lock keyword lists, "-comment syntax-propertize, vimlrs-indent-line, vimlrs-run-buffer (C-c C-c), eldoc + completion, eglot + lsp-mode registration, auto-mode-alist + interpreter-mode-alist.
vimlrs-stdlib.elHand-authored builtin-function signatures (the subset of Vim's funcs.c that vimlrs ports) for eldoc and completion. Byte-compiles cleanly; loads instantly.
scripts/face-test.elFontify a sample buffer and assert the face at each probe token.
vimlrs --lspLaunched with only --lsp; an appended --stdio is rejected by the binary, so neither client adds one.

$VERIFICATION

CI byte-compiles the package with byte-compile-error-on-warn (warnings are errors) and runs the batch face test. Each probe asserts the actual face text-property after font-lock-ensure.

Sample tokenAsserted face
set / let / function / for / if / return / echo / call / augroup / autocmdfont-lock-keyword-face
g:plugin_loaded / s:totalvimlrs-scope-var-face
v:true / v:countvimlrs-special-var-face
has_keyfont-lock-builtin-face
Summarize (user function name)font-lock-function-name-face
single-quoted stringfont-lock-string-face
command-position " commentfont-lock-comment-face