How LSP could have been better
matklad.github.io
matklad.github.io
I want to write Python.
There’s one FOSS language server (pylsp) that’s a better fit for my needs than the other Python servers.
I want to use a certain commercial editor.
The editor and the language server don’t share a common configuration method.
Ergo, I can’t use the editor I’d like to write Python the way I want. It’s no one’s fault. The editor works just fine with other servers, for Python and for lots of other languages. The server is also operating within spec, and plenty of editors support its configuration method. However, they don’t play well with each other. I can still use the editor with that server as long as I’m ok with the default settings, but I’m not.
It would’ve been spiffy to have a preferred baseline method that all editors and language servers spoke, but they went the enterprisey “here are a hundred options - pick a few!” overly configurable direction.
Bummer. I really, really like that editor.
In fact LSP is mostly configuration agnostic. It might use configuration for a particular query like autoformatting, but it's still request/response in terms of text edits.
That’s just one example, not the lone thing users would likely configure.
Edit: More concretely, here are some of the config knobs you can twiddle via LSP for the particular server I’ve been discussing: https://github.com/python-lsp/python-lsp-server/blob/develop...
There are other plugins around with settings that aren’t documented there, but are still configured through the same mechanism.
In many cases the right tool is something like treesitter. Treesitter paired with an LSP is an incredible combination.
But yes, I understand your frustration. And if the best implementation happens to be inside the LSP then so be it.
The examples I gave were around lint-y types of things, but the same problem affects more LSP-y things, too. The link I gave has lots of tweakable knobs for refactoring plugins and other stuff that’s more philosophically in-scope for language servers.
The textDocument/diagnostic[1] is far beyond "the language model behind the text" and includes linting which many LSP servers implement (TS and python for example), and it can also happen as a "push" as opposed to "request/response"
[1]: https://microsoft.github.io/language-server-protocol/specifi...
LSP supports refactoring with "Code Action Request":
https://microsoft.github.io/language-server-protocol/specifi...
That's more than simply answering queries about the model.
If I can’t get it working to write Python the way I want, I’m going back to Emacs. It’s not a “native” Mac app, but doesn’t fall into the uncanny valley the way things like VSCode do.
The worst thing about Emacs is how it absolutely spoils everything else. Yes, it’s a pain in the neck at times, but you can change anything you want.
That said, BBEdit got far closer to my platonic ideal editor than VSCode ever did, and it’s nice enough in other ways to win me over.
But Emacs is still alluring enough that I spent like 4 hours over the last few days trying to get clangd to work in a project that involves cross compiling C++ in a way where generating compile_commands.json does not seem possible, with no success, even with the help of clangd contributors, where VS code somehow is able to just work with minimal configuration of the C/C++ extension. Someday I will stop doing this to myself, hopefully.
If you figure out how to stop this, please let me know.
Rather than fixing the problem by using code points, they made it worse by allowing any encoding. Now, not only do you need to support UTF-16, but also UTF-8 and UTF-32 [1].
[1] https://microsoft.github.io/language-server-protocol/specifi...
Code points is the only thing that makes sense for a multi-language protocol. It’s unambiguous and every Unicode client can talk in code points, even if they use some exotic encoding.
https://github.com/joaotavora/eglot/discussions/1127
I don't know enough about emacs and LSP to see the full picture, but it seems that both eglot's and corfu's maintainers, assumably very competent programmers, can't find a solution for this.
I only skimmed the thread. My understanding is that LSP dumps a long list of completion candidates at once and they can't decide a cache strategy that works well with existing code...? If someone who know more about this please enlighten us.
As a longtime user I couldn't be happier: https://company-mode.github.io/
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=8bf4c...
Do note that many users might have not been aware of this issue. The fixed library is part of Emacs 29. If you are not on Emacs 29 you might pull in a more recent JSONRPC-package from ELPA in which case it will shadow the inbuilt/pre-shipped library.
1. The issue you identified which is about caching. It seems you can work around this issue by using a cache busting hook from cape.
2. An unsolved issue where eglot and LSP get out of sync which seems strongly correlated with using corfu. I've been experiencing this a lot with eglot+corfu+rust-analyzer. I'd estimate about once per hour I'll notice that things are just wrong, as in red underlines in nonsense places with nonsense error messages and completion no longer working or working incorrectly. Running a M-x eglot-reconnect "solves" the issue for another ~1 hour.
The way these two issues were related is the author of eglot states that they have sunk considerable time investigating issue #2 with no success, and they argue that it is not worth their limited time to continue investigating #2 when corfu is broken by design[^] w.r.t. #1.
And yes, I'd agree that this doesn't seem to be an LSP issue but rather an issue solely on the client side.
[^] https://github.com/joaotavora/eglot/discussions/1127#discuss...
Once you try to use LSP for anything not in that form.. it's not so fun.
As far as I know, the only languages with something even vaguely like this are Pharo Smalltalk (with its git integration) and unison
Also, it ends the formatting wars because the in-repository format is disconnected from the user’s preferred format.
I don’t think any editor would want to accept this workflow. The biggest issue is that writing is reputation-critical, if the editor writes to the wrong place, or it fails to write when it should have written, then users lose their work which makes them very unhappy. So the editor has to take responsibility for doing the writing, and that is the user’s mental model when they save their work.
[1]: https://calpaterson.com/bank-python.html
[2]: https://www.unison-lang.org
[3]: https://pharo.org
The rationale is that only the editor knows what files are open and modified. Also we can imagine scenario where the editor and the language server are on different remote (eg GitHub codespace or the browser version of vscode. The language server could be a wasm build running where the editor is running, but the editor may access files in a remote server, or vice versa)
I really dislike this, instead of a fuzzy file finder I want a fuzzy function finder, where all functions are just kept in a database that I can pull into buffers at will. Where hierarchy is only based on the logical structure of your program and the filesystem ceases exist. "New Function" over "New File". You can get the "Fuzzy Function" finder part somewhat with LSP Symbols, but it doesn't get rid of the having to think about files.
Unfortunately I don't think you can get this without first-class support by the language itself, and new languages getting critical adoption isn't a regular thing.
I don't want to edit a "file", I want to edit these two functions that exist in some module(s), why can't I just see those two?
I constantly jump between many different languages and the cognitive load is noticeable: was it "!=", "/=" or "~="? Why am I writing/viewing ascii art when I'm coding?
If I am most comfortable/fluent viewing python, why can't I view a javascript source as python?
I think the remaining challenge is what sort of projections are the best/most useful? How do we manipulate these projections? I have played around with these ideas and made an AST viewer for the browser where you could configure exactly how a node was represented (using CSS) and navigation was done in block mode (node traversal) but I found it really hard to build an editing experience that felt smooth..
Because they are not isomorphic. At all. Even if you just consider the languages themselves, and ignore their ecosystems, which, in practice, you cannot.
For machine manipulation, I think it makes more sense to directly manipulate the AST.
For human manipulation, I think the cognitive overhead of mentally converting between the display syntax and the canonical syntax would far outweighs any gains in readability. But maybe your workflow is different than mine - If you have a lot of custom macros in your editor, I could see s-exps being useful (although, again, I think exposing and directly manipulating the AST would be less error prone)
If you designed the languages and interpreters/compilers around it. Neither Python nor Javascript are, though.
That shift happened like 20 (?) years ago. That's how Eclipse displays your Java stuff. It goes to a great length to pretend that there aren't files. Instead there are packages.
Seeing noobies and experienced programmers struggle with it for years, my conclusion is that this is a bad idea. Most problematically it creates "programmers" who have no idea how their project is actually organized, or how to open files that nobody from the ops department put into their editor in such a way that they can be discovered. The amount of dumb questions I had to deal with is on par with those IT stories about outrageously incompetent users pushing mouse buttons with their foot or forgetting to plug their appliance into power supply.
In practice, the more programmers are removed from the actual thing they are programming, the worse are the results, the lower is the competence and the more resources are wasted. I would rather live with the downsides of poor synchronization between the language server and the files I'm editing then let the language server be in the datapath. Too much headache for very little gain.
I'd only add that well before Eclipse and its ilk, Java started down this path with the deep filesystem paths that made it painful to work with from the filesystem without the kind of multi-level collapsing Github does. It was a choice that pushed people towards seeing the filesystem hierarchy as a nuisance, and laying the groundwork for encouraging people to obscure it in IDEs.
Java’s filesystem hierarchy is a great example of a “fileout” format for the sort of environment I’m talking about. Another example here is smalltalk repositories generated by Iceberg: https://github.com/pharo-vcs/iceberg
I personally find Common Lisp and Clojure much easier to navigate because I can just ignore the filesystem layout and use the in-image database of code relationships to navigate.
Again, note that nothing stops you from ignoring the filesystem when navigating relationships. Nothing stops your IDE from indexing the data. Even ctags is decades old.
What the filesystem structure provides is additional context: "these things belong together for some other reason than the relationships directly expressed in code.
In a codebase where nobody bothered with that, or they've just dumped code together for superficial reasons sure, you will gain nothing, but you also lose nothing because you can fall back to querying your IDE or whatever.
In a well written codebase, on the other hand, the structure lets you follow a narrative.
Put another way: If you need to query a database to get a high level understanding, it's a strong signal that the person who wrote the code thought nothing about communicating the architecture to you, and to me that's a warning that the code base is going to be a massive pain to work with because that tends to extend to other areas.
Sure, but all these systems do significantly more work than necessary (or have subtle caching issues and race conditions) because they have to be continuously reindexing an anemic model of the code base.
As far as image-based systems go, give me one of those any day: Common Lisp and Smalltalk have tooling and introspection capabilities from the future. My own experience is that I’m significantly more productive getting up to speed on a new Lisp (Common Lisp, elisp, Clojure) codebase than on any of the alternatives because the system stores so much metadata about the entities.
Also, I think you're underestimating the capabilities for forming narratives that my proposed system gives you: views, stored procedures, various tools built on things like graphviz for visualizing the structure of the code.
The layout of files on a filesystem is not how a project is organized. The organization of a typical project is a graph that’s lossily represented by filesystem trees.
I.e. be it Ant, Maven or Cradle, in order to carry out project-related tasks they will rely on files. They feed files to various tools, create new ones, delete or move old files, and then the deployed project needs to discover those files somewhere and so on.
When a programmer doesn't understand how what they are presented with in their editor maps to whatever any of those tools do you get questions like: "Where is my Java home?" or "I want to debug in the testing environment, can you tell me where is it?" or "I think I've built my program, and I want to patch the existing deployment with the program I've built -- how do I find the program I've built and where is it deployed?". Not to mention more trivial stuff like developers arguing about having / not having access to eg. Protobuf files in their project because someone's editor not having a plugin to open them and they simply don't know how to find their project directory on their computer... or trying to run poorly written Maven build which has some relative paths in it, from a wrong directory.
(1) the editor read the files, display then, and then sends changes to the LSP which then mirrors the file to compile, analyze, etc it. The file is never persisted in that stage to the file system (needs to because otherwise no syntax highlighting while editing.
(2) there are conversations about that in both the LSP and Editor space about virtual file systems. Google "language server virtual file system". The core author of the LSP spec has written one issue very related to it.
[1] https://github.com/microsoft/language-server-protocol/issues...
Even when the proposal of "UTF-16 default, UTF-8 optional" was made to keep backwards compatibility, it was not enough. It has to be UTF8 because it's superior technically, as if that's the only consideration! I agree they should've just picked one, but I still don't think the maintainers needed a refresher on what is UTF-8 every 3 comments.
But I wouldn’t be annoying about it. I’d just tut tut from afar. (Though if the decision is still up in the air, I’d argue as passionately as any preacher to persuade our fellow devs to adopt our lord and savior UTF-8 into their hearts and minds.)
But I think the worst part was that the maintainer was clear that he/she wasn't debating this on a technical level. Like, they weren't trying to decide which encoding was better. From what I understand it was more about how best to deal with the (at the time) current design choices without breaking the current implementations, and feedback from actual implementers.
* LSP is being used outside of VSCode, and while UTF-16 may be helpful in that case it's a hinderance for others.
* Institutional knowledge of UTF-16 ain't great at Microsoft either. Github broke rendering of multibyte characters and it took a random GH user to the devs explain how multibyte characters and strings interact in Javascript before that got fixed.
* [insert lots of handwaving about the downsides of electron]
[19]: https://github.com/microsoft/language-server-protocol/issues...
I believe the original producers and consumers of LSP were written in languages that had string lengths based on UTF-16, so it was the literal easiest way to do it, even though UTF-16 is probably objectively the most painful thing to compute if your string system isn't UTF-16.
LSP eventually got a solution where you can request something other than UTF-16 offset calculations, but I don't remember the details of what that solution is.
Traditionally though OCaml editor integrations have also supported not only asking just the type of a symbol, but of an expression. I wonder if LSP can do that, because that function needs some interactive scoping of the query, not just a single point, or I suppose it can work if hovering over parenthesis but if precedency needs to be accounted for, it would be difficult to understand what the user wants to see.
I've _really_ enjoyed the expression type queries in the past, but I haven't coded OCaml for a while :/.
I read some factual inaccuracies here.
LSP (the protocol)'s main driving force was for a long time TypeScript rather than JS. FYI TypesSript has a stronger type system than Java at this point, and it's LSP server is the most comprehensive and supported way to write TS with.
Another example of an LSP success story is Rust's rust-analyzer. Not to mention that C++'s clangd also became an LSP server many years ago.
All these are strongly typed and bring extra semantics (templates, lifetimes) way beyond other languages.
"query type of symbol" functionality is provided as an example by the textdocument/hover call [1]
But even if this wasn't implemented, the protocol lets any implementor extend the interface with additional / non-standard methods (and clangd did exactly that[2])
It might be that the not-widely-popular ocaml's LSP support is not there yet. Probably it's an open source project, so you can help with the implementation, or at least vote for missing features to be implemented.
[1]: https://microsoft.github.io/language-server-protocol/specifi...
https://github.com/rust-lang/rust-analyzer/blob/master/docs/...
Works fine in other LSPs.
https://microsoft.github.io/language-server-protocol/specifi...
I look forward making tabs vs spaces a viewer setting and not an author choice.
Unfortunately, though, everyone who has used tabs got bitten by stupid text editors that don't make it obvious whether you've used a tab or a space and substitute a tab for any run of 8 spaces. So if you're aligning an argument list you'll get a mixture of tabs and spaces. Everyone got bitten by this once back in the day then switched tabs off forever. They then switched tabs off in the text editors that the next generation are using.
> This is indentation whitespace, display it how you like
It should be
> This is a function body, display it how you like
Not only should readers be able to differ about how much whitespace is shown. They should be able to differ about whether it's whitespace that is used at all. Maybe they want something crazy like it makes a different kind if sound when you look at it, or appears in a different color or font. Whatever it is, it's no business of whoever is writing the program--they ought to be able to have an entirely different experience while still kicking out the same program.
I'm more than happy to let something like Black handle formatting for me, though. Sure, there are some occasions where my own formatting would have been better, but the benefits far outweigh the (very small) costs here.
The silly thing is with tools like Black etc. it should be possible to use tabs again. If the only reason against tabs is people fuck it up, there's really no reason to use spaces in an auto-formatted project.
But then we'll just have AST vs tabs & spaces. A layer down, tabs already should've solved 2 vs 4 vs 8 vs whatever spaces by making the semantic separation a single character, and the representation of it an author choice.
It's just the lowest common denominator, and it will always be that. Revision control tools, editors, compilers, the entire world is built around this. And there's no single alternative that could take its place.
The reality is that systems like a Smalltalk image or stored procedures in a database, or a fancy IDE, or whatever are just going to have to bundle tools for good interop with filesystems at that level, and that's just how it goes.
In the end what we have in text files is a mediocre, but universal, interop system.
With that LSP would not solve the n x m problem of editors to languages but would require all text editors to reinvent themselves into something completely different.
It makes the (probably reasonable) assumption that all development happens in file-based text editors, and imposes the text editor model. That's fine, but there are other ways to organize code objects, and the LSP ecosystem is mainly useless to them.
Which is frustrating for the people working in or on that model, but maybe of no concern to others and probably no reason VSCode etc would want to have focused on the possibilities of that alternative.
But it means people doing the heterodox will have to reinvent the wheel completely instead of partially.
Hopefully LSP specification can evolve over time and incorporate some of these ideas!
Visual Studio was a meme for a long time because it was so heavy and enterprisey, so to capture more market share they made the cool new shiny version VS Code, and wanted to compete with e.g. Atom whilst still having their grip on the ecosystem as a whole.
So LSP was born. It has a lot of problems. It only really works well with VS Code (yes, there are exceptions, but not many, and they aren't paid for by a mega corporation).
This is Microsoft's way. They try to sway the developer community through force, not persuasion.
[0] https://en.m.wikipedia.org/wiki/Embrace,_extend,_and_extingu...
They could've simply integrated TypeScript into VSCode using a proprietary protocol to keep people locked to it. Instead they took care to make a well documented and reasonably open protocol that others can use for their own language support, and to integrate TypeScript into other IDEs.
I really don't understand what you think they should've done instead.
Do you think that the world where every compiler has its own API is better? You're still free to do so - just develop an extension for VSCode and/or all the other IDEs instead of a single LSP server implementation.
Building VSCode, LSP and Typescript could still prove to be the Embrace and Extend phase. There are some worrying signs, e.g. many VSCode extensions built by MS don't work on open-source VSCode builds like code-server and VSCodium. From a business perspective, this makes sense, as GitHub Codespaces and vscode.dev now have features that are difficult to get in competitors. Maybe at some point they will try to Extinguish all local development and push everyone to use a cloud version of VSCode? (See e.g. Python integration in Excel)
The truth is probably a lot more complex, but we can't rule out anything yet.
They are not extinguishing their own products, but using their products to extinguish alternatives. The example I mentioned actually fits the wikipedia definition quite well in my opinion.
Nonetheless Microsoft managed to use CSS to achieve a great deal of user lock-in by refusing to conform to the standard they co-authored.
- Extend the web with CSS as an open standard.
- Extinguish competition by being the main browser and not following the CSS standard.
Still follows the recipe quite well in my opinion.
As well, Microsoft is building a wealth of VS Code-only features and LSPs (locking out VSCodium), by the end, they will have taken from open source and not given anything back.
This is not true since LSPs can add extensions to the existing API. For example: https://github.com/rust-lang/rust-analyzer/blob/master/docs/...
> If you create an LSP, it will work best in VS Code.
Any editor can work just as well as (or even better than) VS Code.
This was something that had puzzled me for a while until just today when reading another post on the original linked article's site.
It seemed odd that after MS had used Atom/VSCode to essentially "suck all the air out" of the FLOSS/free editor space that they would then "share" something like LSP which seemed to then make it easier for other editors to (at least potentially) offer a similar standard of support for languages that had LSP implementations.
(Because from a purely technical POV I do see LSP as a positive development in the editor space.)
But what I'd apparently missed was something mentioned in an earlier "Why LSP?"[0] post by the same author:
> "[...] Microsoft, who were a vendor of both languages (C# and TypeScript)
> and editors (VS Code and Visual Studio), and who were generally losing
> in the IDE space to a competitor (JetBrains)."
and, so:
> "...launched LSP to increase the value of their platform in other domains
> for free (moving the whole world to a significantly better IDE equilibrium
> as a collateral benefit)."
Thus, assuming this is accurate, the actual target in this case was JetBrains and "sharing" LSP was seen as a reasonable "cost" in order to get additional leverage.
Given that I haven't generally paid attention to any of the C#/TypeScript/JetBrains worlds that was an angle that I'd missed.
The assumption on my part that "sharing" LSP still wasn't likely to be an "altruistic" act on the part of MS was primarily driven by the fact that they hadn't really given up on proprietary/control they'd simply moved the demarcation point to be at the LSP implementation level (e.g. the plugin for Python) & "marketplace" access (e.g. remote plugin) etc (e.g. telemetry).
And by defining/retaining control of LSP they've inserted themselves in the path between other editors & LSP implementations which inherently has value (e.g. by being the "reference"/default implementation[1]).
Anyway, that was an aspect of the context for LSP that I wasn't aware of before today, so thought it might be of interest to some.
(Obviously the majority of today's developers see no issue with the actions of MS in any of this, so, if that's you feel free to agree to disagree & leave the rest of us to tilt at windmills in peace--after all, why would we stop now? :D )
[0] https://matklad.github.io/2022/04/25/why-lsp.html#Why-LSP-is...
[1] Which is one of the reasons I'd really like rust-analyzer to one day change to target an editor implemented in Rust by default. VS Code doesn't need any more value added to it for free but any Rust-based editor would benefit from being a "First Class" rust-analyzer citizen & thus strengthen the wider Rust ecosystem.
It is still top IDE matched by maybe just JB
Instead of every single editor having to understand C and Python and JavaScript and Rust and SQL and Ruby, they only have to know how to talk to a language server using a standard protocol. And if you’re writing a new language, you can make a language server for it, and then every editor that knows how to use LSP can be used to comfortably write code in that new language.
The old way is that M editors want to support N languages, someone has to write M times N language parsers. With LSP, they can write N. That’s way less work.
Typically a language compiler runs over the source files and terminates once it's done. All the compilation states are gone. The language server is the compiler itself running for a long time; its aim is to maintain the compiled states of the source files alongside of the editing session in the editor client. It's ready to answer requests from the editor in regarding the source code.
E.g. The editor loads a source file. It sends a LSP request to the language server saying the file is opened. The language server would compile the file and maintain its compiled states. The compilation process might involve other source files as well. The language server reports any errors or warnings back to the editor. The editor shows them to the user right the way.
The user modifies a function and hits save. The editor sends a file-changed request to the language server. It recompiles the file and sends back any errors or warnings.
The user places the cursor at a function call and issues the jump-to-definition command. The editor sends a LSP request to the language server to look up the location of the definition of the function. The language server has all the compiled states of the source files and knows where the function definition is. It sends back the target location (file and line number). The editor can switch to the target file and jump to the line number.
LSP defines a whole bunch of these requests and responses (e.g. looking up the type of a variable, definition of a value, auto-completion suggestion of function parameters, etc). A language server for a language can implement these and suddenly all the clients that talk LSP can utilize the features.
Where does the language server typically run? Does it run on some remote server or as a separate process next to your editor on your local machine?
E.g. when the editor opens a Rust file, it would launch the Rust language server and connects to it. When it opens a Javascript file, it would launch the Javascript language server and connects to it.
Running the language server remotely would require more setup. The editor and the language server need to look at the same file, so you have to sync the changes to the file locally and remotely somehow. Also the editor might not be able to automatically launch a remote language server. You have to start it manually and make the editor connect to it manually. It's just not a smooth UX.
That's where the sibling protocol, DAP, comes in. Rest of this is a good simple explanation on what LSP does, otherwise.
None of this is new. We've had TAGS tables forever. Certain editors would provide the rest for certain languages in language-specific ways. LSP is just a general solution to the any editor/any language problem. It seems to work at least as good and often better than the custom solutions before.
The standardization that LSP brings is nice, but from a user's point of view it's pretty terrible compared to existing custom solutions. At least for the few languages I tried; Scala and Haskell. The feature set supported was very small compared to what existing integrated editors supported, it was slower and less reliable.
But it's certainly not going to beat something lime SLIME for Common Lisp and obviously not editing Emacs Lisp within Emacs.
Rust, Go, Dart, etc all vastly superior. I recently opened up a powershell script in nvim and even powershell's LSP is better.
I guess there is a new C# LSP with C# Dev Kit and it seems better in vs code but I haven't tried to use it with nvim yet.
> In the programming language world, there's this thing called Language Server Protocol that is pretty much the worst thing I've ever heard of. There are proponents of this all over, building systems for it right now that are going to be living on your computer tomorrow, or maybe even today. As far as I can tell, it's basically a more complicated, slower way to do libraries.
> Say you've got an editor for some programming language and you want to be able to do stuff that we've been doing for decades already. For example, look up the declaration of an identifier by clicking on it, or have tooltips that say, "What type is this value?" Well, they say the way you should do that is—you know, you have your editor and then it's a hassle to make plugins. This is the made-up problem. It's a hassle to make plugins for all these different things. So in order to standardize, you're going to run a server on your machine. Then your editor talks over a socket to the server, and the server talks back and gives you the answer. This approach has now turned your single program into a distributed system.
> The flaw in this whole line of thinking, that none of these people seem to actually think about, is that there's nothing special about looking up the location of an identifier in your code. That's just an API, like we have all the time for everything. So the obvious next step, if you're saying that we should architect our APIs like this, is to do this for other tasks. Now your editor, or whatever program, is going to be talking to multiple of these things. If you ever want to author anything for this, you now have to author and debug components of a distributed system where state is not located in any central place. We all know how fun that is, right?
> But of course, libraries are not that simple. Libraries use other libraries. So what happens at that point is you're running all these servers on your system, and who knows, some of them are going to go down and have to restart. People are synchronizing with each other—no, this is a disaster. And people are actively building this right now, while we're spending all this time overcomplicating stuff that we used to be able to do in 1960.
(Transcript produced by asking GPT-4 to clean up the raw output from youtubetranscript.com: https://chat.openai.com/share/e1bc0e87-f79e-4958-98e7-b93c1b...)
>What type is this value?" Well, they say the way you should do that is—you know, you have your editor and then it's a hassle to make plugins. This is the made-up problem
Ok so it's just a made up problem? Like, the "plug in" part or the need for having tooltips/completion etc? If he was referring to the perceived need of a plugin (vs. a more integrated) architecture being just due to a made up problem, the linked article in this thread shows this is absolutely not the case. I'm not sure it's better to reimplement the same features every time for every single editor?
And if he meant that needing IDE features is the made up problem, then I guess... lol ?
>People are synchronizing with each other—no, this is a disaster. And people are actively building this right now, while we're spending all this time overcomplicating stuff that we used to be able to do in 1960.
I get the "old good" aesthetics he always aims for, but come on. Even the most charitable interpretation of this part is ridiculous. Like sure we probably had some IDE features back then, but that's not the point of LSP. The point is standardizing said features. And specifically, the interface to access them without knowing anything about the editor or how the code is written.
I'm sure your proprietary custom made computer was able to get or provide code completion from other ultra closed systems in the 1960s. It would've been helpful for him to be more specific about what exactly they were doing back then. Again, the whole point is to not have to reimplement a sort-of-compiler for every editor and whatever quirks it comes with.
He is not even doing the regular "YAGNI, it's bloat", it's just downright weird and devoid of actual arguments imo. I'm not even saying he needs to propose a better way to do it, because he doesn't even seem to acknowledge the point of language servers
It's not unreasonable to expect an editor's developers to know how to link a native library.
Oooorrrrr, you could communicate with another process via stdin/stdout and call it a day.
Also the original complaint was about explosion of language combinations and I just pointed the solutions to this are well known.
I believe his opinion is that there shouldn't be LP (since he's against to use servers I remove the S from LSP) written in language that can't be compiled to xxx.so. We're talking about Jonathen Blow after all.
It make sense if you view LP as a part of an editor. But in our reality the language servers are often maintained by that specific language's community, not the editor devs, so it's probably not the best idea to expect them all to be willing to write in low-level language.
I used to disagree with Blow on this point, as stdin/stdout communication really has the arguable advantage that you can write your Brainfuck LSP in Brainfuck, but I've spent way more time than I find reasonable over the last few years dealing with the consequences of the LSP model - tweaking environment variables, paths, command line arguments for the server, server crashes, mismatches of server version vs the compiler, the client picking the wrong server executable, system-provided language vs downloaded by VS code extension......
I'd rather just drop a dll in Plugins/ and be done with it.
Feel free to only use languages you personally find aesthetically pure. The rest of us will continue getting work done.
So in the end even if you had the option of running the language plugin within the same address space, probably you wouldn't want to. A better RPC protocol than JSON would be nice, but a standard is better than no standard.
I don't think he is arguing against a standardized interface to language-specific logic, but arguing for that standard to be a library interface, not a distributed system.
It's not super convincing to just dismiss the only solution that seems to have sort of worked by saying that we only had to keep doing it the way that never really worked.
I'm sure the implementation can be a lot better, but he does not provide any argument for why the architecture itself is bad. Sometimes abstractions are actually useful.
One thing that Blow misses IMHO is to what extent libraries introduce these failure modes _too_: A library can crash as well (and take down the IDE with it), and multiple libraries that deal with the same data can get inconsistent. That's actually a problem of quality control, integrating code from multiple third parties, and so on.
This is just an "old man rants at cloud" take.
Game programmers spend their careers writing C++ where, yes, you really need tricks like this to rename the variable, as the language is so fucking insane that ALL tooling gets it wrong - and the consequences of getting it wrong can be disastrous.
The most widely used options for C++ are VS's IntelliSense and clangd. IntelliSense is utter garbage, I never trust it for renaming things. clangd is better but can still get things wrong if your build process is complicated your compile_commands.json doesn't perfectly reflect it.
Managed languages have fantastic tooling with perfect context of your project, but they're also managed and are not applicable in a lot of environments.
Yes, clangd is accurate but when you have different build variants only one is reflected in the current compilation database. clangd will be perfectly accurate for this current variant, but blind to others.
Would clangd support a merge of several compilation DB into one? If a file appears several times with different options (typically include paths and defines), would clangd handle all variants in parallel or just pick one (first or last)? I haven't tried (yet ;).
It's manageable, and sometimes I'm reverting to pure "text level" changes or searches to work around this.
LSPs solves two "made-up" problems. Editor and LSP team can be different and independent. Go teams work on LSP without actively collaborating with VSCode team for feature and release. Second, both can run at different places, it allows for things like devcontainer and Codespace. code is built/run on some remote server while IDE is running on local.
At the same time, libraries, sadly, do not actually exist. I can not easily cook up an `.so` and then hook that up with Emacs, Vim, VS Code, and Helix. Moreover, any crash in an `.so` library brings down the whole process, which isn't a good idea for an IDE.
Maybe several years in the future we get an actually good implementation of libraries (I have high hopes for WebAssembly component model), but until then, text-over-stdio can actually be better in practice for some use-cases!
If you are going to have a background thread that calculates results for autocomplete, then it helps to give it a protocol.
Spin?
> The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc.
https://en.wikipedia.org/wiki/List_of_Adventure_Time_charact...
Article content in full: She couldn’t.
I was floored to see the "fix typo" link at the bottom. Submitted. I now wonder if the typo was on purpose.
In the real world, many of us would take the time to fix a splinter in a well-traveled floor. I love that your appreciation for robust protocol includes a mechanism for moving the digital world in that direction.
I found myself daydreaming how blogs would work if the author turned their brilliant attention to the process of blogging itself. They would solve such a problem, to encourage collaboration.
I was therefore stunned to see a "Fix Typo" link at the bottom. Perhaps this has become widespread, but I'd never noticed it before, and the logic of having this author provide such a link amazed me.
Part of what we do in comments is appreciate various aspects of a work. I was appreciating this aspect of this work.