fix: preserve list-element indentation in onTypeFormatting - #1327
Conversation
When pressing Enter after a block-sequence item, the onTypeFormatting handler returned an unconditional "- " at params.position, dropping the sequence indentation and placing the dash at column 0 (invalid YAML). It also ignored whitespace the client had already auto-inserted on the line, stamping the dash *before* those existing spaces. This is the LSP-spec-correct behavior to expect: the server advertises documentOnTypeFormattingProvider with firstTriggerCharacter "\n", and DocumentOnTypeFormattingParams explicitly notes that position is "not necessarily the exact position where the character denoted by the property ch got typed" and that a client "could auto insert characters as well" (e.g. automatic indentation/brace completion). A compliant client like lsp-mode sends the request with the line already carrying client-side indentation, so the edit must merge with it rather than overwrite it. Rewrite the block-sequence branch to derive the sequence indentation from the preceding line and insert only the missing text after whatever whitespace already exists on the line: - empty line -> insert "indentation + '- '" (dash aligned with the preceding item's dash) - already-correct line -> no-op - line shorter than expected -> insert the missing suffix after existing spaces (handles client-side auto-indent, e.g. lsp-mode) - line longer than expected -> delete the excess Verified live in Emacs with lsp-mode: the stock 1.24.0 server produced a dash at column 0, while the fixed server leaves the line correctly indented with the dash in place. Co-authored-by: OpenCode Agent <opencode-agent[bot]@users.noreply.github.com>
|
I can't replicate this is in VS Code, and it seems that Helix doesn't support format on type. I couldn't seem to get lsp-mode working in Emacs to test this out (I'm trying out Spacemacs to do this). |
|
It might be easier to reproduce with eglot, just use a minimal Then start with e.g. It should install the The option PS: I couldn't reproduce it in VS Code either, but I logged the server interactions that VS Code makes and it never even used onTypeFormatting. So I presume they switch that feature off there for YAML just like I did by hand in Emacs? The extension I tested it with is PPS: Spacemacs will probably have added dozens of packages that might already turn this feature off. The blank configuration above uses an unconfigured Emacs with just eglot on board. Eglot should react appropriately and set PPPS: I can also reproduce it in Neovim. It's wrong in a different way there, Here's a short demo of the problem in Emacs with an otherwise blank configuration: Screencast_20260831_192914.webm |
Thanks! I was able to replicate the failure that way. I'll test this out now. |
|
This doesn't seem to fix it? This is what I have after this change: 2026-09-01.11-28-28.mp4(this is the same behaviour as before this change) |
|
Oh, yours look like it behaves in a different way now, instead of inserting I will see if I can find the cause and if not I'll proxy this back to the LLM (sorry). |
ebcc7ed to
0efc870
Compare
|
I made another attempt that should fix that behavior by replacing the whole line. This now works for me reliably using eglot and lsp-mode. However, I also observe that other editors (e.g. Kate, Neovim) simply switch off I'm willing to believe the LLM that the feature is supposed to be used when it's advertised, and that it works as it should now, but I don't know enough about this to judge for sure. So if this is too flaky to merge, I can close it and just use my patched server or disable |
|
It's still not working for me. I double checked that emacs+eglot was actually picking up my local copy of I'm willing to believe that the |
|
Thanks for testing again, I can't explain why it doesn't work, I've now cloned the whole thing on a second machine and even a different OS (macOS in this case) and it seems to work for me: Screen.Recording.2026-09-02.at.07.38.37.movBut with the whole cursor placement differences (that other editors also suffer from) I think there might be too much inexplicable magic involved here to chase this any further. I'd be happy to drop this and just switch off on-type formatting, and sorry for taking up your time. Unless someone with more knowledge volunteers to push it further, of course :) I'm leaving my fork open in case it's useful. |
This PR fixes wrong indentation of list items when pressing enter in an existing list, having
onTypeFormattingenabled.The onTypeFormatting handler currently returns an unconditional "- " at params.position, dropping the sequence indentation and placing the dash at column 0 (invalid YAML).
It also ignores whitespace the client had already auto-inserted on the line, putting the dash before those existing spaces.
This is the LSP-spec-correct behavior to expect: the server advertises documentOnTypeFormattingProvider with firstTriggerCharacter "\n", and DocumentOnTypeFormattingParams explicitly notes that position is "not necessarily the exact position where the character denoted by the property ch got typed" and that a client "could auto insert characters as well" (e.g. automatic indentation/brace completion). A compliant client like lsp-mode or eglot sends the request with the line already carrying client-side indentation, so the edit must merge with it rather than overwrite it.
Verified live in Emacs with lsp-mode: the stock 1.24.0 server produced a dash at column 0, while the fixed server leaves the line correctly indented with the dash in place.
What does this PR do?
Changes the behavior of onTypeFormatting to insert list items in the correct location and align the server with LSP spec.
When pressing Enter after a block-sequence item, the server's
onTypeFormattinghandler returns an edit that drops the sequence indentation, producing an invalid dash at column 0. Example (cursor at end of the last line, hit Enter):What issues does this PR fix or reference?
Fixes wrong indentation:
Expected: the new item is aligned with the existing
-(dash at the same column as the preceding item):LSP spec
The handler is invoked because this server advertises the capability:
Advertising the capability is an explicit invitation for clients to delegate newline formatting to the server, so it is expected that a spec-compliant client will call the server on Enter.
DocumentOnTypeFormattingParams.positionis explicitly not guaranteed to be where the dash should land:The fix therefore computes the target
indentation + '- 'from the preceding item and inserts only the missing text after whatever whitespace already exists on the line, rather than assumingposition= insertion point.No issues in this project, but I reported the symptoms of this (perhaps erroneously) on Emacs' lsp-mode: emacs-lsp/lsp-mode#5112
Is it tested? How?
Tested via a live Emacs client, connecting to 1.24.0 and this patched server to observe the correct/wrong behavior.
The behavior occurs both with lsp-mode and with eglot.
Also automated tests are included.
LLM note
I am just a meat proxy/flesh goblin but I put Opencode's Big Pickle through its paces and tried to double and triple-verify that this is indeed the correct behavior according to spec. However, I don't know a thing about LSP server implementations so there could be a whale-sized problem here I'm not seeing.
What I know is that emacs lsp-mode behaves properly with this patched server and VS Code is unaffected because it never seems to make any use of this functionality.
DCO note
As far as I know, the legal standing of LLM code and its licensing has never been decided in any court of law, so it's also unclear if this contribution can adhere to the DCO.