GwynethLlewelyn / Go.novaextension

A quick & dirty Go language template for the Panic Nova editor
Other
34 stars 8 forks source link

Typing lags when language server is turned on #23

Open josebalius opened 2 years ago

josebalius commented 2 years ago

Nova 9.2

Thank you for the fantastic extension! I'd like to use the language server setting ON, but whenever I do so, typing becomes very laggy and you can tell the editor is waiting for the LSP to continue. Is there an additional setting I can set for LSP to be done in the background so that I don't experience this? Has this been reported before?

Thanks again

GwynethLlewelyn commented 2 years ago

I'm a bit confused...

As far as I know (and, remember, I don't really know that much...), both the LSP and the code that updates the editor while typing are done concurrently.

The LSP is an independent process. It gets launched by Nova and runs on its own. If you do a px aux|ug gopls on the Terminal, you should see that process running. So, aye, it runs on the background indeed :)

The actual 'magic' of sending things from Nova to the LSP and back again are, again, AFAIK, done on separate threads. Obviously, I cannot confirm that, but it's what I expect that Panic has done in Nova. In other words, there should be a thread listening for user input from the keyboard, while there is a separate thread running the virtual machine for the extension code (the latter is how Panic describes the implementation, i.e. each extension runs in isolation on a JavaScript virtual machine).

We (users!) have no way to tweak how these things work on the Nova side — in other words, there is no simple way of accelerating the communication between Nova and the PLS in any way. It would be nice if we could somehow raise priorities on a Nova thread, so that it runs earlier, or faster, or more often; but currently that's impossible.

There is a human limit for perceiving things as 'laggy', though. As a rule of thumb, if you press a key and something happens in a (roughly) 200 ms interval, our human brain interprets that as 'instantaneous' — that magic number, 200 ms, is the round-trip time for a signal from your brain to reach the finger muscles and back, and the same happens with any visual input. It's fascinating how it all works together, and I surely believe that you'd be endlessly bored with a full explanation, but, at the end of the day, that's how most humans work. It's not a reliable measurement for all people, though: a brain trained to do something very fast — such as playing a musical instrument... or fast-typing on a keyboard — can reduce that round-trip time by training muscle reflexes to be more-or-less automatic and independent, so that things happen much more swiftly (without the brain needing to be conscious about that process; or else, it would be impossible for a virtuoso to play the piano or a violin — or even for us normal humans to drive a car). Still, there is a limit to how quickly neural impulses are fired; it's never at 'the speed of light'!

That said, programmers tend to focus on that 200 ms limit, and the big question is: how much processing can I do in a 200 ms slot? With modern CPUs, of course, that means thousands or even millions of operations; you really can get a lot done in that slice of time. It also means that you can run many things simultaneously — so long as all of them added together don't exceed the 200 ms limit, the user behind the computer will perceive everything to be 'running at the same time'.

That said — sorry for my divagation! — I guess that what you perceive as 'laggy typing' is just a consequence of you being a fast-typer, and Nova + LPS are simply 'too slow' for you, thus things always seem to lag a little for you. I can say that on my ancient PowerBook (mid-2014), while running a considerable number of applications besides Nova (at least the 50-tab browser, GitHub desktop, sync software for my Synology NAS, an IPFS gateway, and a few more goodies), I perceive the experience of typing in Nova with the aid of the LPS as being 'slightly laggy' but not overly so — not to the extent of making it impossible for me to work. 'Slightly laggy' may mean that Nova + LPS are struggling to process a key press in under 200 ms — maybe they take 250 ms, which doesn't seem much, but it's enough for the brain to be aware that something is going on. Such tiny differences are compensated by the brain, and, to be honest, I don't perceive them any longer (at least, not consciously). It's just when it drags way above that value that I sense that something is taking too much time in responding.

So, in conclusion, how can you improve your experience?

Assuming that there aren't any major flaws on the extension code (there may be!), I know of a few reasons that may cause lag:

  1. Huge Go files (e.g. over 5,000 lines or so). Nova itself will turn automatic syntax highlighting if a file grows beyond a certain limit, simply because there is too much processing to be done in that 200 ms time limit. The larger the file, the more time it takes to process it and keep the syntax highlighting in perfect sync. If Nova already struggles beyond a certain limit, things can be much worse when running an external application, such as gopls, because you now have to account for the extra inter-process communication between Nova and the LSP (within Nova, threads communicate via intra-process communications — even memory sharing — which is orders of magnitude faster).

    The solution here is simply to break up the files in smaller, manageable bits.

  2. Too many open files in Nova (on tabs or separate windows), from different projects, all of them in Go. I believe that Nova will launch only one instance of the LPS, but, naturally enough, it now needs to send much more data to and fro the LPS, establishing communications from each thread that is 'using' the LPS. Note that in theory only 'active' tabs are supposed to be communicating with the LPS, but... I hardly have an idea on how it all fits together.

  3. Too many LPSs running at the same time. If you're like me, you're probably not using only the Go LPS, but rather a few more (I believe I have four running at the same time), depending on what languages you might be writing code at the same time (in open tabs/windows). That means, at the very least, one open connection to the external world for each of those LPS. The solution in this case would be to simply just keep one programming language active/visible at the time, so that, at least, every LSP which is not being currently used could go to sleep in the background.

    Again, that's just an idea. I do have multiple LPS running at the same time — in different projects, all of which open at the same time! — and, personally, I don't experience any of them as 'laggy'.

  4. It's not just LPS that can slow down typing. This is a common experience I have with PHP — not with Go, though. In PHP, besides running a LPS (Intelephense), I also run automatic code validation tools, namely, PHP CodeSniffer and PHP Mess Detector. These will also work in the background, in conjunction with the LSP, in real-time, while I'm typing. As a consequence, all three have to work together in sync, and make sure that each gets a fair share of the CPU, in order to apply all their validation rules at the same time (without conflicts!). This works rather well, even on my slow machine, even when I have a few Go windows open at the same time, but, to be honest, I notice a slight delay in PHP which is not present in Go. And don't get me started on JavaScript, where the amount of tools running at the same time is absurd — especially because there is so much JavaScript out there which is not broken in many files, but everything is thrown together in a single file with thousands of lines... so, aye, that will slow down typing, very perceptibly, even for me!

    So, while these nifty tools are more frequent in other environments (the Go LPS tends to do everything — or almost everything — on its own), see if you have any extensions that are also validating you Go code, running at the same time that the LPS.

  5. Huge projects (with thousands of files) may take some time in processing. Suppose you are working on a Go module on a third-party application that has a huge code base (I'm remembering at least two — Gogs and Pydio Cells). Now you type a function — and expect the LPS to tell you its parameters. That function may be anywhere — not only on the code you're working on, but also on all included packages, and if you have thousands of Go files, each with a few dozens of included packages... well, you can imagine that this may take a long time to process!

    What I have noticed so far is that the LPS — or perhaps it's Nova? — seems to be clever: it tries to process all files for your currently active window(s) first, then start searching for the included packages, and keep searching in the background while you may start receiving some results. In other words: the LPS may be 'instantaneous' in figuring out the correct parameters for a file in the current folder (let's suppose these are the ones in your project, i.e. the ones you're actively working on), take a bit longer if the reference comes from another file in the Big Project (but is still stored locally), and, finally, start scanning the external package references, one by one, until it has a pretty good working knowledge of all functions on all packages...

    This naturally takes precious time: in my case, it might take minutes, not milliseconds, and while that happens, Nova stubbornly believes that a certain function from a specific package does not exist and throws an error. Eventually, however, the LPS will finish its indexing job and acquire knowledge of these included packages and its functions — and then everything will run smoothly ever after.

    I encounter that 'issue' on a daily basis: my projects are middle-sized, as projects go, but still refer to a considerable number of external packages, which in turn reference even more, and so forth. Nova + LPS do struggle to keep themselves in sync. When I suddenly include a new package, which I haven't used before, it may take a long time until Nova/the LPS finally recognises it (and sometimes it may include the 'wrong' package, too — namely, searching on a deprecated or outdated package first, and working slowly towards the current one. That not only takes time (even if it's run in the background), but, more important, it requires assigning CPU slices of time to that work, too, while the user still expects that 'everything else' (i.e. whatever windows/tabs you have open) continues to work as quickly as ever before.

    Again, any of the above are not only way beyond my knowledge, but they're even beyond my ability to control .

Hopefully some of those suggestions are useful for you to figure out how to improve your experience with Nova and this extension...