Language Server
mimas ships a language server to use in the editor of your choice. It is still very young but offers diagnostics, hover, navigation, rename, outlines, and inlay hints for scripting use. Scripts that use a Rust host’s functions and types are checked against that host’s API once it has run – see Host APIs.
What it supports
Diagnostics
Syntax and type errors are all reported inline in your editor. The lexer and parser are resilient to errors and will offer a full report of any syntax errors your code contains. The same is not true of today’s solver, which halts the first time it encounters an error. This means that you can get multiple syntax errors at once, but can only get one type error at a time (the same is true of the compiler however you use it). This will be improved in future releases.
Hover
Hovering a name shows what it is and what type it has. If its declaration has a /// doc comment,
that shows underneath. For a function or type a Rust host registers, that’s the /// on the Rust
item.
| You hover | You get |
|---|---|
| a local, parameter, or field | x: int |
| a function or method | the owner on one line, the declaration on the next |
| a struct or enum | its qualified name, like one::two::Foo |
| a constant | const SCALE: int |
| a module | module `fs` |
| anything else | the expression’s type |
Functions carry where they came from, which matters once a project has modules:
// hovering `bar` anywhere it is used or declared
one::two::Foo
fn bar(self, fizz: int) -> Self
Go to definition
Any name that resolves to a declaration in your project jumps to it, across files. That covers locals, parameters, struct fields, functions, methods, structs, enums, and constants.
Find references
The same names work in reverse: ask for a declaration’s references and you’ll get every use of it in the project, wherever it lives. Resting your cursor on a name also highlights its other uses in the file you’re reading.
Rename
Renaming rewrites a name everywhere it appears in the project. Renaming a member of a pact carries every implementation with it, so the two can’t drift apart.
Outline
Your editor’s outline, breadcrumbs, and symbol search list what a file declares – types with their
fields and variants, impl blocks with their methods, and a script’s top-level bindings. This is
the one feature that only needs the syntax tree, so it keeps working while the rest of the file
doesn’t.
Inlay hints
A let written without an annotation shows the type that was inferred for it.
let count = items.len(); // your editor can render this as `let count: int = ...`
Projects
Each file is checked as part of its project, the same one
mimas run and mimas check use, so a script sees every module in it.
What it does not support
- The solver is not resilient. This means that any error will cut off type information and you’ll be left with only that error in the editor. Everything but diagnostics and the outline goes quiet until the project checks cleanly again, which you’ll notice most while mid-keystroke.
- No completion, formatting, signature help, or code actions. These are the obvious next steps, but none of them exist today.
- Navigation stops at the language boundary. Natives from the standard library or a host,
builtin types like
int, and module names have no mimas source to jump to, so nothing happens. We will support navigating to the Rust definition in the future.
Setting it up
The server
The VS Code extension bundles the server, so skip this step if that’s your editor. Otherwise, install the lsp via cargo:
cargo install mimas-lsp
That puts a mimas-lsp binary on your PATH, which is where editors will look for it by default.
The extension
Install mimas from the Visual
Studio Code marketplace. Each release also attaches the extension’s .vsix files to its
GitHub release, which you can install by opening
the command palette and selecting “Install from VSIX”. Its source lives in tools/vscode.
Other editors
Any LSP client works. The server speaks the protocol over stdio, takes no arguments, and wants to
be started for the mimas language on .mim files. In Neovim, for example:
vim.lsp.config.mimas = {
cmd = { "mimas-lsp" },
filetypes = { "mimas" },
root_markers = { "Cargo.toml", ".git" },
}
vim.lsp.enable("mimas")
Host APIs
When a Rust host embeds mimas, its scripts use the functions, types, and constants it registers. The server checks them against the manifest the host writes, found the way Cargo Projects describes. Until the host has written one, or when it’s from another version of mimas, a warning at the top of every file in the project says so and the server falls back to the standard library alone. After you change the host’s API, run it again, and diagnostics pick up the change on your next edit in that project.
In VS Code, the mimas.apiPath setting points the server at one file for every script (relative to
the workspace folder), or turns it off with off, which leaves only the standard library. The
mimas: Select Host API Manifest command sets it with a file dialog, and mimas: Restart
Language Server restarts the server, which also happens on its own when the setting changes.
Other editors pass the same value as apiPath in the server’s initialization options, where a
relative path starts from the folder the editor starts the server in. In Neovim, add it to the
config above:
init_options = { apiPath = "path/to/api.json" },