Hey, I’ve been able to get this working pretty well (autocomplete, type error lints etc.), so I’m more than happy to help. One of my goals was to build an editor that worked without a backend running the LSP server, so all of this happens in the browser only.
Unfortunately my code isn’t open source (yet), so I cannot point you to a repository, but here’s the overall gist of what I did:
- When you talk about the Typescript LSP, I’m assuming you’re talking about
tsserver
, which ships with Typescript and is the “brains” behind the compiler, so to speak. - Don’t try to run
tsserver
on your own. While I did manage to do it inside a WebWorker, it’s far too tedious. The Typescript folks maintain @typescript/vfs - npm, which is exactly what you want (and is fully typed!). I would also recommend fetching core TS types from the Typescript CDN usingcreateDefaultMapFromCDN
. (I personally had my own CDN setup, but the public TS one works just fine). - It is also worth it to understand
tsserver
commands. Their typings are a great place to do that: TypeScript/protocol.ts at main · microsoft/TypeScript · GitHub - Once you get Typescript working, wiring it up to CodeMirror is a matter of using the
ts.languageServer
instance in the correct places. - For linting (showing up type errors as squiggly lines) you’ll want to use the
linter
extension from@codemirror/lint
. Inside the lint source, I make a call out tots.languageService.getSemanticDiagnostics
- For autocomplete, I also found the blog post Marijn linked, but it didn’t prove very useful for my case. Instead, inside the
override
function of theautocomplete
extension, I make a call out tots.languageService.getCompletionsAtPosition
. This is very inefficient though, as the call will happen on every keystroke, debounced (it’s not really noticable for small lists becausetsserver
is built to be fast), so I’m still trying to figure out a better way.tsserver
also has something called CompletionEntryDetails, which returns more “details” about an autocomplete item. They’re meant to be used to render details about the currently highlighted autocomplete item, but I’m yet sure how to get this information from CodeMirror, so I also fetchCompletionEntryDetails
for all autocomplete items usingts.languageService.getCompletionEntryDetails
. This makes it even more expensive, so be aware. - You can also use the
hoverTooltip
extension from@codemirror/tooltip
. In here, I make a call out tots.languageService.getQuickInfoAtPosition
. - One last thing to remember is that you need to keep
tsserver
's view of the currently open “file” (tsserver deals in terms of files) up-to-date with what you see. To do this, I override thedispatch
function of the EditorView, and make a call out tots.updateFile
from there, AFTER updating the view. make sure you debounce this to avoid UI freezes.
I’m still actively working on this TS + CodeMirror powered editor, so some things are far from perfect (and other features are missing), but overall it works pretty well!
A motivating factor for me was looking at Monaco Editor that the TS folks use on the TS Playground (typescriptlang.org/play/). That does not talk to a backend running an LSP server either, so everything they do in there is possible in the browser. Good luck!