
You may read my paper and cite like this:
WANG, Z. (2025, May 12). Scheme-langserver: Treat Scheme Code Editing as the First-Class Concern. The 18th European Lisp Symposium (ELS`25), Zurich. https://doi.org/10.5281/zenodo.15384882
Due to occasional GitHub access restrictions from China, this repository is also mirrored on Codeberg and Gitee. I collaborate with XmacsLabs; a fork is available here.
VSCode is now supported! See the setup guide.
Note: Auto-generated type information is available here. It is mainly used for downstream development and debugging.
Implementing IDE features like autocomplete, goto definition, and hover documentation is a significant effort. Compared to languages like Java, Python, JavaScript, or C, language server implementations for Lisp dialects are still scarce. Existing tools such as Geiser, racket langserver, and swish-lint rely primarily on a REPL or keyword tokenization rather than static program analysis.
For example, when editing an incomplete project whose code is not yet fully executable, Geiser can only complete top-level bindings listed by environment-symbols (on Chez Scheme) or raw symbols—not true identifiers. This means local bindings and unfinished code receive no help in recognizing valid identifier scopes. The same limitation applies to goto definition and other core IDE features.
The root cause is that Scheme and other Lisp dialects present a formidable challenge for program analysis: their rich data structures, flexible control flow, and especially macros make static reasoning difficult. But this does not mean Scheme is only for geniuses and meta-programming. With a better editing environment, Scheme can be accessible and productive for everyone.
scheme-langserver is a Language Server Protocol (LSP) implementation for Scheme that provides completion, goto definition, hover, and type inference through static code analysis based on the R6RS standard. It handles incomplete code gracefully and is published via Akku, a Scheme package manager.
The server has been tested on Chez Scheme 9.4, 9.5, and 10.x.
See the setup guide.
For troubleshooting tips, see debugging.md.
Active development is focused on bug fixes, performance profiling, and expanding the type inference system. The 2.1.0 release brings major improvements to diagnostics, macro auto-resolution, and LSP protocol robustness. Planned features include a dedicated VSCode plugin and data-flow analysis.
2.1.0 — Major release with expanded diagnostics, macro auto-resolution, performance optimizations, and Docker CI upgraded to Chez 10.4.1.
workspace/symbol search is now supported.source and code fields.lambda, case-lambda, let, letrec, let-values, do, define, with-syntax).only, except, rename, and alias modifiers.syntax-rules to syntax-case, let-syntax, and letrec-syntax. Multi-layer macro cascade reference propagation is fixed.define-record-type now infers record types; car/cdr family macros (caar, cadr, caddr, cadddr, caaar, cadar, etc.) have dedicated type rules.eq? hashtables; matrix operations rewritten with cons+reverse.Content-Length, and malformed JSON; shutdown/exit lifecycle fully compliant with the LSP spec; didChange auto-cancellation removed to comply with the spec; request-queue concurrency hardened with cancel barriers and log-mutex.chez-exe switched to the ufo5260987423/chez-exe fork for 10.x compatibility; test suite refactored to use AST search instead of hard-coded positions.See doc/release-history.md for the full changelog.




workspace/symbol).define-syntax, let-syntax, and other macro forms via hand-written rules.syntax-rules, syntax-case, let-syntax, and letrec-syntax—plus multi-layer macro cascade propagation—is functionally correct but not enabled in production because it is too slow for real-world projects (it triggers heavy macro expansion and cross-document reference back-propagation for every macro use site). The routing code in analysis/identifier/self-defined-rules/router.sls currently falls back to hand-written rules such as match-process for ufo-match. If you are interested in pushing this research forward—e.g. via lazy expansion, incremental caching, or selective rule generation—contributions and discussions are very welcome!.sps files.length-a and length-b (both integer?) appear first because they match the parameter type required by <=.

send-message
2023 11 21 11 26 41 967266866
{"jsonrpc":"2.0","id":"3","result":[{"label":"length-a"},{"label":"length-b"},{"label":"lambda"},{"label":"latin-1-codec"},{"label":"lcm"},{"label":"least-fixnum"},{"label":"length"},{"label":"let"},{"label":"let*"},{"label":"let*-values"},{"label":"let-syntax"},{"label":"let-values"},{"label":"letrec"},{"label":"letrec*"},{"label":"letrec-syntax"},{"label":"lexical-violation?"},{"label":"list"},{"label":"list->string"},{"label":"list->vector"},{"label":"list-ref"},{"label":"list-sort"},{"label":"list-tail"},{"label":"list?"},{"label":"log"},{"label":"lookahead-char"},{"label":"lookahead-u8"}]}
.scm, .ss, .sps, .sls, .sld.source and code fields. Detects library-not-found, duplicate identifiers in binding forms (e.g. (lambda (x x) ...)), unused imports (e.g. (only (rnrs) car) where car is never referenced), and tokenizer syntax errors.

textDocument/rename + prepareRename).textDocument/formatting).textDocument/signatureHelp).textDocument/codeAction) — e.g. “Remove unused import”, “Organize imports”.Pull requests are welcome! Please see AGENTS.md for project conventions, build steps, and coding style before opening a PR.
Since mid-2025, active development on this project has been assisted by KIMI (Moonshot AI) in a vibe-coding workflow: the maintainer describes intent in natural language, KIMI explores the codebase, proposes changes, and iterates with tests. If you notice commits authored or co-authored by kimi, that is the AI agent trail. Human review and final approval always remain with the maintainer.
Almost all key procedures and APIs are covered by tests. Run the full suite with:
bash test.sh
For faster feedback during development, run a single test file:
source .akku/bin/activate
scheme --script tests/protocol/apis/test-definition.sps
Note: Tests currently focus on single-threaded execution.
Script-Fu is based on Scheme. Using this example, you can apply scheme-langserver to .scm files in GIMP.
Possible future targets include OMN (Opusmodus Notation) and AutoLisp.
find . -name "*.sls" ! -path "./.akku/*" |xargs wc -l
define, lambda, let, define-record-type, etc.syntax-rules expansion vs hand-written rulesdefine-record-type in the type system