Subject: bug#61350: Eglot over Tramp freezes with large project

From: João Távora <[email-masked]>
Date: Thu, 16 Mar 2023 13:28:07 +0000

Jim Porter <[email-masked]> writes:

> On 3/15/2023 2:49 PM, João Távora wrote:
>> SLY, jsonrpc.el, and other code is synchronous as well (the completion
>> API is synch, as you well know).  `accept-p-o` + a filter that invokes
>> a closure that throws out of the loop is a great way to do this.
>> See jsonrpc-request, for example.  No JUST-THIS-ONE, and has
>> been working fine in many forms since Emacs 24.3 AFAIK.
>
> Assuming I understand the context here correctly, this sort of thing
> is part of why Chris Wellons' emacs-aio package uses 'run-at-time' for
> handling resolved promises[1]:

There's a relation, but it's not a direct relation.  emacs-aio is a
promise/future/cps library which uses timers.  I was describing this
design pattern for _synch_ requests over Emacs's asynchronous processes

   (set-process-filter
    proc (lambda (proc output)
           (internal-default-process-filter proc output)
           (when (and (process-get proc 'busy) (buffer-live-p (process-buffer proc)))
             (with-current-buffer (process-buffer proc)
               (when (search-forward ", DAVE.\n")
                 (unwind-protect (throw 'done (buffer-substring (point-min) (point)))
                   (process-put proc 'busy nil)
                   (delete-region (point-min) (point))))))))

   (setq answer-from-proc (catch 'done
                            (process-put proc 'busy t)
                            (process-send-string proc "OPEN THE POD BAY DOORS\n")
                            (while (accept-process-output))))

This is very simplified (and untested), but that's the gist.  You can
then add cancellation, timeouts, etc.  Also normally (in SLY and
JSONRPC) instead of a single flag 'busy, you look up a table of pending
requests

This pattern has worked very well for me, for a long time, 10+ years.
SLIME used this pattern back in 2000's, there where I saw it (and
distilled it).  It's similar to what "await" does other languages.

>> If the result is ready call the callback in the next event loop turn
>> using run-at-time. This is important because it keeps all the
>> asynchronous components isolated from one another. They won’t see
>> each others’ frames on the call stack, nor frames from aio. This is
>> so important that the Promises/A+ specification is explicit about
>> it.
> While a solution specific to the problem in this bug likely doesn't
> require an entire asynchrony framework, if we get one into Emacs, it
> should definitely support this case.

Sure, I'd be happy with just using the stuff that's been in Emacs for
ages.

João