A powerful LSP client plugin for CodeMirror 6 that brings IDE-like features to your editor.
This is a fork of FurqanSoftware/codemirror-languageserver with additional features and modernization.
- π Code Completion - Intelligent autocompletion with support for snippets
- π‘ Hover Information - Rich documentation on hover
β οΈ Diagnostics - Real-time error checking and warnings- π Code Actions - Quick fixes and refactoring suggestions
- π·οΈ Symbol Renaming - Smart symbol renaming across files
- π― Go to Definition - Jump to symbol definitions
- π¨ Markdown Support - Rich formatting in hover tooltips and documentation
npm install @marimo-team/codemirror-languageserver
# or
pnpm add @marimo-team/codemirror-languageserver
# or
yarn add @marimo-team/codemirror-languageserverimport { languageServer } from '@marimo-team/codemirror-languageserver';
import { EditorState, EditorView } from '@codemirror/basic-setup';
import { WebSocketTransport } from '@open-rpc/client-js';
// Create a WebSocket transport
const transport = new WebSocketTransport('ws://your-language-server-url');
// Configure the language server plugin
const ls = languageServer({
transport,
rootUri: 'file:///',
documentUri: 'file:///path/to/your/file',
languageId: 'typescript', // Or any other language ID supported by your LSP
// Optional: Customize keyboard shortcuts
keyboardShortcuts: {
rename: 'F2', // Default: F2
goToDefinition: 'ctrlcmd', // Ctrl/Cmd + Click
},
// Optional: Allow HTML content in tooltips
allowHTMLContent: true,
});
// Create editor with the LSP plugin
const view = new EditorView({
state: EditorState.create({
doc: 'Your initial content',
extensions: [
// ... other extensions ...
ls
]
}),
parent: document.querySelector('#editor')
});F2- Rename symbol under cursorCtrl/Cmd + Click- Go to definitionCtrl/Cmd + Space- Trigger completion manuallyCtrl/Cmd + .- Open the code action menu at the cursor/selection
const ls = languageServer({
// ...
// Optional: Filter complete (`isIncomplete: false`) completion lists
// client-side instead of re-querying the server on every keystroke.
clientSideFiltering: true,
});Completion items the server marks deprecated get a cm-deprecated class,
shown with a strikethrough by default. Override with:
.cm-tooltip-autocomplete li.cm-deprecated .cm-completionLabel {
text-decoration: line-through;
opacity: 0.7;
}Pressing Ctrl/Cmd + . (configurable via keyboardShortcuts.codeActions)
requests code actions for the current selection β including refactors and
source actions not tied to a diagnostic β and shows them in a small menu at
the cursor. Actions the server provides lazily (without an edit) are resolved
via codeAction/resolve before being applied.
Hosts can replace the built-in menu with their own UI:
const ls = languageServer({
// ...
codeActionsConfig: {
renderMenu: (actions, apply) => {
// Render your own menu; call apply(action) with the chosen action.
myMenu.show(actions.map((a) => ({
label: a.title,
onSelect: () => apply(a),
})));
},
},
});Custom entry points (e.g. an "Organize imports" button) can request filtered actions directly through the plugin:
import { getLanguageServerPlugin } from '@marimo-team/codemirror-languageserver';
const plugin = getLanguageServerPlugin(view);
if (plugin) {
const wholeDocument = {
start: { line: 0, character: 0 },
end: { line: view.state.doc.lines - 1, character: 0 },
};
const actions = await plugin.requestCodeActions(view, wholeDocument, [
'source.organizeImports',
]);
if (actions?.[0]) {
await plugin.applyCodeAction(actions[0]);
}
}Diagnostics map the full LSP payload, not just the message and severity:
-
Severity β
Hintdiagnostics use CodeMirror's native"hint"severity. -
Tags β
UnnecessaryandDeprecateddiagnostics add the mark classescm-lsp-unnecessary(faded) andcm-lsp-deprecated(struck through). A base theme ships these styles out of the box; override them with your own theme:.cm-lsp-unnecessary { opacity: 0.6; } .cm-lsp-deprecated { text-decoration: line-through; }
-
Related information β "declared here" / "first defined here" entries are rendered below the message. Entries in the current document are clickable and move the selection; entries in other documents invoke the
onShowLocationcallback so the host can open them:const ls = languageServer({ // ... onShowLocation: ({ uri, range, isExternalDocument }) => { // Open `uri` and reveal `range` in your app }, });
-
Code documentation links β when the server provides a
codeDescription(e.g. ESLint or ruff rule docs), the diagnostic renders a link to it.
import { LanguageServerClient } from '@marimo-team/codemirror-languageserver';
const client = new LanguageServerClient({
transport,
rootUri: 'file:///',
workspaceFolders: [{ name: 'workspace', uri: 'file:///' }]
});
// Use in multiple editors
const ls1 = languageServerWithClient({
client,
documentUri: 'file:///file1.ts',
languageId: 'typescript'
});
const ls2 = languageServerWithClient({
client,
documentUri: 'file:///file2.ts',
languageId: 'typescript'
});Contributions are welcome! Feel free to:
- Report bugs
- Suggest new features
- Submit pull requests
Please ensure your PR includes appropriate tests and documentation.
Check out our live demo to see the plugin in action.
BSD 3-Clause License
This is a modernized fork of FurqanSoftware/codemirror-languageserver with additional features:
- Modernized codebase (linting, formatting, etc.)
- Testing
- GitHub Actions CI
- Symbol renaming
- Markdown code completions
- Code completion
resolvesupport - Code actions and quick fixes
- Go-to-definition
- Improved demo page
- Better error handling
- Enhanced documentation