m2-ls
The language server: the thing that started all of this. It gives any editor with an LSP client errors as you type, hover docs, go-to-definition, rename, completion, formatting and a type checker.
It’s written in Rust and never runs Macaulay2. Everything is static, and M2’s documentation is baked into the binary, so it starts instantly, works without M2 installed (yes, even on Windows), and can’t get stuck on a Gröbner basis.
What it does
- Diagnostics: syntax errors, code M2 rejects or quietly ignores, type errors, style nits. More on the linter page.
- Type checker: infers types without running anything, from the return types M2 declares for its own methods. If it isn’t sure, it keeps quiet: a type error it shows should be real.
- Hover: docs for builtins and for your own code, plus the inferred type (how it works).
- Navigation: definition, references, implementations, type hierarchy, symbols, and jumping into M2’s library sources if you have M2 installed.
- Rename across files, inlay type hints, signature help, semantic highlighting.
- Quick fixes and refactors, e.g.
L.1→L#1or “flatten nested if”. - Formatting: see formatter.
It follows needsPackage, load, needs and friends, knows what a package exports, and
checks TEST blocks like normal code.
n = 5
if n then print "yes" -- warning: if condition must have type `Boolean`, but this has type `ZZ`
Install
cargo install m2-ls
You get m2-ls, m2-lint and m2-fmt. Then
hook up your editor. In VS Code skip all that, since the
extension brings the server along on Linux, macOS and Windows.
Settings
Under the m2-ls section of your editor’s LSP config:
{
"m2-ls": {
"diagnostics": { "disabled": ["unused-binding", "T02"] },
"formatting": { "indent": 4 },
"inlayHints": { "expressionTypes": true },
"sources": { "paths": ["~/opt/macaulay2"] }
}
}
The full list is in the repository README.
Known gaps
- Things that only exist at runtime (
value "x", symbols made on the fly) stay unknown. - Completion is sparse on purpose: it shows up when there are a few good candidates, not 400.
- Only files reachable from what you open are indexed, not the whole project folder.
Under the hood
Parsing is m2-syn on top of the tree-sitter grammar, incremental as you type. Builtin docs and signatures come from an index extracted from Macaulay2’s own documentation.
m2-ls is MIT. The only exception is that embedded documentation, which stays under Macaulay2’s GPL.