aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/util.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/lsp/util.lua')
-rw-r--r--runtime/lua/vim/lsp/util.lua308
1 files changed, 240 insertions, 68 deletions
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 33fca29ecd..7e94de7ec3 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -7,6 +7,7 @@ local highlight = require 'vim.highlight'
local M = {}
+-- FIXME: Expose in documentation
--- Diagnostics received from the server via `textDocument/publishDiagnostics`
-- by buffer.
--
@@ -33,18 +34,30 @@ local M = {}
M.diagnostics_by_buf = {}
local split = vim.split
+--@private
local function split_lines(value)
return split(value, '\n', true)
end
+--@private
local function ok_or_nil(status, ...)
if not status then return end
return ...
end
+--@private
local function npcall(fn, ...)
return ok_or_nil(pcall(fn, ...))
end
+--- Replaces text in a range with new text.
+---
+--- CAUTION: Changes in-place!
+---
+--@param lines (table) Original list of strings
+--@param A (table) Start position; a 2-tuple of {line, col} numbers
+--@param B (table) End position; a 2-tuple of {line, col} numbers
+--@param new_lines A list of strings to replace the original
+--@returns (table) The modified {lines} object
function M.set_lines(lines, A, B, new_lines)
-- 0-indexing to 1-indexing
local i_0 = A[1] + 1
@@ -78,6 +91,7 @@ function M.set_lines(lines, A, B, new_lines)
return lines
end
+--@private
local function sort_by_key(fn)
return function(a,b)
local ka, kb = fn(a), fn(b)
@@ -91,13 +105,15 @@ local function sort_by_key(fn)
return false
end
end
+--@private
local edit_sort_key = sort_by_key(function(e)
return {e.A[1], e.A[2], e.i}
end)
+--@private
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
--- Returns a zero-indexed column, since set_lines() does the conversion to
--- 1-indexed
+--- Returns a zero-indexed column, since set_lines() does the conversion to
+--- 1-indexed
local function get_line_byte_from_position(bufnr, position)
-- LSP's line and characters are 0-indexed
-- Vim's line and columns are 1-indexed
@@ -114,6 +130,9 @@ local function get_line_byte_from_position(bufnr, position)
return col
end
+--- Applies a list of text edits to a buffer.
+--@param text_edits (table) list of `TextEdit` objects
+--@param buf_nr (number) Buffer id
function M.apply_text_edits(text_edits, bufnr)
if not next(text_edits) then return end
if not api.nvim_buf_is_loaded(bufnr) then
@@ -168,20 +187,30 @@ end
-- function M.glob_to_regex(glob)
-- end
--- textDocument/completion response returns one of CompletionItem[], CompletionList or null.
--- https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
+--- Can be used to extract the completion items from a
+--- `textDocument/completion` request, which may return one of
+--- `CompletionItem[]`, `CompletionList` or null.
+--@param result (table) The result of a `textDocument/completion` request
+--@returns (table) List of completion items
+--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
function M.extract_completion_items(result)
if type(result) == 'table' and result.items then
+ -- result is a `CompletionList`
return result.items
elseif result ~= nil then
+ -- result is `CompletionItem[]`
return result
else
+ -- result is `null`
return {}
end
end
---- Apply the TextDocumentEdit response.
--- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification
+--- Applies a `TextDocumentEdit`, which is a list of changes to a single
+-- document.
+---
+--@param text_document_edit (table) a `TextDocumentEdit` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit)
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
@@ -195,6 +224,13 @@ function M.apply_text_document_edit(text_document_edit)
M.apply_text_edits(text_document_edit.edits, bufnr)
end
+--@private
+--- Recursively parses snippets in a completion entry.
+---
+--@param input (string) Snippet text to parse for snippets
+--@param inner (bool) Whether this function is being called recursively
+--@returns 2-tuple of strings: The first is the parsed result, the second is the
+---unparsed rest of the input
local function parse_snippet_rec(input, inner)
local res = ""
@@ -248,15 +284,20 @@ local function parse_snippet_rec(input, inner)
return res, input
end
--- Parse completion entries, consuming snippet tokens
+--- Parses snippets in a completion entry.
+---
+--@param input (string) unparsed snippet
+--@returns (string) parsed snippet
function M.parse_snippet(input)
local res, _ = parse_snippet_rec(input, false)
return res
end
--- Sort by CompletionItem.sortText
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--@private
+--- Sorts by CompletionItem.sortText.
+---
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function sort_completion_items(items)
if items[1] and items[1].sortText then
table.sort(items, function(a, b) return a.sortText < b.sortText
@@ -264,9 +305,10 @@ local function sort_completion_items(items)
end
end
--- Returns text that should be inserted when selecting completion item. The precedence is as follows:
--- textEdit.newText > insertText > label
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--@private
+--- Returns text that should be inserted when selecting completion item. The
+--- precedence is as follows: textEdit.newText > insertText > label
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function get_completion_word(item)
if item.textEdit ~= nil and item.textEdit.newText ~= nil then
if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
@@ -284,8 +326,10 @@ local function get_completion_word(item)
return item.label
end
--- Some language servers return complementary candidates whose prefixes do not match are also returned.
--- So we exclude completion candidates whose prefix does not match.
+--@private
+--- Some language servers return complementary candidates whose prefixes do not
+--- match are also returned. So we exclude completion candidates whose prefix
+--- does not match.
local function remove_unmatch_completion_items(items, prefix)
return vim.tbl_filter(function(item)
local word = get_completion_word(item)
@@ -293,16 +337,26 @@ local function remove_unmatch_completion_items(items, prefix)
end, items)
end
--- Acording to LSP spec, if the client set "completionItemKind.valueSet",
--- the client must handle it properly even if it receives a value outside the specification.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--- Acording to LSP spec, if the client set `completionItemKind.valueSet`,
+--- the client must handle it properly even if it receives a value outside the
+--- specification.
+---
+--@param completion_item_kind (`vim.lsp.protocol.completionItemKind`)
+--@returns (`vim.lsp.protocol.completionItemKind`)
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
function M._get_completion_item_kind_name(completion_item_kind)
return protocol.CompletionItemKind[completion_item_kind] or "Unknown"
end
---- Getting vim complete-items with incomplete flag.
--- @params CompletionItem[], CompletionList or nil (https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
--- @return { matches = complete-items table, incomplete = boolean }
+--- Turns the result of a `textDocument/completion` request into vim-compatible
+--- |complete-items|.
+---
+--@param result The result of a `textDocument/completion` call, e.g. from
+---|vim.lsp.buf.completion()|, which may be one of `CompletionItem[]`,
+--- `CompletionList` or `null`
+--@param prefix (string) the prefix to filter the completion items
+--@returns { matches = complete-items table, incomplete = bool }
+--@see |complete-items|
function M.text_document_completion_list_to_complete_items(result, prefix)
local items = M.extract_completion_items(result)
if vim.tbl_isempty(items) then
@@ -350,7 +404,10 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
return matches
end
--- @params WorkspaceEdit [table] see https://microsoft.github.io/language-server-protocol/specification
+--- Applies a `WorkspaceEdit`.
+---
+--@param workspace_edit (table) `WorkspaceEdit`
+-- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit)
if workspace_edit.documentChanges then
for _, change in ipairs(workspace_edit.documentChanges) do
@@ -375,9 +432,15 @@ function M.apply_workspace_edit(workspace_edit)
end
end
---- Convert any of MarkedString | MarkedString[] | MarkupContent into markdown text lines
--- see https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_hover
--- Useful for textDocument/hover, textDocument/signatureHelp, and potentially others.
+--- Converts any of `MarkedString` | `MarkedString[]` | `MarkupContent` into
+--- a list of lines containing valid markdown. Useful to populate the hover
+--- window for `textDocument/hover`, for parsing the result of
+--- `textDocument/signatureHelp`, and potentially others.
+---
+--@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
+--@param contents (table, optional, default `{}`) List of strings to extend with converted lines
+--@returns {contents}, extended with lines of converted markdown.
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
-- MarkedString variation 1
@@ -416,8 +479,11 @@ function M.convert_input_to_markdown_lines(input, contents)
return contents
end
---- Convert SignatureHelp response to markdown lines.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
+--- Converts `textDocument/SignatureHelp` response to markdown lines.
+---
+--@param signature_help Response of `textDocument/SignatureHelp`
+--@returns list of lines of converted markdown.
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help)
if not signature_help.signatures then
return
@@ -475,6 +541,13 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
return contents
end
+--- Creates a table with sensible default options for a floating window. The
+--- table can be passed to |nvim_open_win()|.
+---
+--@param width (number) window width (in character cells)
+--@param height (number) window height (in character cells)
+--@param opts (table, optional)
+--@returns (table) Options
function M.make_floating_popup_options(width, height, opts)
validate {
opts = { opts, 't', true };
@@ -520,6 +593,10 @@ function M.make_floating_popup_options(width, height, opts)
}
end
+--- Jumps to a location.
+---
+--@param location (`Location`|`LocationLink`)
+--@returns `true` if the jump succeeded
function M.jump_to_location(location)
-- location may be Location or LocationLink
local uri = location.uri or location.targetUri
@@ -543,14 +620,14 @@ function M.jump_to_location(location)
return true
end
---- Preview a location in a floating windows
+--- Previews a location in a floating window
---
--- behavior depends on type of location:
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
---@param location a single Location or LocationLink
---@return bufnr,winnr buffer and window number of floating window or nil
+--@param location a single `Location` or `LocationLink`
+--@returns (bufnr,winnr) buffer and window number of floating window or nil
function M.preview_location(location)
-- location may be LocationLink or Location (more useful for the former)
local uri = location.targetUri or location.uri
@@ -565,6 +642,7 @@ function M.preview_location(location)
return M.open_floating_preview(contents, filetype)
end
+--@private
local function find_window_by_var(name, value)
for _, win in ipairs(api.nvim_list_wins()) do
if npcall(api.nvim_win_get_var, win, name) == value then
@@ -573,12 +651,18 @@ local function find_window_by_var(name, value)
end
end
--- Check if a window with `unique_name` tagged is associated with the current
--- buffer. If not, make a new preview.
---
--- fn()'s return bufnr, winnr
--- case that a new floating window should be created.
+--- Enters/leaves the focusable window associated with the current buffer via the
+--window - variable `unique_name`. If no such window exists, run the function
+--{fn}.
+---
+--@param unique_name (string) Window variable
+--@param fn (function) should return create a new window and return a tuple of
+---({focusable_buffer_id}, {window_id}). if {focusable_buffer_id} is a valid
+---buffer id, the newly created window will be the new focus associated with
+---the current buffer via the tag `unique_name`.
+--@returns (pbufnr, pwinnr) if `fn()` has created a new window; nil otherwise
function M.focusable_float(unique_name, fn)
+ -- Go back to previous window if we are in a focusable one
if npcall(api.nvim_win_get_var, 0, unique_name) then
return api.nvim_command("wincmd p")
end
@@ -598,18 +682,21 @@ function M.focusable_float(unique_name, fn)
end
end
--- Check if a window with `unique_name` tagged is associated with the current
--- buffer. If not, make a new preview.
---
--- fn()'s return values will be passed directly to open_floating_preview in the
--- case that a new floating window should be created.
+--- Focuses/unfocuses the floating preview window associated with the current
+--- buffer via the window variable `unique_name`. If no such preview window
+--- exists, makes a new one.
+---
+--@param unique_name (string) Window variable
+--@param fn (function) The return values of this function will be passed
+---directly to |vim.lsp.util.open_floating_preview()|, in the case that a new
+---floating window should be created
function M.focusable_preview(unique_name, fn)
return M.focusable_float(unique_name, function()
return M.open_floating_preview(fn())
end)
end
---- Trim empty lines from input and pad left and right with spaces
+--- Trims empty lines from input and pad left and right with spaces
---
--@param contents table of lines to trim and pad
--@param opts dictionary with optional fields
@@ -617,7 +704,7 @@ end
-- - pad_right number of columns to pad contents at right (default 1)
-- - pad_top number of lines to pad contents at top (default 0)
-- - pad_bottom number of lines to pad contents at bottom (default 0)
---@return contents table of trimmed and padded lines
+--@returns contents table of trimmed and padded lines
function M._trim_and_pad(contents, opts)
validate {
contents = { contents, 't' };
@@ -645,12 +732,13 @@ end
---- Convert markdown into syntax highlighted regions by stripping the code
+-- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+--
+--- Converts markdown into syntax highlighted regions by stripping the code
--- blocks and converting them into highlighted code.
--- This will by default insert a blank line separator after those code block
--- regions to improve readability.
---- The result is shown in a floating preview
---- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+--- The result is shown in a floating preview.
---
--@param contents table of lines to show in window
--@param opts dictionary with optional fields
@@ -664,7 +752,7 @@ end
-- - pad_top number of lines to pad contents at top
-- - pad_bottom number of lines to pad contents at bottom
-- - separator insert separator after code block
---@return width,height size of float
+--@returns width,height size of float
function M.fancy_floating_markdown(contents, opts)
validate {
contents = { contents, 't' };
@@ -738,6 +826,7 @@ function M.fancy_floating_markdown(contents, opts)
vim.cmd("ownsyntax markdown")
local idx = 1
+ --@private
local function apply_syntax_to_region(ft, start, finish)
if ft == '' then return end
local name = ft..idx
@@ -763,11 +852,17 @@ function M.fancy_floating_markdown(contents, opts)
return bufnr, winnr
end
+--- Creates autocommands to close a preview window when events happen.
+---
+--@param events (table) list of events
+--@param winnr (number) window id of preview window
+--@see |autocmd-events|
function M.close_preview_autocmd(events, winnr)
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
end
---- Compute size of float needed to show contents (with optional wrapping)
+--@internal
+--- Computes size of float needed to show contents (with optional wrapping)
---
--@param contents table of lines to show in window
--@param opts dictionary with optional fields
@@ -776,7 +871,7 @@ end
-- - wrap_at character to wrap at for computing height
-- - max_width maximal width of floating window
-- - max_height maximal height of floating window
---@return width,height size of float
+--@returns width,height size of float
function M._make_floating_popup_size(contents, opts)
validate {
contents = { contents, 't' };
@@ -827,7 +922,7 @@ function M._make_floating_popup_size(contents, opts)
return width, height
end
---- Show contents in a floating window
+--- Shows contents in a floating window.
---
--@param contents table of lines to show in window
--@param filetype string of filetype to set for opened buffer
@@ -841,7 +936,8 @@ end
-- - pad_right number of columns to pad contents at right
-- - pad_top number of lines to pad contents at top
-- - pad_bottom number of lines to pad contents at bottom
---@return bufnr,winnr buffer and window number of floating window or nil
+--@returns bufnr,winnr buffer and window number of the newly created floating
+---preview window
function M.open_floating_preview(contents, filetype, opts)
validate {
contents = { contents, 't' };
@@ -912,6 +1008,9 @@ do
severity_floating_highlights[severity] = floating_highlight_name
end
+ --- Clears diagnostics for a buffer.
+ ---
+ --@param bufnr (number) buffer id
function M.buf_clear_diagnostics(bufnr)
validate { bufnr = {bufnr, 'n', true} }
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
@@ -923,10 +1022,18 @@ do
api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
end
+ --- Gets the name of a severity's highlight group.
+ ---
+ --@param severity A member of `vim.lsp.protocol.DiagnosticSeverity`
+ --@returns (string) Highlight group name
function M.get_severity_highlight_name(severity)
return severity_highlights[severity]
end
+ --- Gets list of diagnostics for the current line.
+ ---
+ --@returns (table) list of `Diagnostic` tables
+ --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
function M.get_line_diagnostics()
local bufnr = api.nvim_get_current_buf()
local linenr = api.nvim_win_get_cursor(0)[1] - 1
@@ -941,6 +1048,8 @@ do
return diagnostics_by_line[linenr] or {}
end
+ --- Displays the diagnostics for the current line in a floating hover
+ --- window.
function M.show_line_diagnostics()
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
-- if #marks == 0 then
@@ -977,10 +1086,10 @@ do
return popup_bufnr, winnr
end
- --- Saves the diagnostics (Diagnostic[]) into diagnostics_by_buf
+ --- Saves diagnostics into vim.lsp.util.diagnostics_by_buf[{bufnr}].
---
- --@param bufnr bufnr for which the diagnostics are for.
- --@param diagnostics Diagnostics[] received from the language server.
+ --@param bufnr (number) buffer id for which the diagnostics are for
+ --@param diagnostics list of `Diagnostic`s received from the LSP server
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
validate {
bufnr = {bufnr, 'n', true};
@@ -1000,6 +1109,10 @@ do
M.diagnostics_by_buf[bufnr] = diagnostics
end
+ --- Highlights a list of diagnostics in a buffer by underlining them.
+ ---
+ --@param bufnr (number) buffer id
+ --@param diagnostics (list of `Diagnostic`s)
function M.buf_diagnostics_underline(bufnr, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range["start"]
@@ -1020,11 +1133,18 @@ do
end
end
+ --- Removes document highlights from a buffer.
+ ---
+ --@param bufnr buffer id
function M.buf_clear_references(bufnr)
validate { bufnr = {bufnr, 'n', true} }
api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
end
+ --- Shows a list of document highlights for a certain buffer.
+ ---
+ --@param bufnr buffer id
+ --@param references List of `DocumentHighlight` objects to highlight
function M.buf_highlight_references(bufnr, references)
validate { bufnr = {bufnr, 'n', true} }
for _, reference in ipairs(references) do
@@ -1040,11 +1160,19 @@ do
end
end
+ --- Groups a list of diagnostics by line.
+ ---
+ --@param diagnostics (table) list of `Diagnostic`s
+ --@returns (table) dictionary mapping lines to lists of diagnostics valid on
+ ---those lines
+ --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
function M.diagnostics_group_by_line(diagnostics)
if not diagnostics then return end
local diagnostics_by_line = {}
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range.start
+ -- TODO: Are diagnostics only valid for a single line? I don't understand
+ -- why this would be okay otherwise
local line_diagnostics = diagnostics_by_line[start.line]
if not line_diagnostics then
line_diagnostics = {}
@@ -1055,6 +1183,11 @@ do
return diagnostics_by_line
end
+ --- Given a list of diagnostics, sets the corresponding virtual text for a
+ --- buffer.
+ ---
+ --@param bufnr buffer id
+ --@param diagnostics (table) list of `Diagnostic`s
function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
if not diagnostics then
return
@@ -1093,8 +1226,7 @@ do
--- </pre>
---
--@param kind Diagnostic severity kind: See |vim.lsp.protocol.DiagnosticSeverity|
- ---
- --@return Count of diagnostics
+ --@returns Count of diagnostics
function M.buf_diagnostics_count(kind)
local bufnr = vim.api.nvim_get_current_buf()
local diagnostics = M.diagnostics_by_buf[bufnr]
@@ -1115,7 +1247,7 @@ do
[protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
}
- --- Place signs for each diagnostic in the sign column.
+ --- Places signs for each diagnostic in the sign column.
---
--- Sign characters can be customized with the following commands:
---
@@ -1136,8 +1268,11 @@ local position_sort = sort_by_key(function(v)
return {v.start.line, v.start.character}
end)
--- Returns the items with the byte position calculated correctly and in sorted
--- order.
+--- Returns the items with the byte position calculated correctly and in sorted
+--- order, for display in quickfix and location lists.
+---
+--@param locations (table) list of `Location`s or `LocationLink`s
+--@returns (table) list of items
function M.locations_to_items(locations)
local items = {}
local grouped = setmetatable({}, {
@@ -1180,6 +1315,10 @@ function M.locations_to_items(locations)
return items
end
+--- Fills current window's location list with given list of items.
+--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
+---
+--@param items (table) list of items
function M.set_loclist(items)
vim.fn.setloclist(0, {}, ' ', {
title = 'Language Server';
@@ -1187,6 +1326,10 @@ function M.set_loclist(items)
})
end
+--- Fills quickfix list with given list of items.
+--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
+---
+--@param items (table) list of items
function M.set_qflist(items)
vim.fn.setqflist({}, ' ', {
title = 'Language Server';
@@ -1201,10 +1344,11 @@ function M._get_symbol_kind_name(symbol_kind)
return protocol.SymbolKind[symbol_kind] or "Unknown"
end
---- Convert symbols to quickfix list items
+--- Converts symbols to quickfix list items.
---
--@param symbols DocumentSymbol[] or SymbolInformation[]
function M.symbols_to_items(symbols, bufnr)
+ --@private
local function _symbols_to_items(_symbols, _items, _bufnr)
for _, symbol in ipairs(_symbols) do
if symbol.location then -- SymbolInformation type
@@ -1239,7 +1383,9 @@ function M.symbols_to_items(symbols, bufnr)
return _symbols_to_items(symbols, {}, bufnr)
end
--- Remove empty lines from the beginning and end.
+--- Removes empty lines from the beginning and end.
+--@param lines (table) list of lines to trim
+--@returns (table) trimmed list of lines
function M.trim_empty_lines(lines)
local start = 1
for i = 1, #lines do
@@ -1258,11 +1404,13 @@ function M.trim_empty_lines(lines)
return vim.list_extend({}, lines, start, finish)
end
--- Accepts markdown lines and tries to reduce it to a filetype if it is
--- just a single code block.
--- Note: This modifies the input.
---
--- Returns: filetype or 'markdown' if it was unchanged.
+--- Accepts markdown lines and tries to reduce them to a filetype if they
+--- comprise just a single code block.
+---
+--- CAUTION: Modifies the input in-place!
+---
+--@param lines (table) list of lines
+--@returns (string) filetype or 'markdown' if it was unchanged.
function M.try_trim_markdown_code_blocks(lines)
local language_id = lines[1]:match("^```(.*)")
if language_id then
@@ -1285,6 +1433,7 @@ function M.try_trim_markdown_code_blocks(lines)
end
local str_utfindex = vim.str_utfindex
+--@private
local function make_position_param()
local row, col = unpack(api.nvim_win_get_cursor(0))
row = row - 1
@@ -1293,6 +1442,10 @@ local function make_position_param()
return { line = row; character = col; }
end
+--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
+---
+--@returns `TextDocumentPositionParams` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params()
return {
textDocument = M.make_text_document_params();
@@ -1300,6 +1453,13 @@ function M.make_position_params()
}
end
+--- Using the current position in the current buffer, creates an object that
+--- can be used as a building block for several LSP requests, such as
+--- `textDocument/codeAction`, `textDocument/colorPresentation`,
+--- `textDocument/rangeFormatting`.
+---
+--@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---`current_position`, end = `current_position` } }
function M.make_range_params()
local position = make_position_param()
return {
@@ -1308,11 +1468,15 @@ function M.make_range_params()
}
end
+--- Creates a `TextDocumentIdentifier` object for the current buffer.
+---
+--@returns `TextDocumentIdentifier`
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params()
return { uri = vim.uri_from_bufnr(0) }
end
---- Get visual width of tabstop.
+--- Returns visual width of tabstop.
---
--@see |softtabstop|
--@param bufnr (optional, number): Buffer handle, defaults to current
@@ -1324,6 +1488,11 @@ function M.get_effective_tabstop(bufnr)
return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop
end
+--- Creates a `FormattingOptions` object for the current buffer and cursor position.
+---
+--@param options Table with valid `FormattingOptions` entries
+--@returns `FormattingOptions object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
validate { options = {options, 't', true} }
options = vim.tbl_extend('keep', options or {}, {
@@ -1336,9 +1505,12 @@ function M.make_formatting_params(options)
}
end
--- @param buf buffer handle or 0 for current.
--- @param row 0-indexed line
--- @param col 0-indexed byte offset in line
+--- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer.
+---
+--@param buf buffer id (0 for current)
+--@param row 0-indexed line
+--@param col 0-indexed byte offset in line
+--@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(buf, row, col)
local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
-- If the col is past the EOL, use the line length.