Similar to Clang Format, it'd be nice to have a setting in the settings (false by default maybe) called "format_on_save" that will apply the "Format Document" action when the view is saved (on_pre_save)
EDIT: Since it's probably an async option you'd have to bake in some way to "wait" for the server to give a response before actually returning from EventListener.on_pre_save. I'll stop thinking about details now.
Thanks for the idea and implementation hints.
Blocking in on_pre_save would let us format before the user's save, but I'm a bit worried about the user experience and error handling in this case.
Perhaps two saves is okay?
on_pre_save_async: request textDocument/formattingview.run_command('save') on_pre_save_async: do nothing because 'no_format' flagHow can you be sure step 4 is executed after step 3? Maybe the server sends back a response before the document is even saved?
Good point, some experimentation is needed!
I see that https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#new-willsavewaituntiltextdocument-request is the intended LSP mechanism for format_on_save
Good point, some experimentation is needed! I see that https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#new-willsavewaituntiltextdocument-request is the intended LSP mechanism for format_on_save
That link is broken, the new documentation for LSP —and more specifically for this method— is here:
https://microsoft.github.io/language-server-protocol/specification#textDocument_willSaveWaitUntil
+1, voting for this. we need format_on_save
I am currently working on a implementation of this. I decided to use a blocking format backed by a timeout. If the timeout expires, it will just save and ignore the formatting. Mostly working, just need to cleanup the code and add some settings so it is not always on with a hard-coded timeout. I also need to implement the willSaveWaitUntil for the language servers that support it, instead of a standard format document command.
You can find what I have so far here: https://github.com/oralordos/LSP
@oralordos looking forward to testing it :)
@oralordos I'm testing your changes with my very barebones server that doesn't handle any text synchronization yet. The only capability it advertises is documentFormattingProvider. In order to do the formatting, it reads the file from disk. That means the file already needs to be saved, otherwise the server would generate text edits for an outdated version.
I don't know if this is a scenario that you actually want to support, but the format-on-save feature doesn't work properly in this case. Then again, neither does the regular LSP: Format Document command from the palette, so I don't know whether this even belongs here, or warrants a separate issue.
To support this scenario, the client could detect it, then listen to on_post_save instead, and save again afterwards. Alternativaly, the client should not only check for the documentFormattingProvider capability, but also textDocumentSync (which defaults to TextDocumentSyncKind.None) in FormatOnSave.on_pre_save.
Having much more experience with LSP now I think what I wanted to expres is that this text editor client should implement textDocument/willSaveWaitUntil, and then a language server should decide what to do with that notification. It could format the document, or it could do something else. Perhaps set via workspace/configuration or initializationOptions or via a plain command-line option.
But I disagree with my past self now in that we should offer a "format on save" option; all we can do is enable willSaveWaitUntil and then let the language server decide.
Some servers (Metals, RLS) rely on the editor (eg. VS Code's editor.formatOnSave feature) to invoke the formatter after willSave. I think few language servers will go the additional effort to implement their own internal willSave->format hook if their biggest customer does it for them.
Gopls even leans on VS Code to run code actions (https://github.com/golang/go/wiki/gopls#vscode) instead of doing it in willSaveWaitUntil.
What do you think of implementing the "format_on_save" feature in LSP by blocking in on_pre_save only (instead of baking blocking into the rpc client) ? Would that work?
Two suggestions from this issue are now implemented:
Running "Format Document" on save is enabled by adding a lsp_format_on_save set to true in your Sublime settings (not LSP Package settings!).
The willSaveWaitUntil request (as used by vscode's eslint server) is always sent by LSP, your server likely has a setting (eg. "autoFixOnSave": true) that enables formatting actions for it.
Most helpful comment
Two suggestions from this issue are now implemented:
Running "Format Document" on save is enabled by adding a
lsp_format_on_saveset totruein your Sublime settings (not LSP Package settings!).The
willSaveWaitUntilrequest (as used by vscode's eslint server) is always sent by LSP, your server likely has a setting (eg."autoFixOnSave": true) that enables formatting actions for it.