aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Fußenegger <mfussenegger@users.noreply.github.com>2022-04-30 17:23:50 +0200
committerGitHub <noreply@github.com>2022-04-30 17:23:50 +0200
commit88411613e23bd829088f48983f0253f1b7e5c3fd (patch)
tree20b651ac4c5adf9bec31ea6c1cfb81fd3b768c1a
parent338b9032194a4bc4c98439eb00f65a8ec86609f2 (diff)
downloadrneovim-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.txt8
-rw-r--r--runtime/lua/vim/lsp/buf.lua44
-rw-r--r--test/functional/plugin/lsp_spec.lua44
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)