This plugin connects a CodeMirror 6 editor with a Language Server over WebSocket, providing IDE-like features in the browser.
Features
code-editor.mp4- ⌨️ Code Completion (w/ Resolve Support)
- 📚 Hover Documentation
- 🩺 Diagnostics
- 🔍 Go to Definition, Declaration, and Type Definition
- 🔦 Document Highlight
- 🎨 Document Formatting and Range Formatting
- ✏️ Rename Symbol
Installation
npm i codemirror-languageserver
Peer dependencies: This package requires @codemirror/autocomplete, @codemirror/lint, @codemirror/state, and @codemirror/view as peer dependencies. If you're using CodeMirror 6, you likely already have these installed.
Quick Start
import { EditorState } from '@codemirror/state'; import { EditorView } from '@codemirror/view'; import { languageServer } from 'codemirror-languageserver'; const ls = languageServer({ serverUri: 'ws://localhost:8080', rootUri: 'file:///', documentUri: `file:///${filename}`, languageId: 'cpp', // As defined at https://microsoft.github.io/language-server-protocol/specification#textDocumentItem. }); const view = new EditorView({ state: EditorState.create({ extensions: [ // ... other extensions ls, ], }), });
This sets up all built-in features: completion, hover, diagnostics, go-to-definition, document highlight, and rename support.
Options
| Option | Type | Description |
|---|---|---|
serverUri |
ws://... or wss://... |
WebSocket server URI |
rootUri |
string |
Root URI of the workspace |
workspaceFolders |
WorkspaceFolder[] |
LSP workspace folders |
documentUri |
string |
URI of the document being edited |
languageId |
string |
Language identifier (spec) |
initializationOptions |
object |
Server-specific initialization options |
locale |
string |
Locale for the LSP session (e.g. 'en') |
allowHTMLContent |
boolean |
Trust raw HTML in hover/completion content (default: false) |
synchronizationMethod |
SynchronizationMethod |
'full' or 'incremental' document sync (default: 'full') |
client |
LanguageServerClient |
Share a client across multiple editor instances |
onCapabilities |
(capabilities) => void |
Called when server capabilities are available |
onError |
(error: Error) => void |
Called when the connection encounters an error |
onClose |
() => void |
Called when the connection is closed |
Error Handling
The plugin does not crash on connection failures. Use onError and onClose to handle disconnections:
languageServer({ serverUri: 'ws://localhost:8080', rootUri: 'file:///', documentUri: `file:///${filename}`, languageId: 'cpp', onError(error) { console.error('LSP error:', error); }, onClose() { console.log('LSP connection closed'); // Recreate the editor extensions to reconnect }, })
Shared Client
To share the same language server connection across multiple editor instances:
import { LanguageServerClient, languageServerWithTransport, WebSocketTransport } from 'codemirror-languageserver'; const client = new LanguageServerClient({ transport: new WebSocketTransport('ws://localhost:8080'), rootUri: 'file:///', }); // Use the same client for multiple editors const ls1 = languageServerWithTransport({ client, documentUri: 'file:///main.cpp', languageId: 'cpp', }); const ls2 = languageServerWithTransport({ client, documentUri: 'file:///utils.cpp', languageId: 'cpp', });
Custom Transport
Use languageServerWithTransport for non-WebSocket connections:
import { languageServerWithTransport } from 'codemirror-languageserver'; const ls = languageServerWithTransport({ transport: myCustomTransport, rootUri: 'file:///', documentUri: `file:///${filename}`, languageId: 'cpp', });
The Transport interface:
interface Transport { send(message: string): void; onMessage(callback: (message: string) => void): void; onClose(callback: () => void): void; onError(callback: (error: Error) => void): void; close(): void; }
You can import Transport and WebSocketTransport from the package.
Document Highlight
Enabled by default. When the cursor is on a symbol, all occurrences in the document are highlighted. Style with CSS:
.cm-lsp-highlight-text, .cm-lsp-highlight-read { background-color: rgba(255, 255, 0, 0.2); } .cm-lsp-highlight-write { background-color: rgba(255, 165, 0, 0.3); }
The three classes correspond to DocumentHighlightKind: general text occurrences, read accesses, and write accesses.
Formatting
formatDocument and formatSelection are CodeMirror commands — bind them to keys:
import { keymap } from '@codemirror/view'; import { formatDocument, formatSelection } from 'codemirror-languageserver'; const formattingKeymap = keymap.of([ { key: 'Shift-Alt-f', run: formatDocument }, { key: 'Shift-Alt-g', run: formatSelection }, ]);
Formatting Options
Configure formatting with the formattingOptions facet. By default, tabSize is read from the editor state.
import { formattingOptions } from 'codemirror-languageserver'; // In extensions: formattingOptions.of({ tabSize: 2, insertSpaces: true, trimTrailingWhitespace: true, insertFinalNewline: true, trimFinalNewlines: true, })
Rename Symbol
renameSymbol is a CodeMirror command that opens a rename prompt at the top of the editor. If the server supports prepareRename, the current symbol name is used as the placeholder.
import { keymap } from '@codemirror/view'; import { renameSymbol } from 'codemirror-languageserver'; const renameKeymap = keymap.of([ { key: 'F2', run: renameSymbol }, ]);
Style the panel with CSS:
.cm-lsp-rename-panel { padding: 4px 8px; border-bottom: 1px solid #ddd; } .cm-lsp-rename-input { font-family: inherit; font-size: inherit; }
Server Capabilities
Use the onCapabilities callback to react when the server finishes initializing — e.g. to show or hide toolbar buttons:
languageServer({ serverUri: 'ws://localhost:8080', rootUri: 'file:///', documentUri: `file:///${filename}`, languageId: 'cpp', onCapabilities(capabilities) { // capabilities.documentFormattingProvider // capabilities.renameProvider // capabilities.completionProvider // etc. toolbar.update({ capabilities }); }, })
Initialization Options
The package includes TypeScript definitions for popular language servers:
PyrightInitializationOptions— Python (Pyright)RustAnalyzerInitializationOptions— Rust (rust-analyzer)TypeScriptInitializationOptions— TypeScript/JavaScriptESLintInitializationOptions— ESLintClangdInitializationOptions— C/C++ (Clangd)GoplsInitializationOptions— Go (Gopls)
import { languageServer } from 'codemirror-languageserver'; import type { ClangdInitializationOptions } from 'codemirror-languageserver'; const ls = languageServer<ClangdInitializationOptions>({ serverUri: 'ws://localhost:8080', rootUri: 'file:///', documentUri: 'file:///main.cpp', languageId: 'cpp', initializationOptions: { // Type-checked options specific to Clangd }, });
Contributing
Contributions are welcome.
Real World Uses
- Toph: Competitive programming platform. Toph uses Language Server Plugin for CodeMirror 6 with its integrated code editor.
License
The library is available under the BSD (3-Clause) License.