diff options
author | Mathias Fußenegger <mfussenegger@users.noreply.github.com> | 2022-09-08 11:33:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-08 11:33:04 +0200 |
commit | 11167ab6d569994dd0a4f58155c84b118706380c (patch) | |
tree | e0e4b1bac8ce4c454c9914c7924e71a205259500 /runtime/lua/vim/lsp/buf.lua | |
parent | 8c59d7e6a719b4d8e14441e6ba9e551bd84ed3d1 (diff) | |
download | rneovim-11167ab6d569994dd0a4f58155c84b118706380c.tar.gz rneovim-11167ab6d569994dd0a4f58155c84b118706380c.tar.bz2 rneovim-11167ab6d569994dd0a4f58155c84b118706380c.zip |
feat(lsp): add range option to lsp.buf.format (#19998)
Diffstat (limited to 'runtime/lua/vim/lsp/buf.lua')
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 82 |
1 files changed, 58 insertions, 24 deletions
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 6a070928d9..2ce565e1d9 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -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 |