diff options
author | Mathias Fußenegger <mfussenegger@users.noreply.github.com> | 2022-04-30 17:23:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-30 17:23:50 +0200 |
commit | 88411613e23bd829088f48983f0253f1b7e5c3fd (patch) | |
tree | 20b651ac4c5adf9bec31ea6c1cfb81fd3b768c1a | |
parent | 338b9032194a4bc4c98439eb00f65a8ec86609f2 (diff) | |
download | rneovim-88411613e23bd829088f48983f0253f1b7e5c3fd.tar.gz rneovim-88411613e23bd829088f48983f0253f1b7e5c3fd.tar.bz2 rneovim-88411613e23bd829088f48983f0253f1b7e5c3fd.zip |
feat(lsp): add async option to vim.lsp.buf.format (#18322)
Deprecates the existing `vim.lsp.buf.formatting` function.
With this, `vim.lsp.buf.format` will replace all three:
- vim.lsp.buf.formatting
- vim.lsp.buf.formatting_sync
- vim.lsp.buf.formatting_seq_sync
-rw-r--r-- | runtime/doc/lsp.txt | 8 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 44 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 44 |
3 files changed, 83 insertions, 13 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index d5ee959c36..f55c959a03 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1060,9 +1060,8 @@ format({options}) *vim.lsp.buf.format()* See also: ~ https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting • timeout_ms (integer|nil, default 1000): Time in - milliseconds to block for formatting requests. - Formatting requests are current synchronous to prevent - editing of the buffer. + milliseconds to block for formatting requests. No effect + if async=true • bufnr (number|nil): Restrict formatting to the clients attached to the given buffer, defaults to the current buffer (0). @@ -1081,6 +1080,9 @@ format({options}) *vim.lsp.buf.format()* end } < + • async boolean|nil If true the method won't block. + Defaults to false. Editing the buffer while formatting + asynchronous can lead to unexpected changes. • id (number|nil): Restrict formatting to the client with ID (client.id) matching this field. • name (string|nil): Restrict formatting to the client diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 59682e8a0a..aabafc422f 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -152,8 +152,7 @@ end --- automatically derived from the current Neovim options. --- @see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting --- - timeout_ms (integer|nil, default 1000): ---- Time in milliseconds to block for formatting requests. Formatting requests are current ---- synchronous to prevent editing of the buffer. +--- Time in milliseconds to block for formatting requests. No effect if async=true --- - bufnr (number|nil): --- Restrict formatting to the clients attached to the given buffer, defaults to the current --- buffer (0). @@ -174,6 +173,11 @@ end --- } --- </pre> --- +--- - async boolean|nil +--- If true the method won't block. Defaults to false. +--- Editing the buffer while formatting asynchronous can lead to unexpected +--- changes. +--- --- - id (number|nil): --- Restrict formatting to the client with ID (client.id) matching this field. --- - name (string|nil): @@ -207,14 +211,30 @@ function M.format(options) vim.notify("[LSP] Format request failed, no matching language servers.") end - local timeout_ms = options.timeout_ms or 1000 - for _, client in pairs(clients) do - local params = util.make_formatting_params(options.formatting_options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) - if result and result.result then - util.apply_text_edits(result.result, bufnr, client.offset_encoding) - elseif err then - vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + if options.async then + local do_format + do_format = function(idx, client) + if not client then + return + end + local params = util.make_formatting_params(options.formatting_options) + client.request("textDocument/formatting", params, function(...) + local handler = client.handlers['textDocument/formatting'] or vim.lsp.handlers['textDocument/formatting'] + handler(...) + do_format(next(clients, idx)) + end, bufnr) + end + do_format(next(clients)) + else + local timeout_ms = options.timeout_ms or 1000 + for _, client in pairs(clients) do + local params = util.make_formatting_params(options.formatting_options) + local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) + if result and result.result then + util.apply_text_edits(result.result, bufnr, client.offset_encoding) + elseif err then + vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + end end end end @@ -227,6 +247,10 @@ end -- ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting function M.formatting(options) + vim.notify_once( + 'vim.lsp.buf.formatting is deprecated. Use vim.lsp.buf.format { async = true } instead', + vim.log.levels.WARN + ) local params = util.make_formatting_params(options) local bufnr = vim.api.nvim_get_current_buf() select_client('textDocument/formatting', function(client) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 6e28946cc4..be717cf724 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2833,5 +2833,49 @@ describe('LSP', function() end, } end) + it('Can format async', function() + local expected_handlers = { + {NIL, {}, {method="shutdown", client_id=1}}; + {NIL, {}, {method="start", client_id=1}}; + } + local client + test_rpc_server { + test_name = "basic_formatting", + on_init = function(c) + client = c + end, + on_handler = function(_, _, ctx) + table.remove(expected_handlers) + if ctx.method == "start" then + local result = exec_lua([[ + local bufnr = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + + local notify_msg + local notify = vim.notify + vim.notify = function(msg, log_level) + notify_msg = msg + end + + local handler = vim.lsp.handlers['textDocument/formatting'] + local handler_called = false + vim.lsp.handlers['textDocument/formatting'] = function(...) + handler_called = true + end + + vim.lsp.buf.format({ bufnr = bufnr, async = true }) + vim.wait(1000, function() return handler_called end) + + vim.notify = notify + vim.lsp.handlers['textDocument/formatting'] = handler + return {notify = notify_msg, handler_called = handler_called} + ]]) + eq({handler_called=true}, result) + elseif ctx.method == "shutdown" then + client.stop() + end + end, + } + end) end) end) |