// VSCODE-ELISP — ENGINEERING REPORT

VS Code / VSCodium support for Emacs Lisp · standalone TextMate grammar (source.elisp) · LSP via elisp --lsp · DAP via elisp --dap · verified with vscode-textmate

>_EXECUTIVE SUMMARY

vscode-elisp is the VS Code / VSCodium extension for Emacs Lisp, backed by the elisp interpreter — a pattern/action engine written in Rust (POSIX / / -style union CLI). It ships a declarative language contribution (filetype, grammar, editor config), an LSP client that launches elisp --lsp, a debug adapter that launches elisp --dap, and a TextMate grammar (source.elisp) covering the Emacs Lisp surface.

Design principle: mirror the proven vscode-stryke runtime wiring. The LSP transport is omitted so the client spawns bare elisp --lsp and never appends --stdio (the arg-rejection / “connection got disposed” failure mode learned from vscode-stryke). The binary is resolved to an absolute path through $PATH plus common install dirs (~/.cargo/bin, /opt/homebrew/bin, …), so it works even when the editor is launched from the macOS Dock and doesn’t inherit the shell $PATH.

252
Builtin functions (subrs) scoped
18
Special forms
5
Quoting operators
3
Numeric radixes (#x / #o / #b)
1
TextMate grammar
3
Detection paths (ext + init + shebang)
13
Tokenizer assertions
2
Runtime channels (LSP + DAP)

~COMPONENTS

FileResponsibility
package.jsonExtension manifest — contributes.languages (id elisp, *.el, shebang firstLine), contributes.grammars (source.elisp), contributes.configuration (LSP settings), contributes.commands (run / debug), contributes.debuggers (type elisp), and the vscode-languageclient dependency.
language-configuration.jsonLine comment ;, paren / bracket pairs, auto-closing / surrounding pairs, symbol word pattern, and paren-based indentationRules.
extension.jsActivates on onLanguage:elisp. Starts a LanguageClient running elisp --lsp over stdio, registers the run command (terminal elisp <file>), and registers a DebugAdapterDescriptorFactory launching elisp --dap. Missing binary → one non-fatal warning; highlighting still works.
lib/resolveBinary.jsPure (vscode-free) resolver that turns the elisp.path setting into an absolute, executable path — searching $PATH then the GUI-missed fallback dirs. Unit-tested in CI.
syntaxes/elisp.tmLanguage.jsonTextMate grammar — comments, shebang, strings, char literals, keyword symbols, numbers (#x / #o / #b), quoting sugar, special forms, builtin functions / subrs, and definition names.
scripts/tokenize_test.jsLoads the grammar under vscode-textmate + vscode-oniguruma (the engine VS Code itself uses) and asserts the scope of 13 sample tokens.

$SCOPE MAP

Token groupTextMate scopeSample
Special formskeyword.control.elispdefun defmacro let let* cond lambda setq if when unless while progn quote
Definition namesentity.name.function.elispthe name in (defun NAME …)
Builtin functions (subrs)support.function.elispcar cdr cons list mapcar funcall apply format message + 1+
Keyword symbolsconstant.other.keyword.elisp:test :key :initial-value
Char literalsconstant.character.elisp?a ?\n ?\C-x
Constantsconstant.language.elispt nil
Numbersconstant.numeric.elisp42 3.14 #xFF #o17 #b1010
Quotingkeyword.operator.quote.elisp' ` , ,@ #'
Literalsstring.* / comment.line.semicolonstrings, ; comments

#VERIFICATION

The grammar is loaded under the exact engine VS Code uses at runtime — vscode-textmate driving vscode-oniguruma — and a sample is tokenized with the resulting scopes asserted. This proves the grammar compiles under oniguruma and classifies Emacs Lisp tokens correctly, including the tricky cases: an operator subr such as + distinguished from a symbol, the definition-name capture in (defun greet …), and a keyword symbol :kw against a char literal ?a.

Sample tokenAsserted scope
defunkeyword.control.elisp
greetentity.name.function.elisp
message / +support.function.elisp
:kwconstant.other.keyword.elisp
?aconstant.character.elisp
nilconstant.language.elisp