-
Notifications
You must be signed in to change notification settings - Fork 65
Description
Environment
- OS and Version: GNU/Linux 24.04
- IDE Version: Emacs 29, 30, 31
- Ada & SPARK Extension Version: ALS 2026.0.202510141
Bug Summary and Reproducer
Bug Summary:
The Emacs major mode ada-ts-mode can be configured to allow indentation to be handled by the Ada Language Server instead of handling indentation itself. If configured in this way, triggering of Emacs electric indentation will cause a textDocument/rangeFormatting request to be sent to the ALS for the current line. Certain triggers are used to cause electric indentation, such as the typing of a closing parenthesis (e.g., )).
Additional packages may provide "smart" behavior of pair characters (e.g., a closing parenthesis). For instance, when point (i.e., the cursor) is just before a closing parenthesis and the user presses ), the package may just move point to the other side of the existing closing parenthesis rather than inserting an additional closing parenthesis. Under the hood, this is implemented by temporarily inserting the closing parenthesis, then removing it. These edits are sent to the ALS via textDocument/didChange.
It has been observed that if a textDocument/didChange is immediately followed by a textDocument/rangeFormatting request, that the range formatting response can provide a response that causes text to be deleted. This is because the range specified in the response is too large (e.g., 2 lines instead of 1 line) causing the editor to delete text on the following line. An example of this behavior can be observed in brownts/ada-ts-mode#7. Additionally, it appears the ALS may not have processed all of the changes before responding to the range formatting request, as the text in the response contains an additional ) .
Steps to reproduce:
I have created an Emacs-based test which demonstrates this behavior (see commit) and runs as part of CI (see job). This reproduces the issue in question. However, creating your own reproducer can start with the original example provided in brownts/ada-ts-mode#7 and causing the textDocument/didChange and textDocument/rangeFormatting updates as described above.
The log provided further down is from a local run of the Emacs-based test.
Expected behavior:
I expect that the textDocument/rangeFormatting response does not cause loss of content. Additionally, I expect that all preceding textDocument/didChange methods have been fully processed prior to the textDocument/rangeFormatting being processed.
Configuration and Logs
[ALS.MAIN] ALS version: 2026.0.202510141 () (08:36:11.028)
[ALS.MAIN] Initializing server ... (08:36:11.028)
[ALS.MAIN] GPR PATH: (08:36:11.028)
[ALS.MAIN] PATH: /home/troy/.cargo/bin:/home/troy/bin:/home/troy/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-10-oracle/bin:/usr/lib/jvm/java-10-oracle/db/bin (08:36:11.028)
[ALS.MAIN] Trying config file: /home/troy/.config/als/config.json (08:36:11.028)
[ALS.MAIN] /home/troy/.config/als/config.json doesn't exist (08:36:11.028)
[ALS.MAIN] Trying config file: /home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/.als.json (08:36:11.028)
[ALS.MAIN] /home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/.als.json doesn't exist (08:36:11.028)
[ALS.MAIN] Ada version used for predefined completion: ADA_2020 (08:36:11.033)
[ALS.IN] {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":1146518,"clientInfo":{"name":"Eglot","version":"1.18"},"rootPath":"/home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/","rootUri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair","initializationOptions":{},"capabilities":{"workspace":{"applyEdit":true,"executeCommand":{"dynamicRegistration":false},"workspaceEdit":{"documentChanges":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":false},"configuration":true,"workspaceFolders":true},"textDocument":{"synchronization":{"dynamicRegistration":false,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":false,"completionItem":{"snippetSupport":false,"deprecatedSupport":true,"resolveSupport":{"properties":["documentation","details","additionalTextEdits"]},"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true},"contextSupport":true},"hover":{"dynamicRegistration":false,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":false,"signatureInformation":{"parameterInformation":{"labelOffsetSupport":true},"documentationFormat":["markdown","plaintext"],"activeParameterSupport":true}},"references":{"dynamicRegistration":false},"definition":{"dynamicRegistration":false,"linkSupport":true},"declaration":{"dynamicRegistration":false,"linkSupport":true},"implementation":{"dynamicRegistration":false,"linkSupport":true},"typeDefinition":{"dynamicRegistration":false,"linkSupport":true},"documentSymbol":{"dynamicRegistration":false,"hierarchicalDocumentSymbolSupport":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}},"documentHighlight":{"dynamicRegistration":false},"codeAction":{"dynamicRegistration":false,"resolveSupport":{"properties":["edit","command"]},"dataSupport":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"isPreferredSupport":true},"formatting":{"dynamicRegistration":false},"rangeFormatting":{"dynamicRegistration":false},"rename":{"dynamicRegistration":false},"inlayHint":{"dynamicRegistration":false},"callHierarchy":{"dynamicRegistration":false},"typeHierarchy":{"dynamicRegistration":false},"publishDiagnostics":{"relatedInformation":false,"versionSupport":true,"codeDescriptionSupport":false,"tagSupport":{"valueSet":[1,2]}}},"window":{"showDocument":{"support":true},"showMessage":{"messageActionItem":{"additionalPropertiesSupport":true}},"workDoneProgress":true},"general":{"positionEncodings":["utf-32","utf-8","utf-16"]},"experimental":{}},"workspaceFolders":[{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair","name":"~/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/"}]}} (08:36:11.050)
[ALS.MAIN] Processing initializationOptions from initialize request (08:36:11.052)
[ALS.OUT] {"jsonrpc":"2.0","id":1,"result":{"capabilities":{"textDocumentSync":2,"completionProvider":{"triggerCharacters":[".",",","'","("],"resolveProvider":true},"hoverProvider":true,"signatureHelpProvider":{"triggerCharacters":[",","("],"retriggerCharacters":["\b"]},"declarationProvider":true,"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":true,"referencesProvider":true,"documentHighlightProvider":true,"documentSymbolProvider":true,"codeActionProvider":{"workDoneProgress":false,"codeActionKinds":["quickfix","refactor.rewrite","source.organizeImports"],"resolveProvider":false},"workspaceSymbolProvider":true,"documentFormattingProvider":true,"documentRangeFormattingProvider":true,"documentOnTypeFormattingProvider":{"firstTriggerCharacter":"\n"},"renameProvider":{"prepareProvider":true},"foldingRangeProvider":true,"selectionRangeProvider":true,"executeCommandProvider":{"commands":["als-other-file","als-suspend-execution","als-reload-project","als-open-project-file","als-open-log-file","als-show-dependencies","als-gpr-dependencies","als-source-dirs","als-executables","als-mains","als-get-project-attribute-value","als-project-file","als-object-dir","als-named-parameters","als-auto-import","als-suppress-separate","als-refactor-delete-entity","als-refactor-extract-subprogram","als-refactor-extract-variable","als-refactor-inline_variable","als-refactor-introduce-parameter","als-refactor-pull_up_declaration","als-refactor-replace-type","als-refactor-sort-case-alphabetical","als-refactor-sort-case-declaration","als-refactor-sort_dependencies","als-refactor-swap_if_else","als-refactor-add-parameters","als-refactor-remove-parameters","als-refactor-move-parameter","als-refactor-change-parameter-mode","als-refactor-change_parameters_type","als-refactor-change_parameters_default_value"]},"callHierarchyProvider":true,"semanticTokensProvider":{"legend":{"tokenTypes":[],"tokenModifiers":[]},"range":true,"full":true},"typeHierarchyProvider":true,"inlineValueProvider":true,"workspace":{},"alsReferenceKinds":["reference","access","write","call","dispatching call","parent","child","overriding"]}}} (08:36:11.053)
[ALS.OUT] {"jsonrpc":"2.0","method":"window/logMessage","params":{"type":4,"message":"Log file is: /home/troy/.als/ada_ls_log.2025-12-07T083611.log"}} (08:36:11.053)
[ALS.IN] {"jsonrpc":"2.0","method":"initialized","params":{}} (08:36:11.053)
[ALS.PROJECT] Looking for a unique project at the root (08:36:11.054)
[ALS.PROJECT] Found 0 projects at the root: (08:36:11.054)
[ALS.PROJECT] Loading the implicit project because NO_PROJECT (08:36:11.054)
[ALS.IN] {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb","version":0,"languageId":"ada","text":"procedure Example is\nbegin\n Ada.Text_IO.Open (File, Ada.Text_IO.In_File, To_String (File_Name);\n while not Ada.Text_IO.End_Of_File (File) loop\n null;\n end loop;\nend Example;\n"}}} (08:36:11.058)
[ALS.IN] {"jsonrpc":"2.0","method":"workspace/didChangeConfiguration","params":{"settings":{}}} (08:36:11.059)
[ALS.IN] {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb","version":2},"contentChanges":[{"range":{"start":{"line":2,"character":68},"end":{"line":2,"character":68}},"rangeLength":0,"text":")"},{"range":{"start":{"line":2,"character":68},"end":{"line":2,"character":69}},"rangeLength":1,"text":""}]}} (08:36:11.129)
[ALS.IN] {"jsonrpc":"2.0","id":2,"method":"textDocument/rangeFormatting","params":{"textDocument":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb"},"options":{"tabSize":3,"insertSpaces":true,"insertFinalNewline":true,"trimFinalNewlines":true},"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":70}}}} (08:36:11.130)
[ALS.MAIN] Creating fallback context (08:36:11.566)
[ALS.OUT] {"jsonrpc":"2.0","id":1,"method":"window/workDoneProgress/create","params":{"token":"ada_ls-1146525-indexing-1"}} (08:36:12.103)
[ALS.MAIN] In Message_Handler Text_Document_Did_Open URI: (08:36:12.103)
[ALS.MAIN] file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb (08:36:12.103)
[ALS.OUT] {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair","diagnostics":[{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"severity":2,"source":"ada.project","message":"No project was found in the root directory. Please create a GPR project file and add it to the configuration."}]}} (08:36:12.103)
[ALS.IN] {"jsonrpc":"2.0","id":1,"result":null} (08:36:12.103)
[ALS.MAIN] Out Message_Handler Text_Document_Did_Open (08:36:12.104)
[ALS.MAIN] Processing received workspace/didChangeConfiguration notification (08:36:12.104)
[ALS.OUT] {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb","diagnostics":[]}} (08:36:12.104)
[ALS.OUT] {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb","diagnostics":[]}} (08:36:12.104)
[ALS.OUT] {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair","diagnostics":[]}} (08:36:12.104)
[ALS.OUT] {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair","diagnostics":[{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"severity":2,"source":"ada.project","message":"No project was found in the root directory. Please create a GPR project file and add it to the configuration."}]}} (08:36:12.104)
[ALS.OUT] {"jsonrpc":"2.0","id":2,"result":[{"range":{"start":{"line":2,"character":0},"end":{"line":4,"character":0}},"newText":" Ada.Text_IO.Open (File, Ada.Text_IO.In_File, To_String (File_Name));\n"}]} (08:36:12.106)
[ALS.OUT] {"jsonrpc":"2.0","method":"$/progress","params":{"token":"ada_ls-1146525-indexing-1","value":{"kind":"begin","title":"Indexing","percentage":0}}} (08:36:12.106)
[ALS.OUT] {"jsonrpc":"2.0","method":"$/progress","params":{"token":"ada_ls-1146525-indexing-1","value":{"kind":"end"}}} (08:36:12.106)
[ALS.IN] {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb","version":3},"contentChanges":[{"range":{"start":{"line":2,"character":0},"end":{"line":4,"character":0}},"rangeLength":120,"text":" Ada.Text_IO.Open (File, Ada.Text_IO.In_File, To_String (File_Name));\n"}]}} (08:36:12.107)
[ALS.IN] {"jsonrpc":"2.0","id":3,"method":"shutdown","params":{}} (08:36:12.107)
[ALS.OUT] {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/troy/.emacs.custom/elpaca/repos/ada-ts-mode/test/resources/electric-pair/example.adb","diagnostics":[{"range":{"start":{"line":4,"character":7},"end":{"line":4,"character":11}},"source":"libadalang","message":"Expected ';', got 'loop'"},{"range":{"start":{"line":4,"character":7},"end":{"line":4,"character":11}},"source":"libadalang","message":"Skipped token loop"}]}} (08:36:12.108)
[ALS.OUT] {"jsonrpc":"2.0","id":3,"result":null} (08:36:12.108)
[ALS.IN] {"jsonrpc":"2.0","method":"exit","params":{}} (08:36:12.108)
[ALS.MAIN] Notification decoding failed: (08:36:12.108)
[ALS.MAIN] {"jsonrpc":"2.0","method":"exit","params":{}} (08:36:12.108)Other VS Code Extensions
No response
Additional context
No response