mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 12:27:24 +00:00
feat(lsp): add range option to lsp.buf.format (#19998)
This commit is contained in:
committed by
GitHub
parent
8c59d7e6a7
commit
11167ab6d5
@@ -150,6 +150,33 @@ local function select_client(method, on_choice)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@return table {start={row, col}, end={row, col}} using (1, 0) indexing
|
||||
local function range_from_selection()
|
||||
-- TODO: Use `vim.region()` instead https://github.com/neovim/neovim/pull/13896
|
||||
|
||||
-- [bufnum, lnum, col, off]; both row and column 1-indexed
|
||||
local start = vim.fn.getpos('v')
|
||||
local end_ = vim.fn.getpos('.')
|
||||
local start_row = start[2]
|
||||
local start_col = start[3]
|
||||
local end_row = end_[2]
|
||||
local end_col = end_[3]
|
||||
|
||||
-- A user can start visual selection at the end and move backwards
|
||||
-- Normalize the range to start < end
|
||||
if start_row == end_row and end_col < start_col then
|
||||
end_col, start_col = start_col, end_col
|
||||
elseif end_row < start_row then
|
||||
start_row, end_row = end_row, start_row
|
||||
start_col, end_col = end_col, start_col
|
||||
end
|
||||
return {
|
||||
['start'] = { start_row, start_col - 1 },
|
||||
['end'] = { end_row, end_col - 1 },
|
||||
}
|
||||
end
|
||||
|
||||
--- Formats a buffer using the attached (and optionally filtered) language
|
||||
--- server clients.
|
||||
---
|
||||
@@ -184,7 +211,12 @@ end
|
||||
--- Restrict formatting to the client with ID (client.id) matching this field.
|
||||
--- - name (string|nil):
|
||||
--- Restrict formatting to the client with name (client.name) matching this field.
|
||||
|
||||
---
|
||||
--- - range (table|nil) Range to format.
|
||||
--- Table must contain `start` and `end` keys with {row, col} tuples using
|
||||
--- (1,0) indexing.
|
||||
--- Defaults to current selection in visual mode
|
||||
--- Defaults to `nil` in other modes, formatting the full buffer
|
||||
function M.format(options)
|
||||
options = options or {}
|
||||
local bufnr = options.bufnr or api.nvim_get_current_buf()
|
||||
@@ -206,16 +238,32 @@ function M.format(options)
|
||||
vim.notify('[LSP] Format request failed, no matching language servers.')
|
||||
end
|
||||
|
||||
local mode = api.nvim_get_mode().mode
|
||||
local range = options.range
|
||||
if not range and mode == 'v' or mode == 'V' then
|
||||
range = range_from_selection()
|
||||
end
|
||||
|
||||
---@private
|
||||
local function set_range(client, params)
|
||||
if range then
|
||||
local range_params =
|
||||
util.make_given_range_params(range.start, range['end'], bufnr, client.offset_encoding)
|
||||
params.range = range_params.range
|
||||
end
|
||||
return params
|
||||
end
|
||||
|
||||
local method = range and 'textDocument/rangeFormatting' or 'textDocument/formatting'
|
||||
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']
|
||||
local params = set_range(client, util.make_formatting_params(options.formatting_options))
|
||||
client.request(method, params, function(...)
|
||||
local handler = client.handlers[method] or vim.lsp.handlers[method]
|
||||
handler(...)
|
||||
do_format(next(clients, idx))
|
||||
end, bufnr)
|
||||
@@ -224,8 +272,8 @@ function M.format(options)
|
||||
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)
|
||||
local params = set_range(client, util.make_formatting_params(options.formatting_options))
|
||||
local result, err = client.request_sync(method, params, timeout_ms, bufnr)
|
||||
if result and result.result then
|
||||
util.apply_text_edits(result.result, bufnr, client.offset_encoding)
|
||||
elseif err then
|
||||
@@ -356,6 +404,7 @@ end
|
||||
---@param end_pos ({number, number}, optional) mark-indexed position.
|
||||
---Defaults to the end of the last visual selection.
|
||||
function M.range_formatting(options, start_pos, end_pos)
|
||||
vim.deprecate('vim.lsp.buf.range_formatting', 'vim.lsp.formatexpr or vim.lsp.format', '0.9.0')
|
||||
local params = util.make_given_range_params(start_pos, end_pos)
|
||||
params.options = util.make_formatting_params(options).options
|
||||
select_client('textDocument/rangeFormatting', function(client)
|
||||
@@ -885,23 +934,8 @@ function M.code_action(options)
|
||||
local end_ = assert(options.range['end'], 'range must have a `end` property')
|
||||
params = util.make_given_range_params(start, end_)
|
||||
elseif mode == 'v' or mode == 'V' then
|
||||
-- [bufnum, lnum, col, off]; both row and column 1-indexed
|
||||
local start = vim.fn.getpos('v')
|
||||
local end_ = vim.fn.getpos('.')
|
||||
local start_row = start[2]
|
||||
local start_col = start[3]
|
||||
local end_row = end_[2]
|
||||
local end_col = end_[3]
|
||||
|
||||
-- A user can start visual selection at the end and move backwards
|
||||
-- Normalize the range to start < end
|
||||
if start_row == end_row and end_col < start_col then
|
||||
end_col, start_col = start_col, end_col
|
||||
elseif end_row < start_row then
|
||||
start_row, end_row = end_row, start_row
|
||||
start_col, end_col = end_col, start_col
|
||||
end
|
||||
params = util.make_given_range_params({ start_row, start_col - 1 }, { end_row, end_col - 1 })
|
||||
local range = range_from_selection()
|
||||
params = util.make_given_range_params(range.start, range['end'])
|
||||
else
|
||||
params = util.make_range_params()
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user