bug#81538: 32.0.50; Eglot: Non-local exit during window/showDocument handling
Eli Zaretskii <[email protected]> Sun, 02 Aug 2026 21:18:03 +0300
| Newsgroups | gmane.emacs.bugs |
|---|---|
| Message-ID | <[email protected]> |
> Date: Sun, 2 Aug 2026 14:05:56 -0400 > From: Troy Brown via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <[email protected]> > > The Ada Language Server has a command for showing the "other file". > This is similar to `ff-find-other-file` for navigating between an Ada > body (similar to C source) file and an Ada specification (similar to C > header) file. It has advantages over `ff-find-other-file` as it can > automatically map between files with non-standard naming conventions, > so it is preferred over `ff-find-other-file`. I trigger this command > using `eglot-execute-command` which sends a > `workspace/executeCommand`. When the Language Server command is sent, > the server responds with a `window/showDocument` request back to Emacs > to open the corresponding file. Eglot receives this request and > starts the process of opening the corresponding file (via > `find-file-noselect`), and sends a response back to the server. > > As was noted in Bug#60088, when a string sent to `process-send-string` > (via `jsonrpc-connection-send`) is large enough, it can cause > reception of output from the server (likely due to the output buffer > becoming full, causing output from the server to be processed by > `jsonrpc-connection-receive` [via `jsonrpc--process-filter`]). > > When the eglot package is loaded, it registers > `eglot--maybe-activate-editing-mode` in the > `after-change-major-mode-hook`. As part of the `find-file-noselect` > machinery, these hooks are executed and > `eglot--maybe-activate-editing-mode` is run. This function executes > `eglot--signal-textDocument/didOpen` to indicate to the server the new > document being opened (by sending `textDocument/didOpen` via > `jsonrpc-connection-send` and ultimtely via `process-send-string`). > The `textDocument/didOpen` ends up sending the entire buffer contents > of the new file to the server as part of it's payload. If this file > is large enough, it can cause the scenario above where the output > buffer becomes full and it starts processing output from the language > server. > > When Emacs starts processing the output from the server, it ends up > processing the `workspace/executeCommand` response. This bubbles down > through `jsonrpc--process-filter`, `jsonrpc-connection-receive` and > `jsonrpc--continue` where the "success function" is invoked. This > function is the lambda function setup in `jsonrpc-request` which > performs a transfer of control via the "throw" in that function. This > causes a non-local exit and an unwinding all the way back to the > `jsonrpc-request` from the original `workspace/executeCommand` > command. This non-local exit prevents the `textDocument/didOpen` from > completing and prevents the `find-file-noselect` from finishing, > leaving the buffer incompletedly initialized (e.g., `font-lock` is not > enabled, etc.) and doesn't end up popping the buffer, so it stays > hidden. > > While I've documented the method by which this problem arises for > myself, I think this scenario can arise in more generalized scenarios > where outstanding replies might be received and cause in-progress > transmissions to be aborted prematurely. I think this might be solved > by delaying processing of the process output while a send is currently > in progress. > > I have enabled numerous function traces to track this down and provide > a visible representation of what appears to be happening. The full > eglot event and trace function logs can be found in the attachments. > The following illustrates the interesting part of the eglot event log > to illustrate the client/server communication described above. > > ```text > [jsonrpc] e[10:12:28.254] --> workspace/executeCommand[13] > {"jsonrpc":"2.0","id":13,"method":"workspace/executeCommand","params":{"command":"als-other-file","arguments":[{"uri":"file:///home/troy/junk/crate/gtkada_24.0.0_80c56171/src/gtkada-mdi.adb"}]}} > [jsonrpc] e[10:12:28.255] <-- window/showDocument[4] > {"jsonrpc":"2.0","id":4,"method":"window/showDocument","params":{"uri":"file:///home/troy/junk/crate/gtkada_24.0.0_80c56171/src/gtkada-mdi.ads","takeFocus":true}} > [jsonrpc] e[10:12:28.256] --> window/showDocument[4] > {"jsonrpc":"2.0","id":4,"result":{"success":true}} > [jsonrpc] e[10:12:28.313] <-- workspace/executeCommand[13] > {"jsonrpc":"2.0","id":13,"result":null} > ``` Adding João.