[[!meta title="lsp-bridge: a smooth-as-butter asynchronous LSP client"]]
[[!meta copyright="Copyright © 2022 Andy Stewart"]]
[[!inline pages="internal(2022/info/lspbridge-nav)" raw="yes"]]
<!-- Initially generated with emacsconf-generate-talk-page and then left alone for manual editing -->
<!-- You can manually edit this file to update the abstract, add links, etc. --->
# lsp-bridge: a smooth-as-butter asynchronous LSP client
Andy Stewart and Matthew Zeng (IRC: Andy: manateelazycat)
[[!inline pages="internal(2022/info/lspbridge-before)" raw="yes"]]
Emacs built-in single-threaded mechanism and GC design will cause Emacs to freeze when receiving oversized LSP data.
Lsp-bridge uses python's threading technology to build caches that bridge Emacs and LSP server. Lsp-bridge will provide a smooth completion experience without compromise to slow down emacs' performance.
lsp-bridge is completely asynchronous, to the point that even the completion popup is controlled by lsp-bridge. It offloads all the computation to an external python process, and hence the emacs session itself stays always responsive, as it has very few things to do.
lsp-bridge has now supported 39 LSP servers and all kinds completion backend: include LSP、 TabNine、 Citre、 Elisp、 Search Words、 Path、 Yasnippet、 Tempel、 Telegra、 English etc, it just works pretty well out of the box.
Related design, please check <https://manateelazycat.github.io/emacs/2022/05/12/lsp-bridge.html> and <https://manateelazycat.github.io/emacs/2022/06/26/why-lsp-bridge-not-use-capf.html> (sorry, I'm Chinese Emacser)
[[!sidebar content=""]]
# Discussion
## Notes
- <https://github.com/manateelazycat/lsp-bridge>
## Questions and answers
- Q: Is the fatal mistake of this approach that you can't M-x
find-function into the code?
- A: It is an unfortunate tradeoff. But what is the "fatal"
part?
- Q:Will lsp-bridge replace eglot/lsp-mode, or could it work with
them?
- A: Yes, lsp-bridge will replace lsp-mode/eglot and
company/corfu.
- Q:Is it possible to use lsp-mode and lsp-bridge together (Disabling
completions of lsp-mode)?
- A: lsp-bridge is plugin to replace lsp-mode and eglot, can't
work with lsp-mode.
- Q:Is there a demo of lsp-bridge showing its performance?
- A:Hard to do that in 20 minute presentation about the
principles. Best to try it to see.
- Q:Will this be a candidate for core Emacs?
- A:Perhaps not, it uses a lot of Python and many Emacsers may not
like that instead of pure elisp.
- (someone else on IRC): And as I said above, this breaks introspectivity, which is one of the main features of Emacs.
- Q:If performance is the main objective, why Python and not something
like, e.g. Rust?
- A:Python is easy to develop in, and LSP's performance is
IO-based. The key is multi-threading, not language performance.
- A: LSP is IO intensive not CPU intensive, Python isn't doing
too good with latter but former is pretty fine. Anyways, as
I've explained in the talk, the multithreading design
fundamentally fixed the problem, it doesn't need any faster
language. Existing python ecosystem and python's ease of
development were also part of consideration
- Q: Is there a benchmark comparison with lsp-mode and eglot?
- A: It is a nuisance to create a benchmark comparison when
lsp-bridge and lsp-mode/eglot are structured so fundamentally
different (single-thread & multi-thread). Feel free to try
lsp-bridge on a huge repository with a slow server (i.e volar,
java), you will experience the difference immediately
- Q:You tried lsp-mode , but have you tried Eglot re:performance? I
heard lsp-mode isn't that efficient.
- A:lsp-bridge is much much faster than eglot and lsp-mode
- A: lsp-mode and eglot both suffer from bottlenecks from the
single-threaded Emacs and the uncontrollability of the codebase
size & lsp-servers, I've also heard eglot is better in terms of
performance than lsp-mode, but lsp-bridge avoided this problem
fundamentally
- Q:How well does lsp-bridge coexist with clojure-lsp and cider?
- A: clojure-lsp is part of the supported language servers
already., C# also supported by OmniSharp
- Q:Can lsp-bridge work with all LSP backends or just Python at the
moment?
- A: All LSP backends.
- A:
<https://github.com/manateelazycat/lsp-bridge#supported-language-servers>
- Q: Is there any plan to support dap-mode or something alike?
- A: Yes, but this year I've already spent so much time on
develop lsp-bridge/EAF/blink-search/deno-bridge/markmacro. We
can use lsp-bridge's technology build faster dap-mode similar
project.
- Q: does lsp-bridge work over Tramp?
- A: tramp is very slow, I will planinng write new plugin to
replace otramp, then we will make lsp-bridge work on remote
machine, and something like VSCode does, idea
<https://github.com/manateelazycat/lsp-bridge/issues/357>
- Q: Does acm mode work on terminal or it only works on GUI?
- A: The main acm-mode bundled with lsp-bridge only works on GUI
at the moment. There is a community maintained repo that enables
acm-mode to work on terminal:
<https://github.com/twlz0ne/acm-terminal>
- Q: acm-mode is fast, is it possible to use it outside of lsp-bridge
as a standalone mode?
- A: No, acm-mode fast is because lsp-bridge's multi-thread and
asynchronous design, not because acm-mode itself
- Q: What lsp features will not be considered in lsp-bridge? How about
symbol highlight, breadcrumbs?
- A:lsp-bridge's highest priority is performance, symbol
highlight is not useful and it will slow down the render
performance (symbol-overlay is better choose)
- A: breadcrumbs is not LSP procotol, I just want we coding like
hacker that live in Emacs, I don't want make Emacs like a
VSCode clone.
- Q: doesn't Python have the same fundamental problem with threads? I mean GIL.
- A: NO, if you really wrote multi-thread code.
- GIL doesn't matter for handling blocking IO in multiple threads
- lounge-4227, same is true for elisp
- Most emacsers haven't experience on multi-thread, python GIL won't block this.
- But Emacs's haven't multi-thread.
- Emacs's single-thread and GC can't handle LSP in real-time.
- Q: ManateeLazyCat Do you think Emacs could be fixed in order to allow for this kind of multithreaded implementations in Elisp itself?
- A: No, there have so many elisp code running single-thread, if elisp implement multithread, Emacs will break out.
- Q: I tried lsp-bridge, and it's wonderful. What I miss most is imenu integration in lsp-mode/eglot. Is there any plan to support it ?
- A: I doesn't use imenu, I'm personal no plan to support it, but any PR are welcome.
- I don't have anything against Python, in fact I like it myself, but it seems strange that this can't be solved without requiring a second runtime
- A: It's not technology, it's about Emacs's history, if emacs include multi-thread, will break most elisp plugins.
- Q: Does the package manage the external LSP and bridge processes.
- A: Yes.
Other feedback from IRC:
- I can relate Java LSP and a huge repository :D
- Fast response from LSP really impressed me.
- Smooth-as-butter, that's a really apt description of it. In the past few days I have learned it for the improvement of acm-mode and I am very comfortable. I was a TabNine user, so it was exciting that acm-mode supported it out-of-box.
- I was hooked on Corfu and Cape right before I touched on acm-mode, but acm-mode turned me around in an instant.
- Yeah, I like the ideas behind lsp-bridge, and a great explanation of it. I may have to have a wrapper function to toggle corfu and whatnot whenever I start the lsp-bridge.
- Well, you just did, with this work, so there is at least one way that was done. It means that it should be a way to restrict multithreading in a way that doesn't break existing code but adds functionality for solving particular problems
- Yes, definitely not easy, but worth it. Your work proves it, so I hope it motivates people to solve the fundamental problem at some point. In the meantime, please continue the awesome work you are doing!
- Big thanks for working on this project, I think it's great that there's a solution out there for LSP performance. My setup has been struggling on some particularly large projects w/ many thousand line TS/Ruby files
[[!inline pages="internal(2022/info/lspbridge-after)" raw="yes"]]
[[!inline pages="internal(2022/info/lspbridge-nav)" raw="yes"]]
[[!taglink CategoryCoding]]