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
This commit is contained in:
Mathias Fußenegger
2022-04-30 17:23:50 +02:00
committed by GitHub
parent 338b903219
commit 88411613e2
3 changed files with 83 additions and 13 deletions

View File

@@ -1060,9 +1060,8 @@ format({options}) *vim.lsp.buf.format()*
See also: ~ See also: ~
https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
• timeout_ms (integer|nil, default 1000): Time in • timeout_ms (integer|nil, default 1000): Time in
milliseconds to block for formatting requests. milliseconds to block for formatting requests. No effect
Formatting requests are current synchronous to prevent if async=true
editing of the buffer.
• bufnr (number|nil): Restrict formatting to the clients • bufnr (number|nil): Restrict formatting to the clients
attached to the given buffer, defaults to the current attached to the given buffer, defaults to the current
buffer (0). buffer (0).
@@ -1081,6 +1080,9 @@ format({options}) *vim.lsp.buf.format()*
end 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 (number|nil): Restrict formatting to the client with
ID (client.id) matching this field. ID (client.id) matching this field.
• name (string|nil): Restrict formatting to the client • name (string|nil): Restrict formatting to the client

View File

@@ -152,8 +152,7 @@ end
--- automatically derived from the current Neovim options. --- automatically derived from the current Neovim options.
--- @see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting --- @see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
--- - timeout_ms (integer|nil, default 1000): --- - timeout_ms (integer|nil, default 1000):
--- Time in milliseconds to block for formatting requests. Formatting requests are current --- Time in milliseconds to block for formatting requests. No effect if async=true
--- synchronous to prevent editing of the buffer.
--- - bufnr (number|nil): --- - bufnr (number|nil):
--- Restrict formatting to the clients attached to the given buffer, defaults to the current --- Restrict formatting to the clients attached to the given buffer, defaults to the current
--- buffer (0). --- buffer (0).
@@ -174,6 +173,11 @@ end
--- } --- }
--- </pre> --- </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): --- - id (number|nil):
--- Restrict formatting to the client with ID (client.id) matching this field. --- Restrict formatting to the client with ID (client.id) matching this field.
--- - name (string|nil): --- - name (string|nil):
@@ -207,6 +211,21 @@ function M.format(options)
vim.notify("[LSP] Format request failed, no matching language servers.") vim.notify("[LSP] Format request failed, no matching language servers.")
end end
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 local timeout_ms = options.timeout_ms or 1000
for _, client in pairs(clients) do for _, client in pairs(clients) do
local params = util.make_formatting_params(options.formatting_options) local params = util.make_formatting_params(options.formatting_options)
@@ -218,6 +237,7 @@ function M.format(options)
end end
end end
end end
end
--- Formats the current buffer. --- Formats the current buffer.
--- ---
@@ -227,6 +247,10 @@ end
-- --
---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
function M.formatting(options) 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 params = util.make_formatting_params(options)
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
select_client('textDocument/formatting', function(client) select_client('textDocument/formatting', function(client)

View File

@@ -2833,5 +2833,49 @@ describe('LSP', function()
end, end,
} }
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)
end) end)