reddit / emacs

[package-find] lsp-bridge

ckoneru · 2022-05-24 04:41
lsp-bridge - [https://github.com/manateelazycat/lsp-bridge](https://github.com/manateelazycat/lsp-bridge) Looks like the project is in infancy. Posting the link here to get it some traction.
ekd123 · 2022-05-24 05:35
On a side note, this package was announced and discussed at Emacs China. If you can read Chinese or are willing to use an online translator, check out the original post: [https://emacs-china.org/t/lsp-bridge/20786](https://emacs-china.org/t/lsp-bridge/20786) **edit**: I want to add that my experience with it is very positive. IMHO It really lives up to its claim ("fastest"). Even though it's still in infancy, I recommend everyone to try and contribute.
saevarb · 2022-05-24 06:39
It would be amazing if we could get better performance, but given that they chose to do this in python, I'm not exactly hopeful. But LSP performance is easily the worst thing about using emacs as a daily driver for me. I've frequently tried diving into profile traces to figure out why emacs becomes so sluggish so easily, but I've never found anything conclusive. My current suspicion is that lsp simply handles slow language servers incredibly poorly and leaks that into the user experience, but i'm not sure if this is lsp's issue or just a fundamental limitation in emacs. But I know that handling them better is possible, since the experience in VSC in the same exact codebase is leagues ahead of emacs.
jimehgeek · 2022-05-24 08:26
What version of Emacs are you using? Cause your experience used to be what my experience was like too on 26.x, and a slightly lesser extent on 27.x. Native JSON parsing of Emacs 27.x made a noticeable difference. But in summer 2020 I started using custom builds with native compilation enabled. It made a world of a difference, Emacs became as snappy as VSCode for me. And native compilation is now in 28.x as an optional configure flag. That said, I’m curious about lsp-bridge and will give it a try sometime soon.
saevarb · 2022-05-24 08:38
I've been using native-comp since it was possible, and am currently using 28.1. It certainly makes a difference, but it's nowhere near enough. Emacs' slowness is sort of a death by a thousand cuts. Everything is just a little bit slower, and it all adds up, and occasionally you get a "perfect storm" where, say, LSP is churning through completion JSON, the buffer is being formatted and you're saving, which may trigger another thing(like `eslint`), and what you end up with is just a 3-5 second hang where nothing happens. This isn't helped by how easy it is to accidentally set something up in emacs which works badly with what is already set up. For example, it is pretty easy to accidentally cause something like format on save to happen in a way that runs a syntax checker twice(the buffer is saved, formatted and saved again, or something like that). This sort of emergent bad behavior is almost impossible to avoid because of the way emacs works and everything is messing with the same global environment, everything runs on hooks, and doing things like advicing functions is a not so uncommon way to fix a problem.
bspwm_js · 2022-05-24 08:52
I think you have problem gc
collapsing_spacetime · 2022-05-24 10:30
i incorporated into my config many various changes done via doom emacs that adjust things like when emacs rerenders as well as using more emacs native packages like corfu over company. additionally, configuring lsp to have more sane timings and use plists basically eliminated hangs for me 😊 and yea, format on save is a terrible idea, always something i disable. I/O is always expensive, especially in single threaded programs like emacs.
ErnestKz · 2022-05-24 10:52
Have you tried configuring the `*-delay` variables? For the longest time i didn't know they were a thing. e.g lsp-idle-delay, company-idle-delay, etc.
DefiantAverage1 · 2022-05-24 11:12
Huge fan and user of Emacs and LSP. TLDR of why/how lsp-bridge's significantly faster over lsp-mode and eglot?
takutekato · 2022-05-24 11:17
I'm a bit hesitant because their issues and PR lists are quite... unsearchable.
ckoneru · 2022-05-24 11:48
Can you please share your configuration.
ekd123 · 2022-05-24 12:20
I read some code of lsp-bridge and eglot, but none of lsp-mode. Please correct me if I'm wrong. 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 process, and hence the emacs session itself stays always responsive, as it has very few things to do. Compare: * eglot (`eglot-completion-at-point`) * you somehow trigger a completion * lsp client prepares a completion request to the lsp server * wait for the result synchronously (ie. you get stuck here if the lsp server does not return results quickly) * show a popup window * lsp-bridge * you somehow trigger a completion * lsp-bridge sends a completion request, and returns immediately * no blocking at all! * you are free to move around in your buffer now. literally zero wait time. * lsp-bridge in the background (an external process, the companion python script) waits for the completion results, and once it gets them, lsp-bridge notifies emacs to show a completion popup window. * lsp-bridge takes care to discard stale responses and cache useful responses (so later calls to `complete-at-point` also return immediately). This is also why you have to turn off auto completion (e.g. `corfu-auto`) to use lsp-bridge. I feel there could be even more improvements (e.g. we can absolutely replicate the idea in pure Emacs Lisp), but the results are already impressive! **edit**: To be fair, I should mention eglot *does* have asynchronous requests for e.g. initialization, but just not for the completion, which is what a user experiences the most. I guess João Távora wanted to make everything async, but unfortunately he was limited by what we currently have in Emacs.
arthurno1 · 2022-05-24 12:50
> given that they chose to do this in python I believe the bulk of improvement is in asynchronous processing. The implementation language is not that important. Very few LSP servers are implemented in C or C++, if that was your concern.
arthurno1 · 2022-05-24 12:58
> lsp-bridge sends a completion request, and returns immediately > > no blocking at all! > you are free to move around in your buffer now. literally zero wait time. But if you trigger completion, why would you want to move around in the buffer? If you are asking for completion, you would like to see some list of available completions to choose and complete at the point where you are, usually. Isn't it so? > I should mention eglot does have asynchronous requests for e.g. initialization, but just not for the completion, which is what a user experiences the most. I guess João Távora wanted to make everything async, but unfortunately he was limited by what we currently have in Emacs. Eglot runs in its own process, so there shouldn't be problems to send requests asynchronously. I think it is rather a problem that if we ask for completion, we want that completion to happen, we don't want to do something else in the meanwhile, from a user view. Emacs could maybe do something else, like garbage collect, while waiting for the asynchronous response, but then there is a risk of not responding fast when completion finally arrives, so I am not sure if asynchronous completion is the best idea. However, completion sources could be still acquired/queried asynchronously in parallel on the server side before composed into one list and sent to Emacs. I don't know, just a thought, I might be wrong about it as well.
saevarb · 2022-05-24 13:14
No, most language servers are implemented in the same language they are written for, which is unfortunately frequently the reason they are so slow. I'm fully aware of this. Python is still pretty slow, and you don't need to throw a lot at it for there to be noticeable latency. I'm not saying this can't help at all. It's entirely possible it can improve the experience. But that doesn't make python any less of a bad choice in my eyes when the primary goal is to improve performance. Personally, though, I'm not very fond of [this kind of additional complexity](https://github.com/manateelazycat/lsp-bridge/blob/master/framework.png) in my editor just to make the emacs experience less painful. Caching also brings its own set of problems.
arthurno1 · 2022-05-24 13:41
> Python is still pretty slow, and you don't need to throw a lot at it for there to be noticeable latency. When you say "Python is slow", it is very generic and not much saying. I would say it depends on the workload and chosen solution. I wouldn't agree the language itself really matters. People do lots of high intensive processing in Python, OpenCV, TensorFlow, Keras, natural language processing etc. > Personally, though, I'm not very fond of this kind of additional complexity in my editor just to make the emacs experience less painful. Caching also brings its own set of problems. Unless you would like to work with the internals of that solution, I don't see how it matters to you (or me) as an end user. As long as you can M-x package-install ..., you shouldn't have to worry about how simple or complex it is internally. > (...) that doesn't make python any less of a bad choice in my eyes when the primary goal is to improve performance. The trick here is to use an external process, since Emacs itself is not multithreaded. If this was done in the main Emacs process, it would lock Emacs while collecting and processing lsp responses (as LSP does). They could use JS on Node/Deno or with CommonLisp (SBCL/CCL) or something similar. It does not really matter which choice of language they do. I guess they choose Python because the author is probably familiar with Python.
ekd123 · 2022-05-24 13:43
>... why would you want to move around in the buffer?... > >... we don't want to do something else in the meanwhile, from a user view ... It's very common. For example, LSP completion can be triggered by certain characters (e.g. `.`, `->`, an identifier prefix which is more than 3 characters), and the user is probably still typing more characters: the user definitely doesn't want to wait for the responses here. *But when the user needs the results, they must be there already.* Therefore, there's a dilemma: completions must be triggered excessively, while the user only needs few of them. This is where lsp-bridge shines: it just hides the latencies from the critical path, even if it doesn't reduce any computations. By comparison, the conventional wisdom is to suppress excessive completions to avoid these unwanted latencies, such as `company-idle-delay`. It's not a satisfactory solution, because it introduces one more tradeoff a user has to care about...
arthurno1 · 2022-05-24 13:57
> or example, LSP completion can be triggered by certain characters (e.g. ., ->, an identifier prefix which is more than 3 characters) Exactly, and ideally we would see a completion list momentously, in the best of worlds! :-) > the user probably is typing more characters: the user definitely doesn't want to wait for the responses here > So completions must be triggered excessively, and the user actually does not need most of them. I am not sure what you mean here; you mean the completions are recomputed after the completion is triggered, or before? If you mean they compute lists of *possible* completions asynchronously while user type, before a '.' or '->' is typed, so that a list is ready once the completion is actually asked for, then we are in agreement. If that was meant, then I misunderstood the Op originally, apologize in that case :). > This is where lsp-bridge shines: it just hides the latencies from the critical path, even if it doesn't reduce any computations. I don't think you can reduce computations, either. You have to get a list of all available candidates to be able to filter ones that are needed, which Emacs can do on its own pretty fast. The server, though, has to precompute the list of all candidates, and that can be done asynchronously by precomputing possibly several lists, as suggested above.
ekd123 · 2022-05-24 14:19
> I am not sure what you mean here > > ... filter the list of candidates ... Good point that once you have a candidate list, you can just filter out the ones you want. I completely forgot this... I was speaking from capf's perspective. `completion-at-point` does not distinguish whether you are filtering or not. (The same to corfu since it's just a frontend to capf. I'm not familiar with company.) Hence `xyz.|` (`|` = the point) and `xyz.a|` can possibly trigger two separate calls to `completion-at-point`. And to make everything smooth, capf must be called whenever it can be called, so it's more than what's needed. LSP servers can handle partial completions like `xyz.a|`. (Of course if you have candidates for `xyz.|` you can use them for `xyz.a|`, but I'm not really sure what eglot and lsp-mode do here. lsp-bridge seems to issue excessive lsp completion requests. I guess vscode does the same?) > the server just needs to return the list of all possible candidates AFAIK, lsp servers return many kinds of information, even including documentation. I do hope this can be customized to reduce IPC traffic...
saevarb · 2022-05-24 14:21
> When you say "Python is slow", it is very generic and not much saying. I would say it depends on the workload and chosen solution. I wouldn't agree the language itself really matters. People do lots of high intensive processing in Python, OpenCV, TensorFlow, Keras, natural language processing etc. Yes, I'm aware of how python and its ecosystem works. I've used python for many years. It's absolutely true that for a lot of things a lot of people use python for, the underlying libraries are actually written in much faster languages like C and Fortran. This isn't really supporting the point you're trying to make, though, because what we are discussing right now is exactly none of those things, and in fact, the reason those libraries aren't written in python is because it's way too slow. When I say "Python is slow", I'm not saying "all the libraries in the python ecosystem are slow" or "every time someone uses python it is slow for everything". I'm saying that comparatively, python, as an interpreted language, is a lot slower than a lot of other languages. It is slow to the point where just throwing a few megabytes of JSON at it will show noticeable latency compared a faster language.. which is basically exactly what this middleware is doing. Ingesting a lot of JSON and caching it. > Unless you would like to work with the internals of that solution, I don't see how it matters to you (or me) as an end user. As long as you can M-x package-install ..., you shouldn't have to worry about how simple or complex it is internally. This is just plain naive. It can very easily become your problem when the caching logic doesn't work as intended and you get stale results, or if it somehow ends up not caching and keeps making requests. The point is that we shouldn't *need* this additional complexity just to make emacs editing tolerable. > The trick here is to use an external process, since Emacs itself is not multithreaded. If this was done in the main Emacs process, it would lock Emacs while collecting and processing lsp responses (as LSP does). They could use JS on Node/Deno or with CommonLisp (SBCL/CCL) or something similar. It does not really matter which choice of language they do. I guess they choose Python because the author is probably familiar with Python. I understand what this does and how it aims to speed up the experience. I can even imagine it working quite well. I *still* don't think this kind of additional complexity should be needed, and that this should be fixed in emacs so that we don't need to run 5 sidecar processes just to have a tolerable editing experience. Really, this kind of work happening in the ecosystem should be telling the emacs maintainers that there is something horribly wrong.
arthurno1 · 2022-05-24 15:32
> This isn't really supporting the point you're trying to make, though, because what we are discussing right now is exactly none of those things, and in fact, Actually we do. You are claiming that Python is "slow" for this kind of stuff, and I am just pointing out that there is a lot of high-performance software used from within Python as the glue language. I don't see reason why they couldn't use cython or pandas or numpy to process strings for the lsp server, if it turns out python is too slow. > It is slow to the point where just throwing a few megabytes of JSON at it will show noticeable latency compared a faster language You are aware of [simdjson](https://github.com/simdjson/simdjson) being [available in python](https://github.com/TkTech/pysimdjson) if you really need some json crunching, albeit json module in Python is implemented in C itself, so I don't think understand why do you think Python is slow there? > the reason those libraries aren't written in python is because it's way too slow No they write those libraries in C/C++/Fortran/Cuda/Whatever, because Python is a glue language, designed for rapid prototyping and ease of use, in a same manner as Tcl, Bash, Perl or even Emacs Lisp, not to compete in runtime execution speed. Of course, you would write a performance part in a lower level language if the performance is lacking, and that is what people do. You can use Cython if Python is too slow for you, or IronPython or whatever you prefer. Anyway, I don't care, you seem to have your opinions, and you are of course free to have them. I am just happy if they make better LSP solution for Emacs. It would be cool if they can get along with the already existing LSP project, so we can re-use existing code ecosystem and configurations, and speed that one up, instead of creating a completely new solution. But whatever happens, if there is a speed improvement, which I suppose there will be, it is a good and welcome thing.
arthurno1 · 2022-05-24 15:41
> Hence xyz.| (| = the point) and xyz.a| can possibly trigger two separate calls to completion-at-point. Ok, Then we were talking about different things. IMO, completion lists should be computed when you type x|, one for xy|, one for xyz| and so on. Actually those are subsets of each other, so the server could just filter the initial bigger list, but that is really up to the server. Once we type '.' the server would just return the last list. Any characters typed afterwards are just a filter for the list, since the new list is always a subset of the existing set list of all candidates. Or if you have a language like say bash or lisp that does not use dots or ->, after a certain number of characters, what user configures the system with, say two or three typed chars. If user does not ask for the completion that is unnecessary work, but at lest the result can be cached if user asks for the completion at another time. What you are talking about is rather an artifact that completion is too slow. I remember in old Netbeans or Eclipse, I could type the entire name of a variable or function before a pop-up with completion candidates was even shown. > AFAIK, lsp servers return many kinds of information, even including documentation. I do hope this can be customized to reduce IPC traffic... Indeed.
ieure · 2022-05-24 15:42
> Lsp-bridge's goal is to become the fastest LSP client in Emacs. > Lsp-bridge uses python's threading technology… ahhh, [tugs collar]
saevarb · 2022-05-24 15:55
> Actually we do. You are claiming that Python is "slow" for this kind of stuff, and I am just pointing out that there is a lot of high-performance software used from within Python as the glue language. I don't see reason why they couldn't use cython or pandas or numpy to process strings for the lsp server, if it turns out python is too slow. Let's play that out a bit. Let's say they went with cython. What does that mean? Well, it means that you now require a specific python implementation, and you are doing so explicitly to get around the fact that python is slow. Let's say they tried to use pandas or numpy to speed up processing. Why would they do that? Because python is so slow, they are having to resort to hacks to get around the fact that it's slow. This isn't even discussing what "processing strings in numpy or pandas" would even look like. Neither of those are string processing libraries. > You are aware of simdjson being available in python if you really need some json crunching, albeit json module in Python is implemented in C itself, so I don't think understand why do you think Python is slow there? Yes. There are multiple implementations, in fact. I wonder why that is, though. Do you think it may be because the people who built those solutions ran into issues with standard python JSON processing being too slow? (Hint: Yep) > No they write those libraries in C/C++/Fortran/Cuda/Whatever, because Python is a glue language, designed for rapid prototyping and ease of use, in a same manner as Tcl, Bash, Perl or even Emacs Lisp, not to compete in runtime execution speed. Of course, you would write a performance part in a lower level language if the performance is lacking, and that is what people do. You can use Cython if Python is too slow for you, or IronPython or whatever you prefer. You're right. What I said wasn't very precise. But the fact remains that those libraries would be literally impossible to implement in native python to a useful degree because they would be too slow. If you have ever used any real chunk of the scientific python ecosystem in any serious way, then you'll probably also be familiar with how much thought you sometimes have to put into ensuring that what you are doing takes the correct happy path. It is very easy to do something just slightly wrong in numpy or pandas, for example, that will totally cripple the performance of your algorithm. Pandas is particularly bad here. There is no more room for extra slowness in emacs. It's already slower at almost everything than it should be, and building a python sidecar process to speed it up is not a sound decision if the main goal is improved performance. Also worth noting that lsp-bridge relies on python multi-threading, which is notoriously horrible to use, in large part due to the global interpreter lock. This is a perfect example of a death by a thousand cuts. People seem to think that you can keep building an infinite tower of abstractions without ever having to pay for it. What happens instead is that you end up with something slow where it's nearly impossible to find the culprit, because the culprit isn't a single thing, but a series of bad decisions made throughout the entire software stack all of which are adding anywhere between micro- and milliseconds of latency. This will *very* easily happen with python, and anyone who has used python to any serious degree knows this. It's not even an indictment of python. It's literally just a fact of using it. I applaud the author of `lsp-bridge` for trying to improve things, but I just think it's the wrong way to solve the problem, using the wrong tools.
arthurno1 · 2022-05-24 16:51
> There are multiple implementations, in fact. I wonder why that is, though. Do you think it may be because the people who built those solutions ran into issues with standard python JSON processing being too slow? Simdjson had nothing to do with Python when it was started. The author is a well known professor interested in optimization. Simdjson started as an experiment to parallelize json parsing and to see how much throughput they can get through a CPU, for C++ programs. Since it was made available, people wrote bindings for other languages, not just Python. Pythons native JSON library is implemented in C, so if Python is slow for you, so would be even a C program that uses the same library. That has nothign to with Python. > But the fact remains that those libraries would be literally impossible to implement in native python to a useful degree because they would be too slow. How is that an argument at all against using Python? Then nobody would use it for anything, if that was a valid argument. Or for that matter any scripting language at all, since they all work pretty much the same way as Python. > If you have ever used any real chunk of the scientific python ecosystem in any serious way, then you'll probably also be familiar with how much thought you sometimes have to put into ensuring that what you are doing takes the correct happy path. If you have used any scientific, game, graphic, simulation or visualization library you would be surprised how much work goes into ensuring that code takes correct paths, even more so when you use C, C++ and especially when you put GPUs into the mix. Python makes it actually easier to prototype things fast. I wish though we had those libraries available in Elisp or CL, but it is what it is, it is still better than plain C or C++. > It's already slower at almost everything than it should be Nah, I wouldn't agree to be honest. Gives us numbers instead of rants. > Also worth noting that lsp-bridge relies on python multi-threading, which is notoriously horrible to use, in large part due to the global interpreter lock. Oh, please. Leave that to the authors. If they sort it out, what does it matter to you if it is horrible or not? You are free to implement an LSP server in a programming language of your choice, or to give Emacs what it needs in terms of LSP or threading or whatever you consider is the best technology to have. I will be happy to use it. Thank you very much if you do!
collapsing_spacetime · 2022-05-24 16:55
sure! [customacs](https://github.com/xevrem/customacs) oh, FYI, the literal config hasn't been updated in ages, so its useless, and the Dockerfile hasnt been tested in a while and probably doesnt work either 😅 i generally use a very aggressive custom hook delay approach... on my machine it loads cold in about 60-200 miliseconds 😁 (give or take whatever else is going on) also, its likely running this config will fail if you don't have `fd-find` installed, since i use that over `find` when utilizing `straight.el` runs generally well under 28.1 and 29 edit: extra info
Ghosty141 · 2022-05-24 17:56
>This is also why you have to turn off auto completion (e.g. corfu-auto) to use lsp-bridge. Uhhh this goes against the "use native emacs apis" approach corfu, orderless, vertico etc. go for. Not too big of a fan personally.
arthurno1 · 2022-05-24 19:40
If you build custom 28.1, then try the master instead. There have been quite few speed improvements recently, check [this discussion](https://www.reddit.com/r/emacs/comments/sunkzx/is_it_only_me_or_did_emacs_without_native_comp/).
jimehgeek · 2022-05-24 22:09
Yep, I’ve been running nightly builds from master ever since native comp was merged in :)
sunnyata · 2022-05-24 23:00
Well as the others use Emacs threading technology...
emacs_expert · 2022-05-25 02:05
Completely agree. It helps a lot to cut down on frills you don't need. (Like the other commenter said, get rid of format-on-save and bind it to a key instead.) Disable things like syntax checking as you type or make them run on save instead. Get rid of large, hefty packages like `helm` and use simpler ones, like `vertico`. Increase the GC threshold and set it to run when you tab out or go idle: ``` (add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold (* 100 1000 1000)))) (add-hook 'focus-out-hook 'garbage-collect) (run-with-idle-timer 5 t 'garbage-collect) ``` I just disabled my fancy modeline and `show-parens` and my experience is smoother. Try disabling one minor mode at a time and see how things feel with each change. Also, use M-x profiler-start and profiler-report to profile runtime.
ndpian · 2022-05-25 14:29
Wishful thinking: Hope some lsp client supports TRAMP with local lsp server instead of lsp server having to sit in the remote server itself.
haidongji · 2022-05-25 23:41
The package author blogged about it on 05/12. It was written in Chinese, but the diagram illustrating its design is in English. It looks pretty impressive, and I think is on the right track. https://manateelazycat.github.io/emacs/2022/05/12/lsp-bridge.html
Sad_Entry9267 · 2022-09-22 12:26
lsp-bridge support TabNine now.