Why LSP?
matklad.github.io
matklad.github.io
This is just wrong, https://vimhelp.org/insert.txt.html#compl-omni
The first occurrence of "omni" I can find in the git log is this commit from 2012:
https://github.com/vim/vim/commit/5d3a8038b6a59e6f1b219f27ec...
which means it's even older
I don't think the Emacs situation is bad at all, but I agree 100% that it needs third party plug-ins to be anything close to what people expect of an editor in 2022.
>Contrast this with Emacs and Vim. They just don’t have proper completion as an editor’s extension point. Rather, they expose low-level cursor and screen manipulation API, and then people implement competing completion frameworks on top of that!
People don't implement competing completion frameworks on top of "low-level cursor and screen manipulation API". There are more high-level APIs included in Emacs, such as completion-at-point. To quote company-mode's website:
>The CAPF back-end provides a bridge to the standard completion-at-point-functions facility, and thus works with any major mode that defines a proper completion function.
To me the author misrepresents what Emacs has built-in and what package writers use.
Technically company-mode isn't third party, it's part of GNU Emacs. It needs to be downloaded, yes, but it's not third party. Emacs needs a package recommendation engine (I know VS Code has this, awesome!).
What you get with ivy/company/etc is different ways on how to expand/handle/show completions and they're all still relevant.
I'm using different frontends depending on the mode that I'm using. I personally dislike pop-up style completions. I'm using a mixture of completion buffers (the boring emacs built-in ones) ivy and ido instead.
Why is that? Emacs comes built in with modes like `fido-vertical-mode`, which are arguably more powerful and modern than `company-mode`. They're just not turned on by default.
Having LSP support was a godsend for things like Emacs and NeoVim.
I don't expect that very long time users and hardcore adopters (people who actually regularly spend time programming their editors in Elisp/Vimscript/Lua/etc) of these programs are not going to see it because they have their own tailor made custom workflows that work for them and would be disrupted by switching to LSP.
But for everybody else LSP has made things SOOOO much easier and better. It's ridiculous how much better things work nowadays.
Years ago I would spend weeks farting around with this or that python plugin to get something working really well in Emacs or Vim. There was a whole mess of different frameworks and plugins, dependencies, and scripts that any user had to wade through. A lot of "work for me" type post. Posts implying that icicles the best thing you could ever possibly use in Emacs and things of that nature.
Nowadays I can just install Doom-Emacs, enable the LSP support for whatever language-of-the-day I happen to be looking at... run doom doctor to tell me what dependencies to install and have actually really good language support up and running in about 20 minutes of work and reading. Another 2-3 hours to get used to the key bindings and basic functioning and I am off to the races.
It is actually really nice.
VS, Eclipse, Netbeans, Delphi, C++ Builder, KDevelop, QtCreator,...
> Notably, the two-sided market problem was solved by Microsoft, who were a vendor of both languages (C# and TypeScript) and editors (VS Code and Visual Studio), and who were generally loosing in the IDE space to a competitor (JetBrains)
Nope, the IDE space on Windows has always been owned by Microsoft since Borland dropped the ball with their management crisis where to go next.
VSCode and LSP were created out of Monaco and Erich Gamma's stewardship, yep one of the four on the patterns book, and original Eclipse team.
"VS Code an Overnight Success… 10 years in the making"
My understanding is that the state of semantic IDE features for C++ was pretty miserable until CLion and clangd came along.
That is, sure, there were a whole lot of “literally” IDEs — gui wrappers around editor/build system/debugger/compiler combos. In the post, when I say IDE, I focus on “refactoring rubicon” connotation of the term, not on the literal meaning (https://martinfowler.com/articles/refactoringRubicon.html).
Here is the documentation to cadillac, https://dreamsongs.com/Cadillac.html, and the respective demo of their XEmacs based environment from 1993.
https://www.youtube.com/watch?v=pQQTScuApWk
Refactoring is one feature of IDEs, not the whole package.
Still, here is your refactoring rubicon in Visual Age for C++ (1999), http://www.edm2.com/index.php/VisualAge_C%2B%2B_4.0_Review
https://www.developer.com/java/suns-forte-developer-7-simpli...
Still available under Oracle, now rebranded as Oracle Solaris Studio.
https://docs.oracle.com/cd/E24457_01/html/E21989/gkofj.html#...
Example, these blog posts from 2009 showing that KDevelop already had semantic highlighting, smart auto-completion, quick fixes and whatnot https://zwabel.wordpress.com/
KDevelop had its own C++ parser at the time, and it was quite good. Same for QtCreator. They both moved to use libclang much later.
Speak for yourself. Editing C# is much better in Rider than VStudio.
Eclipse was a competitior, but I dread having to use it for anything nowadays. CLion just doesn't work correctly, yet.
For Rust VS Code is better, but only because of awesome rust-analyzer plugin.
Eclipse is still my get to go, InteliJ wants me to buy Clion + InteliJ licenses for features Eclipse does out of the box.
VSCode isn't an IDE, plus Rust is the new kid in town.
Add enough plugins and it will be. Rust being new is one part, other part is that Jetbrains really insists on their plugins vs LSP.
I get Rust errors in Clion on programs that run normally. Bugs that rust-analyzer/cargo don't report.
This allows significantly more functionality than any type of LSP + editor ever can. The refactoring functionality is what makes an IDE into an IDE. I use every single feature of IntelliJ every day, and I actually would prefer even more refactoring functionality. LSPs can’t come close to this.
LSPs can compete with classic Visual Studio, but there’s a reason JetBrains started with ReSharper, replacing the refactoring engine of Visual Studio.
Rather arbitrary distinction that doesn't even hold true for all IDEs out there.
Can you select a function and drag and drop it into a different file or class and have the code automatically adapt, add/remove parameters, imports, etc as needed?
If you have two functions called doA, in different modules, and you have a file that imports doA from module 1, and you copy that doA call and paste it in a new file, does the IDE correctly add the import as well, or does it just paste the text and you have to import manually?
I don't remember having any opinions on Kotlin. I've never seen it use in production, just tales.
You sure, you don't have me confused for someone else.
Anecdata time. I was working on codegen in C#. So I wrote the codegen in netstandard2.1. That is until a team member that used Visual Studio complained it didn't work for him. So I had to rewrite the thing in netstandard2.0 (shudder) and it worked.
I haven't seen anyone that wanted to go back to VS after using Rider. I did use it for a while, but after Rider it just seemed like an inferior version.
How is autocomplete better in Rider? Faster coming up with suggestions? More helpful suggestions? IntelliSense and IntelliCode in latest VS versions is pretty decent...
Performance in VS has improved since going 64-bit.
What refactorings are unique to Rider?
UI? What features?
Your statements smells of preference and sound vague.
Because it is. My preference, never claimed it wasn't one. But I don't know people that would recommend anything else. VS Code is faster but poorer refactors/debug experience. It was just a subjective concensus.
I haven't timed the IDEs nor do I intend to in near future.
I think overall the helpfulness was better, and support for bleeding edge features like CodeGen, but I haven't used VS in like year or two.
I know Rider/ReSharper can fix variable names that are mentioned in comments, which VS can't do (and it gets on my nerves when I don't have ReSharper).
https://i.imgur.com/mD6Z4zO.png
Idk if it comes with VS out of the box or comes from
free extension called 'Roslynator', but eitherway it is there.
Also, it's been a long time now since ReSharper was "needed" to work in VS. ReSharper also bogged down VS a lot.
>> To get a decent IDE support, you either used a language supported by JetBrains (IntelliJ or ReSharper) or.
>VS, Eclipse, Netbeans, Delphi, C++ Builder, KDevelop, QtCreator,...
Of course it depends on the size of the project, the plugin used for VSCode (I'm using Microsoft Intellisense).
Once LSP gained popularity, the question shifted to “why doesn’t $language have a language server yet?” which set an easy goal post for languages and compilers to go from 0 to 1 in terms of IDE support.
The first chart shows that before lsp you needed special language support for each language for each editor, which is unfeasable. After lsp you just need lsp support for each language. The author then goes on to say “this is wrong”
It seems like he's more saying "this is an oversimplification, and the reality is a more-nuanced version of that statement" -- specifically, that rather than "now languages just build a language server, and editors just accept LSP", it's that "now languages just build a language server, and editors just accept LSP, plus a bit of LSP-specific configuration to point the editor at the particular LSP for a context."
Breaking things down a bit further, there are three scenarios discussed in the article:
1. M × N -- every language needs a from-scratch, bespoke plugin for every editor
2. M + N -- the "standard explanation" for LSP, where you build one LSP client implementation per editor, one LSP server implementation per language, and you're done
3. The reality of what exists today: one LSP server implementation per language, one LSP client implementation per editor, and a tiny bit of (usually-end-user-supplied) configuration in your editor to glue those two sides together.
The key difference between scenario 1 and scenario 3 is that scenario 1 requires someone with _very deep_ knowledge of a language's structure and semantics to implement a fully-fledged plugin for _every_ editor, usually requiring deep knowledge of that editor (or vice-versa), where scenario 3 allows both ends to wrap that deep knowledge up behind a standardized interface so that any shmuck can write like <100 lines of lua to glue the two ends together (speaking from my own experience as an "any shmuck" using neovim)
> I believe that this standard explanation of LSP popularity is wrong. In this post, I suggest an alternative picture.
If the intent was not to say "this is wrong" that's a very strange way to start your article.
The point of TFA (which is wrong, IMO) is that the M × N explanation was wrong, and the evidence for this is:
1. The LSP implementation itself is trivial compared to the work to get all the information the LSP needs.
2. Outside of dedicated IDEs, nobody implemented the "get all the information LSP needs" before LSP existed
3. GP editors didn't implement the high-level protocols necessary for being a good IDE; a big advantage of LSP for the editor side is that the LSP client can include its own implementation of these high-level protocols. One example of such high-level protocols is code completion.
4. If the standard (quadratic complexity) argument were true, we would have had a world where some GP editors were very good for developing some languages
My rebuttal:
1. Quadratic growth trumps any small constant-factor
2. To the extent that this is true, it's driven by the quadratic growth of M × N. Efforts to implement this get divided between many different groups. Even something as simple as ctags got both a VIM and Emacs implementation
3. As others in HN comments have pointed out, this isn't universally true, and where it is true, the editor communities tended to settle on one plugin that implements these protocols well before LSP existed.
4. I can think of at least two places where this was true: Emacs for Lisp; Vim for C (particularly with cscope, which gives you completion, cross-references, &c.). Nothing was good for C++, but as TFA notes, C++ essentially requires using the full compiler, and prior to libclang supporting C++ there was no Free tool for doing this (Many people tried with GCC, but got burned by the internal frontend API changing so damn often). That there weren't good Free tools for working with C# is kind of ... expected?
Now there are special extensions like rust-tools.nvim popping up that provide additional support on top of the built-in LSP client or enhance the features of the language server.
Somehow, the author misunderstood the original argument, dismissed it, independently discovered the actual argument, and now claims they’re the one who found the true reason for LSP, when in reality, it’s just the standard argument.
Here’s the history: Every editor has a language abstraction already. And some language analyzers had an “editor abstraction”, perhaps notably Roslyn for C# with its programmable refactoring rules that worked in multiple editors.
None of that was new. But that’s still N*M if you do the math, so that graph was never completely filled — for the obvious reason that this would have been practically impossible. No mystery about it.
I still can't get over the awesomeness of being able to just throw together a fully supported custom analyser from a template—unique to Roslyn to this day, AFAIK.
The original NxM problem is that each language needed support per editor and each editor required support per langauge. While "each language writes one custom server" and "each editor has to support each language's custom protocol" would still be an improvement, it wouldn't be enough of one.
Now, the idea that an editor can just implement this protocol and magically all the unicorns start singing in unison is a pipe dream as well. But what it does is make something that is completely infeasible for even a well-funded commercial team into something that some new little open source editor can afford to start doing. Support for Haskell may be a bit rough until someone wants to use Haskell in that editor and can fix the editor support for Haskell specifically, because of this quirk and that quirk and the other quirk (the quirks will always be with us), but at least it's in the realm of possibility now instead of a ludicrous pie-in-the-sky idea.
> Rather, a language should implement a server which speaks some protocol, an editor needs to implement language agnostic APIs for providing completions and such, and, if both the language and the editor are not esoteric, someone who is interested in both would just write a bit of glue code to bind the two together
I mean, yes, ideally that is what should have happened, but the first editor to actually do that was VSCode, and the protocol it chose is called LSP, so that's where we are.
The benefit of the LSP is that it decoupled the plugin development environment from the editor development environment.
This is a BIG deal.
Remember building plugins for Eclipse? Exactly. You don't because building them was massive, massive pain. You had to install a universe of build tools, understand how they went together, build your plugin, fit into the UI correctly, pull it into the system and configure it, and finally you could do some development.
The existence of the LSP means that the plugin development and the editor development are decoupled. I don't have to put together the enormous build system of the editor in order to create the LSP plugin. I'm not stuck in the language of the editor implementation when creating an LSP plugin.
This dropped the cognitive load for creating a plugin by order and orders of magnitude.
Some of these IDE's supported more than one language. For example, VisualAge also supported C++ and SmallTalk. But each IDE supported a different set of languages with implementations of varying quality, they each had their own complicated plugin framework, and that's the N:M problem.
Even if it were just IntelliJ and Eclipse, that's still implementing support for a new language twice from the ground up, and you'll be doing it in Java both times, which is a lot of work for a team working on a new programming language.
You can look at the Wikipedia page to get a sense of how many different IDE's and languages there are out there: https://en.wikipedia.org/wiki/Comparison_of_integrated_devel...
I honestly think this is highly underrated as a reason. Teams working on a language want to program in that language. It doesn't really matter if it's complex, or they have to repeat the work for multiple IDEs. They love doing that. They will actually compete to do that (look how many posts on HN these days are just "$MUNDANE_TOOL written in Rust"). The main thing LSP did is it moved the boundary of the implementation to the other side of the language barrier.
We also had an earlier analyzer written in Java that was mostly discarded and rewritten as well as two compilers to JavaScript that share less code than you would expect.
Some of the redundancy is because, as the author correctly states, the needs of an IDE are quite different from the needs of a batch compiler. Likewise, an ahead-of-time whole program compiler has different constraints from a JIT compiler running a program from source.
But a lot of the redundancy in Dart's case is incidental. We have a fairly large, distributed team with a lot of autonomy and sometimes that led to people doing their own thing instead of putting in the effort into coordinating and sharing more code.
Also, the language changed radically from Dart 1.0 to 2.0. 1.0 was a dynamically typed scripting language designed to be run from source in a native VM directly embedded in a browser with a separate optional type system mostly used at dev time. Dart 2.0 is a fully statically-typed language with a more typical compilation process.
That monumental change led to some duplication and technical debt that we are slowly paying down by sharing more and more of the front end over time.
The path I see most new languages take is:
1. Start with a command-line batch mode compiler.
2. Eventually get popular enough that users clamor for real IDE support.
3. Cobble together an IDE plug-in based on the batch-mode compiler's front end.
4. Discover that the latency is horrific and slowly and painfully realize you need to write a new front end architected for IDE use.
5. Now you have two front ends.
I believe the throughput loss of a front-end designed for interactive IDE use is less than people realize. So I suspect that a more efficient path for any new language is to design your front end for interactive IDE use from day one.
Maybe! One problem is that this is going to be harder than starting with a batch compiler: you might not get to 2. due to the lack of resources.
Another plausible trajectory is the following:
1. you start with a non-self hosting batch compiler, whose explicit goals are simplicity, language-designer iteration speed, and short time horizon, and which has deliberately minimal capabilities when it comes to error messages and other user-facing niceties.
2. using this bootstrap compiler, get to the 1.0 of the language.
3. implement a second, self hosting compiler with a long-term focus, interactive capabilities and all that stuff.
4. either discontinue bootstrap compiler, or explicitly support it as a minimal implementation for the purposes of differential fuzzing and specification.
This is not always the case for existing servers. Semantic highlighting wasn't in the protocol until 3.0 (iirc), and many servers have extra non-standard endpoints. So the real world situation is that there's a core feature set allowing M+N, and additionally, custom endpoints and features requiring MN.
Nevertheless the non-standard MN endpoints at least follow the "shape" of LSP -- same communication channel and message format, and that makes MN much easier than before already! As the core protocol evolves, more MN features will be decoupled to M+N.
There are already a more than a couple LSP features I wish existed, but in the mean time it’s good enough to have the (typed! and using rich data structures!) RPC endpoints exist for enterprising users to wire up to their IDE’s presentation layer.
Innovation could just happen at a higher level.
That, or retro-backing into the protocol novel features required by those experimental languages.
In my experience, industry-wide ossification and chilling effects appear not because the environment makes it difficult to build new designs, but because it makes it difficult to think outside the current paradigm and imagine novel features.
Once those innovative ideas are out of the box and many people understand their need, the frameworks needed to support them are created. I know because right now we're experiencing such a paradigm shift in terms of note-taking and knowledge building (abandoning WYSIWYG word processors in favor of networked-thinking bidirectional-linked graphs of notes), which IMHO sooner or later will extend to programming tools as well.
What paradigm shift? Can't say I've experienced it.
Sure, people use OneNote and such as a secondary thing, but outside of some startups, they're not the central thing. And startups are early adopters, very fickle.
But that's not their purpose; their primary role is as personal databases, where you can dump any factoid, TODO or interesting article that you know you'll want to process later, freeing your short-term memory and your mental burden. Having all your notes in a single searchable knowledge base allows it to grow organically and find patterns, so that you can do incremental iterative refinement of your intellectual activities.
Creatives using them are saying that it's way easier to compile ideas for writing and publishing articles or blogs entries when they are compiled and processed with these tools.
- Programming based on fragments, not documents (e.g. LEO https://leoeditor.com/)
- Live programming (e.g. smalltalk environments)
- ... where certain actions are not available, e.g. a PL geared towards speech recognition may not support "hover"
But on the other hand, these are not well-aligned with current text editors (text based, has a cursor, organize info as documents etc.)
So languages are one side, editors are the other.
It’s a bit incoherent anyway. The author’s argument seems to be that if you have language-provided pluggable language servers and editors that can host these language server plugins appropriately, then the M * N shrinks down to a small problem, without the help of LSP. Well, OK, but that’s actually the original LSP M * N argument, except with LSP replaced with something just like LSP.
From memory, notepad, notepad++, scite, vim, emacs, netbeans, eclipse, VS studio, IDEA, sublime text, bbedit, plus a number of linux only ones. Languages, VB, C++, Pascal/Delphi, Fortran, Java, C# (from 1998/9?).
The problem was tight coupling of languages to IDEs, in particular VB, and C++ to VS, and Java to Eclipse.
I guess I do use it in Python REPL quite often though. But there at least you have to prompt it by pressing tab.
If I could get the navigation and analysis (go to def/decl/parent/etc., show/jump to uses/children/impls/etc.) all on its own, without auto-complete, type hints, or syntax highlighting, I'd be a pretty happy camper.
I'm fine with features that are on-demand (on-demand completion, type info, actions, etc.). They add occasional value without distraction.
About the only other things I care about in a development environment are compile output navigation (optionally with isolated warnings & errors, but full output is mandatory), configurable run and tooling integration (doesn't need to be close integration, either, just flexible and configurable).
Gravy/Frosting (depending upon your preferred metaphor) would be debugger and documentation integration. Both are hard to do well, and can usually be accomplished using a decent run/tooling interface.
Me: I want to type "Hi Andrew,"
Outlook's autocomplete: I see an <H>, I see an <i>...
Oh, oh, I know this one! Do you want me to autocomplete "Hi" for you?
<space>? You do! I'm helping!
and I'm left getting two characters out of my three key presses in a frustratingly unexpected way.In user studies it was found that beginner/novice coders (or really, users that aren't SWEs) autocompletion was the most requested feature for improvement in IDE support. It's foundational for understanding what they can write and making sure it's valid.
And that makes sense to me, if you have a lot of experience in a codebase and ecosystem it's not as important. If you don't then typing `.` and seeing a bunch of aptly named methods show up, then snippet completion for their arguments to tab through them, you are immediately productive. Autocomplete turns known unknowns into known knowns.
I'm glad that LSP exists, and I've got it hooked into vim... but autocomplete is seldom very useful to me. It's usually faster to just type the thing out.
I see where this is coming from. That's why I do not let neovim hit me with completions all the time, but only when I request them. Most of the time, I can work with the (neo)vim builtins, like "complete word" or "complete line" and do not even use the language-server provided semantic autocompletion. But when I need to, it is only two keystrokes away.
It's a good middleground.
Do you remember all those properties, method names, like wtf? how?
Microsoft really nailed it with LSP (albeit, I agree with the caveats the implementation has some warts). Jetbrains must be sweating - more and more of my colleagues and coworkers are using VSCode these days.
I think Jetbrains should seriously consider LSPifying their backends. If they don't, they risk someone else building a better JVM LSP and then they are going to lose a lot of market share. Plus it gives them the opportunity to shape the LSP spec. I'd happily pay Jetbrains right now a sub just for the backend if I can use it with my editor of choice.
people use intellij because of the various plugin/features/debugging for all the jvm ecosystem/frameworks https://www.jetbrains.com/idea/features/#jvm-frameworks
similar to how Rider became immensely popular (1st class Unity Engine support)
and now Rider C++ support for .sln solution and 1st class Unreal Engine support
intellij's problem is their plugin API and development cycle, for a while you needed to restart the whole IDE whenever you wanted to recompile your plugin, as a result, the 3rd-party plugin ecosystem is very poor
hopefully they fix all the annoying things with Fleet https://www.jetbrains.com/fleet/
they went with JVM so it gives them a poor start already (no comparatif benefit over VSCode and electron, same bloatshit, but they can eat some market share by providing a better out of the box experience)
Like I said, in my ideal world, Jetbrains would simply provide commercial LSP servers for all of the things they support. Like you said, they have some of the best in class IDE support for various languages, especially JVM.
I’d love an excuse to stop using VS Code, and Fleet is shaping up to be that, without losing the actual plugins I care about (which are largely LSP features anyways).
Often, it's because LSP clients have differences not in interacting with the LSP Server, but in how that is surfaced to the user. Some LSP clients are written in different languages, and that can make some implementations faster than others. This is why LSP is a success. It allows for clients to be written in many ways but for all of them to do the most basic thing they need to (go to def, rename, refactor, search symbols etc).
Multiple LSP clients is a success and offers users more choice about how they want to interact with their code. Do I want a search for symbols to open in a new window, to replace the current buffer, in a searchable list etc.
Talk about commoditising your complement!
----
Unrelated: how are LSP implementations and Emacs support generally these days? When I last tried 2–3 years ago the Emacs-specific plugins for various languages were still more reliable and predictable than their LSP counterparts, but has this changed a lot? If so, I might be inclined to try again.
Like I said, editing Rust is awesome in Emacs; saw someone working on Rust in VS Code and didn't notice anything that Emacs couldn't match.
See also lsp-ui; I don't turn this on personally, but it does give you some significant bling.
I've used it with Python, C/C++, SQL, HTML/CSS/JS, without issue and of course it has stellar support for Clojure.
I reported this to lsp-mode, but they kicked the can over to Emacs[1], which I never bothered reporting. The fact this is now a combination of tools with no clear reporting path when something goes wrong is awful UX.
Every few months I update the entire setup with hopes things improve, but eventually I always get the crashes. I would really like for this to work, as the DX when it does is great, but for me it's just not there yet.
It's not without problems, occasionally taking quite a bit of processor power or needing the odd restart when it falls out of sync with a multi-module project, but it has never once crashed Emacs for me (using it on Ubuntu on WSL2, for what it's worth).
I am not writing this to invalidate your experience. It's clear that something is rotten with the way the plugin uses emacs on your OS, and it's frustrating to not get help with that. I will note that their observation - that an Emacs crash is first and foremost is an Emacs problem, not a plugin problem - is fair though. But, I also would not want to go through a long series of communications between different projects, so I get your pain entirely.
It's best to have a recent Emacs though. At least Emacs 27, which introduced support for a C based JSON library (in Emacs 26 all the LSP parsing is done in elisp). This is the biggest change. Emacs 28 introduced an elisp JIT. I haven't any hard data, only a subjective experience but in my daily use with Emacs 28 it's fine, whereas it could be a bit sluggish at times with Emacs 26.
Interesting theory but my recollection of that time is pretty much exactly that. Lots of IDEs with great Java support (IntelliJ, Netbeans, Eclipse), a very small number with good CJJ support (Visual Studio, Qt Creator, maybe KDevelop or Code::Blocks if you're generous with "good"), and not much else.
How many IDEs had great Delphi support? As far as I know exactly one - the Delphi IDE.
Ok there were a couple of exceptions - Eclipse had decent C++ support IIRC and IntelliJ sort of had support for loads of languages, but that was a business whose main product is IDEs.
I think the alternative suggestion is also true. They're both good reasons for the success of LSP.
Ultimately, complexity itself is the enemy.
I'm really attracted to Kotlin as a language[1], but, last I checked, IntelliJ is the only way to get great tooling for Kotlin, which is a show stopper for me since I've invested a lot into my neovim config.
[0] https://github.com/fwcd/kotlin-language-server/projects/1
[1] What attracts me to Kotlin is that it is actually statically typed (ruling out Python/JS/TS), with a relatively expressive type system (ruling out Golang), great type inference, not verbose (ruling out Java), not too involved with low level details (ruling out Rust), not too steep of a learning curve (ruling out Rust again), and a great cross-platform community (ruling out Swift).
[1] https://confluence.jetbrains.com/display/JBR/JetBrains+Runti...
Why is Android Studio so slow, then?
NB: Using the compiler that way probably isn't the right way to go. IntelliJ is somewhat modular. You could parse Kotlin into PSI and then re-use parts of the Kotlin IDE plugin in headless mode. Other JB products do this e.g. Qodana so you don't really need the GUI to be running to do IDE type stuff with it.
I really should try that out more. But from my limited foray into using vim emulation: it's not perfect + I really don't like how resource intensive and slow IDEs are + it's not just using vim text navigation, but my neovim plugins, tmux, ripgrep, fdfind, etc.
> You could parse Kotlin into PSI and then re-use parts of the Kotlin IDE plugin in headless mode
I currently don't have the bandwidth to look into this kinda stuff, hence my call-to-action for "talented folks" :)
It kind of worked, but once I stopped needing to use Java for my job it became too much of a hassle to flesh out.
Level of confidence just 0.4, but, if you invested the same amount of time into IntelliJ platform, you might have got more out of it. The “advanced semantic features” rabbit whole is as deep as “advanced vim”, it’s just less popular :-)
I've been looking everywhere for evidence of the value-add of IDEs as compared to my neovim_plugins+LSP setup, but haven't found anything that convinced me to do the investment.
Some specific things which IntelliJ brings to me:
1. Rich refactors -- things like "change signature" are a huge time saver in big codebases. LSP still can't do interactive refactors which require user input.
2. Structural Search Replace -- you can grep and sed sourcecode by matching on AST and semantic information.
3. Significantly more polished basic features. When I search for a thing in VS Code, I get a flat list of 20 occurrences. When I search for a thing in IntelliJ, I have 20 occurrences, but I immediately see that 12 come from tests, and, among the remaining 8, I can clearly identify 2 write and 6 reads, and it's writes I care about.
4. Significantly better integration with language specific tooling. When I want to run a custom command in VS Code, I open terminal and type `cargo run --package foo --bin bar`. In IntelliJ, I press a shortcut and get auto-completion not only for general cargo command, but for project specific things as well (eg, IntelliJ knows that `foo` package exists and completes that).
5. Local history -- rather than maintaining a hard-to-visualize and unintuitive undo-tree, IntelliJ transparently remembers all transient version of a file and shows you a fine-grained "git log" with diffs and such.
6. Merge tool that understands semantics of the language and can resolve a lot more conflicts automatically (though, to be fair, the actual Git interface still is not as good as magit)
7. A lot of polished "small things". IntelliJ helps a lot with adding punctuation, placing the cursor in the right position and doing other small editing tasks. Subjectively, it significantly reduces the cognitive load for just typing the code in.
I guess, the overall thing here is not so much as some big, flashy things, but rather than a myriad of small, polished details. Like vim has a dedicated command/keysequence for anything, IntelliJ exploits any semantic information it can get from the sourcecode to be helpful.
This is the best case I've ever heard for IDEs. Thank you!!
1 and 3 seem to me to require extensions/improvements to the LSP protocol.
2, and 6 seem like one could build them off of treesitter (but I don't think anyone has as of yet).
5 seems already implemented in a vim plugin[0].
Thanks for 4 and 7 (the "myriad of small, polished details") also, I feel like I have to spend a week using an IDE to get a feel for them.
Will it take time and energy? Sure! Such is life.
At least it's not as bad as e.g. JavaScript.
It's good that tooling has improved across the board for many languages with LSP, but there's so much more still.
which language got stifled as a result of the existence of LSP? Would that language still have stifled anyway without LSP?
Obviously you have to add custom implementation on the client for each ide, but that's the case without LSP.
But sharing as much as possible and harmonizing as much as possible is a huge step forward, even if each language still has a bit around the edges to implement. At least they agree on language, fundamental communication model, common functionality, etc.
That seems to be generic, e.g., rust-analyzer provides the suggestions, and lsp-mode is just listing them. Though I don't know that for sure.
So for me, the question is wrong. It's not "Why is LSP so great?".
The question should be "Why are people so hyped about tech that's based on questionable assumptions and that hasn't proved itself?"
The reason VSCode invented LSP is that different programming languages don't have a reliable way to intercommunicate (other than as separate processes communicating over a socket).
The processes-communicating-via-IPC architecture is way underrated for plugins. It's much easier to separate the plugin from the host, and to cleanly stop or restart the plugin. For example, sometimes (rarely) rust-analyzer hits a bug and starts consuming 100% CPU. When that happens, I just kill that process and VS Code transparently restarts rust-analyzer; I don't have to restart the IDE, and all other plugins are unaffected as well. That would be practically impossible if rust-analyzer were a library instead of an independent process.
Why is that?
1. An in-process type safe API can be evolved and iterated rapidly. There's no need to write informal English specs for everything because the API itself provides so much guidance. Actually, IntelliJ is rather notorious for its absence of JavaDocs though this reflects cultural decisions inside JetBrains itself more than anything intrinsic (they take "code should be self documenting" perhaps a bit too seriously). In contrast, the LSP spec is enormous and the document itself doesn't provide much assistance implementing it (the article discusses this somewhat).
2. A protocol spec doesn't give you any re-usable code. If you write an IntelliJ plugin there's tons of re-usable helper logic and you can easily customize other plugins. The whole thing is designed for on-the-fly presentation compilers. With LSP you may or may not have anything to base your work on.
3. An IDE is fundamentally a highly parallel mutable database, in which the data can be in arbitrarily invalid forms at any point and the user is allowed to change anything whilst many different analyses are running in parallel. Shared data structures are everything in this problem, yet the LSP model effectively forbids all shared state between backend and frontend. This feels like a constraint inherited from browsers - it arguable doesn't make things easier, it just replaces relatively simple and statically/dynamically analyzable locking protocols with complicated sync and rec protocols. Both sides have to maintain their own copies of each other's data structures instead of re-using a single source of truth. This can get really messy, really fast. You're also constantly paying the costs and overheads of multi-process like context switching (especially expensive on Windows), IPC copies, process overhead, serialization etc.
4. A presentation compiler doesn't seem to benefit much from being written in Rust or C++. Developer workstations are fast and have plenty of RAM, so GCd/JITd languages don't seem like a particular problem here. Developer productivity on the other hand is at a premium. People want features. One reason JetBrains can add new languages and features so fast is that they're writing in relatively forgiving languages like Java and Kotlin, where you don't have to think too hard about ownership or memory management. Some thought is still needed - see the disposable model inside their IDEs - but you can more or less just go for it with a high rate of feature throughput.
You raise the question of how to kill hung operations. In practice that doesn't seem to be a common problem. I've been using IntelliJ with various languages for years and there have been many bugs, but I can't remember any time that a plugin hard-hung whilst analyzing. There are cases where plugin bugs happen but exceptions and GC mean the IDE can simply catch the errors and disable it. These days it can do that temporarily and simply reload the plugin on the fly. Other times e.g. if a pure static analysis crashes it just logs the error and uploads it for analysis. That particular analysis might not appear as a consequence but there are so many different optional quality-of-life analyses being done you often hardly notice.
Huh? The first part of the sentence makes me think of Rust. It's fast, memory safe, type safe, and thread safe.
Is GC a problem in language analysis systems? Doesn't feel that way these days, and anyway JVMs have pauseless GCs anyway now.
In terms of speed, as long as you don't choose Python I think you'll be fine.
I do think in terms of productivity, something like F#, that has GC, ML style syntax with piping and partial application, and a strict enough type system with Hindley-Milner type inference, would be the most productive.
My hold up was mostly with the sentence I quoted which seems to contradict itself.
The "shared state" in this context is IDE program text, and analyzer diagnostics. Copying those across address spaces and keeping them in sync is super fast, the overhead is too low to matter.
Recall that most analysis is done async, so results arrive at different times. Even if you're not doing anything then, your IDE/backend will be context switching back and forth as stuff arrives to be rendered.
In the limit this degrades to the backend being the entire IDE and the frontend being just an translator between the OS IO system a stream of JSON rendering commands.
This would mean that you'd have to write a compiler not just for each host language/source language combination, but for every IDE/source language combination, because Atom would have different internal data structures than VS Code.
Historically for IntelliJ that meant writing everything in Java. Nowadays plugins are written in many different languages. You could write plugins in Ruby or Python if you wanted to. They run on the JVM. You could even use C++ and get the same benefits because GraalVM can run C++ on the JVM itself, i.e. it will apply GC to the C++ parts so you don't have to worry about ownership across the interface. But that'd be an advanced move and I don't think anyone has tried that; for such big gaps in language they tend to fall back on the more conservative multi-process model again. Stuff like Sulong is too new to have made such an impact.
Atom would have different internal data structures than VS Code.
LSP doesn't solve that. It either forces everyone to implement the LSP model and data structures, or you have a mismatch and translation anyway.
Microsoft didn't go that way and again it feels like maybe JS limitations are the cause. Calling into a native library is tough in JS because there's no standardized FFI (browsers wouldn't allow it) and you're going to end up blocking the one JS thread you've got. Native code is going to expect the host to be able to spin up threads and use them because that's a super reasonable assumption, but one V8 can't meet. So they want everything to look like a web server because that's what JavaScript is intended for. That pushes them down a particular path, but it's definitely worth stepping back and saying ... does this really make the most sense, overall?
That's basically what separate processes are, so what's your point?
> Calling into a native library is tough in JS because there's no standardized FFI
No need for using anything standardized: VS Code brings its own custom browser engine – for better or for worse – so it's not limited to what any Web standards allow or forbid.
> you're going to end up blocking the one JS thread you've got
There are worker threads in JS.
JS has workers but they aren't sharing memory, so they aren't really threads.
The way I see it, there are possible two grand architectures:
* you either have a single, multi-language combine supporting any language. In a sense, LLVM/GCC but for front-ends
* or you have a bunch of independent servers
The first is clearly less code — there’s a lot to share. The second is embarrassingly parallel though. So, if you are a (single-threaded company), you should go for the first approach. If you are a (multi-threaded) OSS community, the second approach has shorter critical path.
Some second order effects:
1. While backands are more or less the same between languages and LLVM is a clear win, frontends tend to differ a lot. That’s the point of having different programming languages. So in practice sharing the code in IDE is harder. 2. An interesting benefit of separate process architecture is that it forces you to have async interface, which is important for responsive IDEs. But that’s an argument for separating back and front, not necessary for sharding back.
It means that as a user of the system you must understand the inner workings of the system.
Imagine someone says this about a car.
"If you are driving on the highway and some component dies midway, you just open the cover and press a button on the broken component and it restarts itself! Isn't that much better than waiting two weeks for some repairman to repair it?"
I don't want a car that has components that just randomly die mid flight. That's not a feature. It's a deal breaker.
In more general terms, a system where failures are hard is easier to make robust because the errors are visible to developers.
In a dynamic system where failures are "not my problem", it's very easy for the system to develop into a wobbly unstable mess, because no one owns the system. It's just a bunch of plugins that may or may not behave erratically.
That's not a good way to build a stable relaible IDE.
Completely bug-free software is a desirable, but utopian goal. What do you think why processes with separate address spaces were invented? Would you rather go back to the Windows 3.1x days where a bug in a single program could bring down your entire system? Do you believe those programs were "easier to make robust because the errors [were] visible to developers"?
> "If you are driving on the highway and some component dies midway, you just open the cover and press a button on the broken component and it restarts itself! Isn't that much better than waiting two weeks for some repairman to repair it?"
Yes, that would be much, much better than waiting for two weeks while being stranded in the middle of nowhere.
How far would you extrapolate this? Where would you draw the line?
Would you say VS Code would be more resiliant and reliable if it had more isoldated processes for different parts of the editor?
- Process to blink the cursor
- Process to render the text
- Process to run syntax highlighting on the text
- Process to show the buttons on the left most side bar
- Process to draw the file/directory tree
I think it would be obvious that this would be insane.
Yet, why should it be? Wouldn't it be better - according to this way of thinking - because it means the editor will not crash if the cursor blinking code crashed! or if the file tree viewer crashed!
To where it makes sense from an engineering perspective. Yes, that's what makes good engineering: selecting a pragmatic point between two extremes.
> Yet, why should it be? Wouldn't it be better - according to this way of thinking - because it means the editor will not crash if the cursor blinking code crashed! or if the file tree viewer crashed!
Your argument is absurd. You're trying to counter my point by making up an extreme version of what I said and then refuting this imaginary point. This kind of logical fallacy is called "straw manning" [1]. This is how it works:
"According to your line of thinking, wouldn't it be better if every program shared the same address space, even in general purpose computing? Maybe even with the kernel? Then every programmer would be really* invested in avoiding bugs. I think it would be obvious that this would be insane. Therefore, you're wrong and I'm right."*
Can you see now why that kind of argument is a fallacy?
You didn't answer the question though.
That is just assumed within my question.
The question is where do you draw the line.
Why is it ok for the autocomplete to be a separate program (and somehow that's good because the autocomplete can crash without crashing the editor)? Why is it not ok for the syntax highlighter to be a separate process? or the file viewer?
> You're trying to counter my point by making up an extreme version of what I said and then refuting this imaginary point. This kind of logical fallacy is called "straw manning"
I'm taking your basic premise and showing you that if you extrapolate it to its natural conclusion you will end up with an absurd situation.
This is not a fallacy.
Although my general feeling is, when you start accusing people of being fallacious, it's difficult to continue the discussion in good faith.
Most issues with the VSCode plugins I have is that they don't report errors to the user properly. It's really hard to find out _why_ something is failing. So when everything is configured correctly, the LSP works great. When you have a misconfiguration you need to play detective.
Plenty of plugins hang forever, fail silently, or they give you very generic error messages. But this seems to be a VSCode issue.
But even then, not all of them are great. For example, the Python plugin is of questionable quality, but that is probably because Python does not amend itself well to intellisense, even when you add type hints to the picture.
> Most issues with the VSCode plugins I have is that they don't report errors to the user properly. It's really hard to find out _why_ something is failing. So when everything is configured correctly, the LSP works great. When you have a misconfiguration you need to play detective.
Good observation. This is not just a "feature" of LSPs. It's a feature of all distributed systems developed with the unix mindset.
For example, Docker suffers the same problem. Someone gives you a docker image, it works great! For a while. But when something breaks, it really breaks, and it doesn't tell you why. It prints some superfluous error message; one that does not help you understand what's going on.
That is also a good observation. It's hard to create a good UX with a system where you don't somehow handle all of the failures of the subsystem in a central manner.
My problem here with VSCode is that it often doesn't even expose the failure of the subsystem, essentially not even giving you the information you need to find out the issue.
If my corporate proxy fails, the extension store will say "XHR failed", and before it used to just hang forever.
But as a user, what is XHR? Why does this hang forever now? There could be many reasons.
At least tell me that you had a failure while downloading something.
It's one of the reasons why the Linux UX will always be subpar.
Apple's macOS is based on unix underpinnings, but they take ownership of the whole thing and this is why they can beat it into shape.
That’s a protocol issue! While LSP has a method to report a transient (edge triggered) error, it doesn’t have a way to report a persistent (level triggered) status. And to solve configuration problem, you really want a “status” concept - you need an LSP health indicator which is either red or green, and which you can click on to get info about what the server thinks the project is. There’s no such feature in LSP at the moment.
https://github.com/microsoft/language-server-protocol/issues...
It can now actually act like real IDE as the editor knows about the code pretty well.
https://github.com/folke/trouble.nvim
https://github.com/tanvirtin/vgit.nvim
https://github.com/kosayoda/nvim-lightbulb
Some features look pretty close to what you get in JetBrains.
I can see some parts are kind of rough until you Google enough to fix/customize to your needs but if I take enough time, I might as well feel like its a decent replacement for a real IDE.
For a starter, AstroNvim helped me figure out what the juicy plugins are these days.
It seems NvChad and LunarVim are preconfigured competitors to it.
I wonder if JetBrains one day gets left behind for not using LSP ecosystem but perhaps Fleet might implement it.
Yes, please! There is next to nothing about "How to write a language server using LSP". All I can find is "how to write a language server for VSCode".
- Written by a neovim userhttps://m.youtube.com/playlist?list=PLhb66M_x9UmrqXhQuIpWC5V...
https://rust-analyzer.github.io/blog/2020/07/20/three-archit...
Maybe building another programming language can be accelerated by deriving its M libraries from another, using some kind of abstract libraries or translation methods, through a service similar to LSP.
He's saying about actual working code, something akin to universal libraries you could use from any language. Or maybe some auto-translation/hooking up of libraries from another language, through some sort of "library protocol".
On another note: huge thanks for rust-analyzer, not only is it my main daily driver, but we also used it as a reference for implementation of "deno lsp" - the language server that ships with Deno.
I can't say I am a user of deno today, but my feelings about deno remind me my feelings about Rust circa 2015: it's not clear if the thing succeeds, but, if it does, that would be a huge boon for the whole industry, as finally "better is better" would take over "worse is better". Deno has all the potential to become the first really dependable scripting environment!
So, I wish you luck and hope one day I'll migrate my jekyll+asciidoctor blog to deno :-)
It's when you have a tool that has ongoing async communication which enables the editing the author mentions that LSP is really useful. Implementing a goofy protocol for each tool is a pain.
Why not? I’m interested in any concrete reasons why doing so would be a bad idea, why you should maintain independent extension points and bind LSP to them, rather than providing LSP-shaped extension points, as it were.
_First_, a general clean architecture considerations -- protocol is "view", it shouldn't infect the model.
_Second_, LSP is a way to consume semantic info, but there might be others. A different protocol might come along, or you might want to embed the server as a library somewhere.
_Third_, LSP is language agnostic, so, to implement LSP, you'd have to dumb-down internal rich language specific representation to a language agnostic one. The system will be more evolvable if such dumbing down happens near the edge of the system.
_Fourth_, LSP really just stretches the surface of whats possible. Language servers should push the boundaries of whats possible to both deliver a better UX for a specific language as well as to pressure the protocol itself to implement more advanced features.
The design guideline we use in rust-analyzer is that we are building not for LSP/VS Code, but for a hypothetical, rust-specific perfect IDE whose frontend is capable of doing anything we want.
Why can't arbitrary LSP clients connect directly to tsserver (maintained by MS) ?
[1] https://github.com/typescript-language-server/typescript-lan...
Can you explain a bit more about why they can't connect?
- It's a big selling point for vscode. - It might hard to migrate what they have to LSP, they might implement a lot of non LSP standards. - Migrate to LSP could possibly delay new features because of the rewrite in tsserver.
There is an open issue [1] that has been open since 2020.
As far as I'm informed, they can.
For example, NeoVim language client has a pretty wide range of officially supported servers [0], including tsserver.
[0] https://github.com/neovim/nvim-lspconfig/blob/master/doc/ser...
That's why an arbitrary LSP client can't connect to it.
> Rather, a language should implement a server which speaks some protocol, an editor needs to implement language agnostic APIs for providing completions and such, and, if both the language and the editor are not esoteric, someone who is interested in both would just write a bit of glue code to bind the two together
Yes, this is the ideal world, but the first editor to actually go ahead an do that was VSCode, and the protocol they chose was LSP, so everyone else fell in line, because having a protocol that worked with one editor was at least a workable start.
Another example of this is syntax highlighting, which is definitely N*M -- people have written syntax highlighting plugins for every conceivable language for almost every editor, which always requires some manual patchwork. Editors are increasingly migrating over to tree-sitter for this support, which seems to have become the de facto standard, and as a long-time vim user and occasional syntax highlighting maintainer, this cannot come soon enough.
LSP also solves a big pain by making it easy to build tooling when teams choose to implement an external DSL's.
Not sure what the Right Direction is when it comes to text editing but this isn't it.
It's also important to note that LSPs almost always provide you more than auto completion (for example, go to definition, go to implementation, find references).
Do let me know if you have more questions, neovim and LSPs are my "daily driver" as a dev, so to speak.
NCM ancillary plugins that interacted with e.g. libclang were more what I was referring to, but I'd hoped the average reader could deduce that.
Those features of LSP I do not use, namely because LSP is a buggy mess. Some files have wild syntax errors reported for them that don't exist when compiling, but not others. Half the time, the auto-completion simply doesn't do anything. Nothing pops up, nothing auto-completes, etc.
And now, just a few weeks after switching over, without changing a thing about my config, the arrow keys for selection have completely stopped working inexplicably.
I feel like if your comments' utility to the conversation would be greatly improved by prefacing them with something like "in my experience with clangd, treesitter and neovim".
I say this because my experience with LSPs is the polar opposite of yours[0]. While I believe there's value to sharing our personal experiences, I think we have to be careful not to present our personal experience (especially with (neo)vim setups, which tend to vary wildly from one to the next) as representative of the whole ecosystem.
[0] I also have nothing but praise for most of the LSPs I've used (clangd, typescript-language-server, rust-analyzer, clangd, pyright, css-language-server, sumneko/lua-language-server, of the top of my head).
The issue is trash files is very weird and I doubt it has to do with lsp integration.
Maybe tryout AstroNvim [1] which is a nice pre-integrated environment with a lot of sane defaults.
You'll have to file a bug report, because none of the built-in LSP stuff should cause any performance degradation.
> syntax highlighting just stops working randomly
This has nothing to do with LSP.
> files get spewn all over my repositories that I have to .git/info/exclude
Neovim does not automatically create files in your repositories.
That's a bold claim. Migrating from NCM + clangd integration is absolutely slower.
> This has nothing to do with LSP.
Sorry, you're right. Tree-sitter-based syntax highlighting is buggy and slow. My point still stands.
> Neovim does not automatically create files in your repositories.
No, you're right. Clangd does. I was commenting more on my experience, less Neovim's LSP behavior specifically.
You'll have to define slower (time to diagnostics, time to completion, are you really talking about the performance of nvim-cmp instead, etc.) preferably in a bug report with benchmarks. I've done several rounds of performance optimization since 0.5, and I haven't heard any complaints since 0.6 when I swapped out our json decoder.
(2) Maybe it is better today but historically Eclipse was a workable Java IDE but the "plugins" for other languages pretended to work but didn't really work, at least not as well as Java.
I never learned to code without a superfast feedback loop. (maybe I've never learned to code!!!?)
oh, okay, there was a C++ project (a music recognizer - shazam clone) and I've mostly hacked that together in vim until the compiler stopped complaining about move semantics and right-references.
But the heavy tail of 80% of the features which are used relatively rarely is very heavy. The biggest one there is the "change signature" refactor. LSP today can't really express that.
You can’t compare the architecture of VSCode, vim, emacs, VS, IntelliJ, etc. and come to any conclusion.
They are completely different tools, built at different times, with different goals, by different (dis)organizations.
Emacs was a bunch of primitives that were wrapped in Lisp, and you could do anything. It was a day 1 goal. Ignoring the things that evolved to become normal in the Lisp on top is weird. It was extensible by design and completely open ended, with packages evolving to being part of the expected toolchain.
Vim took vi and bolted on some scripting interface that kept being pushed, adding extensibility by demand.
Now we have neovim embedding lua which is more emacs-like, and driving vim features as well. But it got to add higher level “primitives” because it’s a new implementation.
IDEs like VS, Borland X, Sun Studio, etc. were purpose built tools for a specific toolchain package. Only after the fall of traditional IDE/RAD environments did VS start trying to be an everything IDE.
Eclipse and Netbeans started as Java IDEs in Java, were all focused on architecture, and enabled plugins. People started making plugins to support all the languages (and then totally break the IDE by installing the wrong combo). As eclipse, well eclipsed, NetBeans you started seeing Eclipse “distros” of canned plug-in combos to not implode. I know folks with an eclipse install per codebase they work on.
IntelliJ got the architecture part from Eclipse, but stayed very hand curated like the old RADs and IDEs. You can install all the things in IntelliJ Ultimate or buy the more focused language specific ones (PyCharm, CLion, etc). The plugins are less flaky because they’re predominantly 1st party. The language specific ones make each toolchain ergonomic like a traditional IDE.
VSCode got the benefit of being the newest. Strip down below an “IDE” but above a text editor exposing primitives. Use web tech so the kids can make stuff because Java isn’t the lingua franca it once was. It could look back for a better sweet spot.
So whatever. Use what you find productive and comfortable.
I wander between probably 10 languages. I tend to have an editor and terminal side by side. It’s comfortable for me. I prefer the editor+ experience more than the integrated IDE one. I also am generally mouse-adverse. But that’s me and I’m not “right.”
I like my neovim acting like VSCode more than VSCode acting like vim. But it’s because it matches what my hands do already. When I do !!fmt or whatever and it doesn’t work, it takes me out of my flow. And when editing remotely, I still get vi/vim just without bells and whistles so my hands still work. Many just never have that use case.
That comes at a cost of maintaining a crazy config for me vs clicking for plugins. It used to be 10-15 vim plugins. Now it’s more LSP + a few. But I revision control it and revisit every 6 months or so. That trade off’s worth it to me, maybe not to you.
Some folks still love their full IDEs with tighter integration with a toolchain and language-specific features ergonomically placed. They likely use Java/C#/C++ and have to dabble in html+js at times.
Use and make what you want. Make an LSP or don’t. Integrate them into something or don’t. All of the experiences described in the article still exist. No one has to use any of them. Follow your heart (or I guess your hands). Saying one is best is like saying some kind of shoes are best for everyone. They’re tools, but ones we live in. Wear what’s comfortable.
In the words of a song by Sheryl Crow that I don’t particularly like “If it makes you happy, then why the hell are you so sad?”
[0] https://www.vimfromscratch.com/articles/vim-and-language-ser...
> In particular, add assist/code action/(bulb) as a first-class UX concept already. It’s the single most important UX innovation of IDEs, which is very old at this point. Its outright ridiculous that this isn’t a standard interface across all editors.
In the grand scheme of things, this particular super-local tactical optimisation seems like entirely the wrong problem to focus on with all the inefficiencies that come with badly designed software. Whether I write
public double Hours { get { return _seconds / 3600; } }
or public double Hours => _seconds / 3600;
is really not going to make a big difference to the quality of my software. Is this where we want to focus our attention?The day I get a little pop-up that says
- "are you sure you need to invent your own time abstraction here?", or
- "this is a derived value that should only be used in presentation and not business logic or persistance", or
- "the customer has not been using the feature that this code is relevant for in six months, are you sure you want to spend time on this?"
then we can start to rave about the single most important UX innovations.