LSP (Language Server) plugin¶
Code intelligence powered by the Language Server Protocol — error squiggles, navigation, hover, completion, signature help, formatting, find references, rename, and go-to-symbol — for any language that has a language server. The editor talks to the server over LSP; the plugin is the client. Which servers exist is data-driven (one small JSON per language), so C++/clangd below is just one of several bundled definitions.
The editor does not bundle or download servers
A language server is a separate program you install once. MTE detects an installed server and points it at your project; it never ships one. See Getting a language server.
Current features¶
| Feature | How |
|---|---|
| Diagnostics | Errors/warnings from the server appear as squiggly underlines (red = error, amber = warning, blue = info, grey = hint), updated as you type. |
| Go to Definition | Put the caret on a symbol and press F12, or use Search ▸ Code Navigation ▸ Go to Definition. Jumps to the definition, opening another file if needed. |
| Find References | Caret on a symbol → Shift+F12 (or Search ▸ Code Navigation ▸ Find References). Results open in a bottom References panel, grouped by file with a source-line preview; double-click to jump. |
| Hover | Rest the pointer over a symbol; a popup shows its type/signature and documentation (rendered from the server's Markdown). |
| Completion | Ctrl+Space requests completions from the server and folds them into the editor's completion popup (ahead of the built-in keyword/buffer-word suggestions), filtered as you type. |
| Signature help | Typing a call's ( or a , shows a call tip with the function signature and the active parameter highlighted; ) dismisses it. |
| Format Document | Alt+Shift+F (or Edit ▸ Format Document) reformats the whole document via the server, in a single undo step. The server's own configuration governs the style (for clangd, a .clang-format file). |
| Find References (listed above) | — |
| Rename Symbol | Caret on a symbol → Shift+F6 (or Edit ▸ Rename Symbol). Enter a new name; every usage is updated. When the rename spans several files you are asked to confirm first — each file is opened, changed, and left modified for you to review and save. |
| Go to Symbol (in file) | Ctrl+Shift+O opens the Command Palette listing every symbol in the current file (functions, classes, methods…); type to filter, Enter jumps. Each row shows the symbol kind and its container. |
| Go to Symbol in Workspace | Ctrl+T searches symbols across the whole project as you type (the server matches the query); Enter opens the file at the symbol. |
The go-to-symbol pickers are the Command Palette's symbol modes — see Command palette.
Cross-file references and rename need the server's index
Find References and Rename only reach other files once the server has indexed
the project. For C/C++ that means a compile_commands.json (see below) and
clangd's background index; without it they operate on the current file only.
Rename is per-file undo for now
A multi-file rename is applied one file at a time, so each file is its own undo step (the confirmation dialog says so). Review the modified tabs before saving.
The server status indicator¶
The status bar shows a compact LSP: segment (left of the other plugin
segments) summarising every language server relevant to your open files:
| Glyph | Meaning |
|---|---|
… |
Starting — the server was launched and is handshaking. |
✓ |
Ready — serving requests. |
↻n |
Restarting — the server stopped unexpectedly; automatic restart attempt n is scheduled. |
✗ |
Dark — either no server is installed for the language, or the server kept crashing and automatic restarts gave up. |
The segment appears when the first document with a configured language opens, tracks only languages you actually have documents open for — closing a language's last file removes its entry (reopening one brings it back instantly) — and hides entirely when no such document remains.
If a server crashes¶
A language server that exits unexpectedly is restarted automatically with
an increasing delay (1 s, 2 s, 4 s… capped at 30 s). While this happens the
indicator shows ↻n and a status-bar notification reports the first crash.
After a successful restart your open documents are re-announced to the server
and diagnostics come back on their own; stale squiggles from the dead server
are cleared immediately. Editing is never blocked.
After 5 failed attempts in a row the plugin gives up: the indicator shows
✗, a notification points you at the settings, and the language stays dark
until you restart it manually. A server that ran fine for at least a minute
gets a fresh set of attempts when it later crashes.
Manual restart — either of:
- Search ▸ Code Navigation ▸ Restart Language Servers (no default shortcut; also available from the Command Palette), or
- the Re-scan / restart servers button in Preferences ▸ Language Server.
Both tear every server down, re-run the discovery with the current settings, and reset the failure budget — use them after installing a missing server or fixing a broken one.
Getting a language server¶
Install the server for your language and make sure it is on your PATH (or set
an explicit path in the settings). If none is found,
the feature simply does nothing for that language — the
status indicator shows ✗ and the log records a
one-time hint, but nothing interrupts you.
MTE ships server definitions (not the servers) for many languages, so most just need the server installed — no JSON editing. Bundled definitions cover C/C++, Python, Rust, Go, TypeScript, JavaScript, C#, Java, HTML, CSS, JSON, YAML, and Bash (plus forward-looking Kotlin, Swift, and Objective-C entries that activate once those languages get syntax colouring).
| Language | Server | Where to get it |
|---|---|---|
| C/C++ | clangd | winget install LLVM.LLVM (Windows), the "C++ Clang tools" component in the Visual Studio installer, brew install llvm (macOS), or your distro's clang-tools-extra package. |
| Python | pyright | npm i -g pyright. |
| TypeScript/JS | typescript-language-server | npm i -g typescript-language-server typescript. |
| Rust | rust-analyzer | rustup component add rust-analyzer. |
| Go | gopls | go install golang.org/x/tools/gopls@latest. |
Verify in a terminal, e.g. clangd --version. For a language MTE doesn't ship a
definition for, add one as described in Adding a language.
C/C++ projects need compile_commands.json¶
clangd only understands your code accurately when it knows the compile flags,
from a compilation database (compile_commands.json). Without one, clangd
falls back to guessing and cross-file features (find references, rename) stay
limited to the open file.
MTE finds a compile_commands.json automatically — it searches the project
root and common build directories (build/, out/, cmake-build-*,
.mte-compile-commands/) and points clangd at it. You generate the database;
the editor does not (reliably configuring an arbitrary project needs your
toolchain/SDK environment, which the editor doesn't have). When a C/C++ project
has none, MTE shows a one-time hint (with a Don't show this again option)
linking here.
Generating it (CMake)¶
CMAKE_EXPORT_COMPILE_COMMANDS is honoured only by the Ninja and Makefile
generators — the Visual Studio generator ignores it (it produces no
compile_commands.json even with the flag set). So generate the database with
Ninja, into a dedicated directory, separate from the one you normally
build in: CMake refuses to reconfigure an existing build directory with a
different generator, so a project you usually build with Visual Studio needs its
own Ninja directory.
This is a configure-only step (no full build needed). From the project root:
.mte-compile-commands/is one of the directories MTE scans, so the resultingcompile_commands.jsonis found automatically. Any scanned directory works too (build/,out/,cmake-build-*, or the project root) — just keep it separate from a directory configured with another generator.- Run it from an environment where the project actually configures: the right
compiler on
PATH(e.g. an x64 Native Tools Command Prompt on Windows) and any variables your project needs (such asQT6_DIRfor a Qt project). Ifcmakecan't find your compiler or SDK, the database ends up empty or missing include paths and clangd won't index well. - Reopen the folder afterwards. The log should no longer say "no compile_commands.json"; give clangd a moment to build its background index before references/rename span files.
Other build systems: Bear (bear -- make), compiledb, Meson, Bazel and others
can all produce a compile_commands.json that the plugin will find.
Adding a language¶
Servers are described by JSON files the plugin loads at startup from
<editor>/lsp-servers/*.json. Each entry maps a language to its command plus
discovery hints:
{
"language": "cpp",
"command": "clangd",
"aliases": ["clangd-18", "clangd-17"],
"args": ["--background-index"],
"extensions": [".cpp", ".h", ".hpp"],
"searchDirs": ["${LLVM}/bin", "${ProgramFiles}/LLVM/bin"],
"docsAnchor": "cpp-clangd",
"compileCommandsArg": "--compile-commands-dir=${dir}"
}
languagematches the editor's detected language id;command/aliasesare the executable names tried onPATH;searchDirs(with${VAR}expansion) are extra install locations.compileCommandsArg(optional) is appended, with${dir}replaced by the located database directory — that is how clangd is pointed atcompile_commands.json.
How a server is located¶
For a matching document the plugin resolves the server in order: an explicit
configured path → the command and its aliases on PATH → the entry's
searchDirs and ecosystem locations. The server is started once per language
and shut down with the editor.
Language server settings¶
Preferences ▸ Language Server lists every language a server definition exists for. Per language you can:
- Enable / disable the server (a disabled language never starts one).
- Set an explicit executable path (with Browse…). This override wins
over the
PATH/searchDirssearch above — useful when the server isn't onPATHor you want a specific build.
Changes take effect when you press OK / Apply: if any enable flag or path actually changed, the servers are restarted with the new settings automatically (an untouched page never disturbs the running servers). The Re-scan / restart servers button additionally forces a teardown-and- rediscover with the current settings — useful after installing a server the editor previously could not find, and it also resets the crash-restart budget.
Limitations¶
- Code colouring inside hover popups is not applied (the text is formatted — bold, headings, monospace code — but not syntax-highlighted).
- Accuracy depends on the server: for C/C++, without
compile_commands.jsonclangd falls back to heuristics and results may be incomplete.