LSP is an example of utterly horrid technical design.
Stop letting Microsoft design protocols and APIs. They are so. bad. at. it.
LSP is an example of utterly horrid technical design.
Stop letting Microsoft design protocols and APIs. They are so. bad. at. it.
Unfortunately nobody else stepped up to do it.
I'm glad that the code editors out there didn't wait for your theoretical better designed protocol and decided to adopt LSP. Otherwise we'd still have editor that only support one language properly, and the rest is treated like text. If the price to pay is that it sucks for the handful of people who have to work with it, so be it. For every LSP developer that suffers there are tens of thousands of downstream users who benefit from better language support in their favorite editor!
Emacs supported zillions of languages before LSP.
Zoom out.
Resolving file paths is not trivial because it's language specific.
Syncing source changes on the LSP server side is necessary to keep packet side small and patching is trivial (span, new text).
(I made an LSP-powered text editor and implemented LSP client from scratch)
So the LSP crashes and/or goes into a runaway memory consumption loop. And your main application dies with it.
Or what if you want, you know, to be able to use the same LSP from TWO different applications at the same time?
Never mind issues with other managed runtimes not expecting to deal with something else in their address space.
A synchronous function can also have obsolete indexing information if it races with the code updates.
But running the LSP itself is slow. It's not instant, and you can't run it in a blocking way for each keypress.
> func doLspStuff() { sleep(60000); }
Now sprinkle them after each keypress. Do you see the issue now?
In no way does this mean LSP is a perfect solution, but anything synchronous would be a step backwards.
Once you get past that, JSON-over-TCP is just another kind of asynchronous RPC mechanism, one that has the advantage that you can build it in just about any language with out-of-the-box tools. Trying to make a plugin system or a COM or CORBA or OLE based system really cuts out the ability to build language servers in most languages, because you have to be able to build the code in just the right way.
I can almost guarantee you that a synchronous API would yield a much more complicated design just because many operations can not be expected to reliably work within a few milliseconds.
You want to rename something across multiple files? Well now you add file system overhead and blow straight past reliable frame timings. Good luck waiting for that operation to finish. Of course you could make the API beginRename, and queryRename, or whatever you fancy to see if the operation was successful, but now you're back to what you wanted to avoid: an asynchronous API. Do mind that the example is actually one of the better cases, as many things you might want to do with a codebase are actually more expensive. You will feel the hiccups from waiting in the UI thread and you will loathe the program for it.
Would you write your editor that way if it didn't use LSP but was specific to one language? If not, but you would write it that way with a language plugin, why? You still have to write a good product. You can't blame the plugin API for everything you get wrong.
Parallel to that, IBM had SOM on OS/2, which was even better allowing for metaclasses and proper class inheritance, it was the key mechanism between Smalltalk and C++ on OS/2, where Smalltalk enjoyed a role similar to .NET on Windows nowadays.
OLE naturally still exists when using Office natively on Windows, other vendors seem to have forgotten about it.
COM's role on Windows has grown since Vista, and the Windows team redid many of the Longhorn ideas originally implemented in .NET into COM/C++, with WinRT being an evolution of COM.
Interesting to complain about one and then ignore exactly the same boilerplate for the other.
Leaving aside the fact that Microsoft's tooling for COM has already had multiple reboots between VB OCX, MFC, .NET Framework RCW/CCW, .NET ComWrappers, ATL, WRL, WIL, WinRT, each one with its share of astronomy.
No one uses the bare bones vtbl and nothing else.
Everything uses the bare bones vtbl. That's how there can be so many things, they're all using the bare bones vtbl. Obviously there's application specific stuff as well because a bare bones vtbl is not useful by itself but that's like saying if TCP is so good why is there HTTP?
The point being that beyond the plain vtbl, SOM was much better designed than COM, in the sense of overall architecture for application development.
LSP is a function call protocol. So that is already done?
Imagine if all the editing tools in microsoft word were specific to the language you used, and if you mixed German and English, each had different tooling.
Now if you mix Rust, HTML, JS, and CSS, they'll all have separate tooling, seperate "go to definition", and separate refactoring. Worst of all, none of them can see the definitions of the other ones.
So what you'd actually want to do is parse each language into your AST, with proper annotations as to what is what, and have all the "go to definition", the UI rendering, highlighting, refactoring, etc all done generically by the IDE ontop.
Which is much much closer to how Jetbrains IntelliJ does it, and why their tooling can handle "find usages" on an HTML element to find matching querySelector in .js files and matching selectors in .css
And if you subscribe to the AI stuff, you'd also want your AI to operate on this AST so it can learn skills that generalize across all languages.