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

From: Michael Albinus <[email-masked]>
Date: Sun, 05 Mar 2023 12:21:41 +0100

João Távora <[email-masked]> writes:

Hi João,

>> Yes. But Tramp calls accept-process-output only, if it has send a
>> command to the remote shell, and it expects something to be returned. At
>> least the shell prompt.
>
> Yes.  Tramp is doing the right thing.  It really expects a response to
> come.  And more often than not, it does.  But sometimes it doesn't, and
> that's when we hang.

After digging further, I believe I understand now why it hangs. We have
the following scenario:

- Both Eglot and Tramp use the same ssh connection with enabled ControlMaster.

- Eglot gets JSON output from the remote LSP server. In
  jsonrpc--process-filter, this output is handled. It includes a call to
  file-truename, which triggers Tramp to send a request in its own
  process to the remote side.

- The remote side returns the answer for Tramp (shell output). However,
  the ssh socket is still full of the jsonrpc process output, which
  waits to be handled.

- So the socket is blocked. The jsonrpc output cannot be read, because
  jsonrpc--process-filter waits for the result of file-truename. And the
  Tramp process output cannot be handled, because it is stuck in the
  socket after the jsonrpc output.

The proper solution is indeed to have two connections, and to refuse use
of ControlMaster.

Surprisingly, this is not new to Tramp :-) But I've simply forgotten the
case ...

See tramp-integration.el. There is a comment for bug#45518, a similar
blocking in compile.el. And the solution is indeed to disable ssh
ControlMaster. Tramp hooks into compilation-mode-hook, and sets
tramp-use-ssh-controlmaster-options buffer-local to nil.

I'd like to apply the same solution for eglot.el. Unfortunately, there's
no hook Tramp could use. I've played with eglot-server-initialized-hook,
but this is applied too late.

So would you mind to add a hook to Eglot, which runs before calling
make-process, but in the proper process buffer? When you've added it,
I'll let Tramp hook into, and you don't need any longer the Tramp
specific code in eglot.el.

In parallel, I'll extend tramp-use-ssh-controlmaster-options to accept a
further value 'suppress', which overrides possible settings in ~/.ssh/config.

> João

Best regards, Michael.