aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/autoload/remote/define.vim6
-rw-r--r--runtime/doc/api.txt36
-rw-r--r--runtime/doc/autocmd.txt4
-rw-r--r--runtime/doc/diagnostic.txt2
-rw-r--r--runtime/doc/lsp.txt89
-rw-r--r--runtime/doc/options.txt10
-rw-r--r--runtime/doc/treesitter.txt14
-rw-r--r--runtime/doc/vim_diff.txt1
-rw-r--r--runtime/filetype.vim9
-rw-r--r--runtime/lua/vim/lsp.lua6
-rw-r--r--runtime/lua/vim/lsp/handlers.lua4
-rw-r--r--runtime/lua/vim/lsp/util.lua209
-rw-r--r--runtime/lua/vim/treesitter/query.lua38
13 files changed, 310 insertions, 118 deletions
diff --git a/runtime/autoload/remote/define.vim b/runtime/autoload/remote/define.vim
index 2aec96e365..82e5164d85 100644
--- a/runtime/autoload/remote/define.vim
+++ b/runtime/autoload/remote/define.vim
@@ -240,7 +240,11 @@ function! s:GetAutocmdPrefix(name, opts)
endif
if has_key(a:opts, 'nested') && a:opts.nested
- call add(rv, 'nested')
+ call add(rv, '++nested')
+ endif
+
+ if has_key(a:opts, 'once') && a:opts.once
+ call add(rv, '++once')
endif
return join(rv, ' ')
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index d2d010882e..8fb6290e50 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1018,7 +1018,7 @@ nvim_get_mode() *nvim_get_mode()*
{fast}
nvim_get_option({name}) *nvim_get_option()*
- Gets an option value string.
+ Gets the global value of an option.
Parameters: ~
{name} Option name
@@ -1049,6 +1049,24 @@ nvim_get_option_info({name}) *nvim_get_option_info()*
Return: ~
Option Information
+nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()*
+ Gets the value of an option. The behavior of this function
+ matches that of |:set|: the local value of an option is
+ returned if it exists; otherwise, the global value is
+ returned. Local values always correspond to the current buffer
+ or window. To get a buffer-local or window-local option for a
+ specific buffer or window, use |nvim_buf_get_option()| or
+ |nvim_win_get_option()|.
+
+ Parameters: ~
+ {name} Option name
+ {opts} Optional parameters
+ • scope: One of 'global' or 'local'. Analagous to
+ |:setglobal| and |:setlocal|, respectively.
+
+ Return: ~
+ Option value
+
nvim_get_proc({pid}) *nvim_get_proc()*
Gets info describing process `pid` .
@@ -1510,11 +1528,25 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
key is an error.
nvim_set_option({name}, {value}) *nvim_set_option()*
- Sets an option value.
+ Sets the global value of an option.
+
+ Parameters: ~
+ {name} Option name
+ {value} New option value
+
+ *nvim_set_option_value()*
+nvim_set_option_value({name}, {value}, {*opts})
+ Sets the value of an option. The behavior of this function
+ matches that of |:set|: for global-local options, both the
+ global and local value are set unless otherwise specified with
+ {scope}.
Parameters: ~
{name} Option name
{value} New option value
+ {opts} Optional parameters
+ • scope: One of 'global' or 'local'. Analagous to
+ |:setglobal| and |:setlocal|, respectively.
nvim_set_var({name}, {value}) *nvim_set_var()*
Sets a global (g:) variable.
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 879a34bcaa..242631d98c 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -824,6 +824,10 @@ RemoteReply When a reply from a Vim that functions as
Note that even if an autocommand is defined,
the reply should be read with |remote_read()|
to consume it.
+ *SearchWrapped*
+SearchWrapped After making a search with |n| or |N| if the
+ search wraps around the document back to
+ the start/finish respectively.
*SessionLoadPost*
SessionLoadPost After loading the session file created using
the |:mksession| command.
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index d02510a829..0893f1f343 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -41,6 +41,7 @@ requires a namespace.
*diagnostic-structure*
A diagnostic is a Lua table with the following keys:
+ bufnr: Buffer number
lnum: The starting line of the diagnostic
end_lnum: The final line of the diagnostic
col: The starting column of the diagnostic
@@ -48,6 +49,7 @@ A diagnostic is a Lua table with the following keys:
severity: The severity of the diagnostic |vim.diagnostic.severity|
message: The diagnostic text
source: The source of the diagnostic
+ user_data: Arbitrary data plugins or users can add
Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based
rows and columns). |api-indexing|
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 11f9d62e69..3793a21f36 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -630,6 +630,12 @@ client() *vim.lsp.client*
server.
• {handlers} (table): The handlers used by the client as
described in |lsp-handler|.
+ • {requests} (table): The current pending requests in flight
+ to the server. Entries are key-value pairs with the key
+ being the request ID while the value is a table with
+ `type` , `bufnr` , and `method` key-value pairs. `type` is
+ either "pending" for an active request, or "cancel" for a
+ cancel request.
• {config} (table): copy of the table that was passed by the
user to |vim.lsp.start_client()|.
• {server_capabilities} (table): Response from the server
@@ -1326,12 +1332,14 @@ apply_text_document_edit({text_document_edit}, {index})
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
*vim.lsp.util.apply_text_edits()*
-apply_text_edits({text_edits}, {bufnr})
+apply_text_edits({text_edits}, {bufnr}, {offset_encoding})
Applies a list of text edits to a buffer.
Parameters: ~
- {text_edits} table list of `TextEdit` objects
- {bufnr} number Buffer id
+ {text_edits} table list of `TextEdit` objects
+ {bufnr} number Buffer id
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to encoding of first client of `bufnr`
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
@@ -1358,37 +1366,30 @@ buf_highlight_references({bufnr}, {references}, {offset_encoding})
{references} table List of `DocumentHighlight`
objects to highlight
{offset_encoding} string One of "utf-8", "utf-16",
- "utf-32", or nil. Defaults to utf-16
+ "utf-32", or nil. Defaults to
+ `offset_encoding` of first client of
+ `bufnr`
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight
*vim.lsp.util.character_offset()*
-character_offset({bufnr}, {row}, {col})
+character_offset({buf}, {row}, {col}, {offset_encoding})
Returns the UTF-32 and UTF-16 offsets for a position in a
certain buffer.
Parameters: ~
- {buf} buffer id (0 for current)
- {row} 0-indexed line
- {col} 0-indexed byte offset in line
+ {buf} buffer id (0 for current)
+ {row} 0-indexed line
+ {col} 0-indexed byte offset in line
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ `buf`
Return: ~
- (number, number) UTF-32 and UTF-16 index of the character
+ (number, number) `offset_encoding` index of the character
in line {row} column {col} in buffer {buf}
- *vim.lsp.util.close_preview_autocmd()*
-close_preview_autocmd({events}, {winnr})
- Creates autocommands to close a preview window when events
- happen.
-
- Parameters: ~
- {events} (table) list of events
- {winnr} (number) window id of preview window
-
- See also: ~
- |autocmd-events|
-
*vim.lsp.util.convert_input_to_markdown_lines()*
convert_input_to_markdown_lines({input}, {contents})
Converts any of `MarkedString` | `MarkedString[]` |
@@ -1528,47 +1529,73 @@ make_formatting_params({options})
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
*vim.lsp.util.make_given_range_params()*
-make_given_range_params({start_pos}, {end_pos})
+make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
Using the given range in the current buffer, creates an object
that is similar to |vim.lsp.util.make_range_params()|.
Parameters: ~
- {start_pos} ({number, number}, optional) mark-indexed
- position. Defaults to the start of the last
- visual selection.
- {end_pos} ({number, number}, optional) mark-indexed
- position. Defaults to the end of the last
- visual selection.
+ {start_pos} ({number, number}, optional)
+ mark-indexed position. Defaults to the
+ start of the last visual selection.
+ {end_pos} ({number, number}, optional)
+ mark-indexed position. Defaults to the
+ end of the last visual selection.
+ {bufnr} (optional, number): buffer handle or 0
+ for current, defaults to current
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ `bufnr`
Return: ~
{ textDocument = { uri = `current_file_uri` }, range = {
start = `start_position` , end = `end_position` } }
-make_position_params() *vim.lsp.util.make_position_params()*
+ *vim.lsp.util.make_position_params()*
+make_position_params({window}, {offset_encoding})
Creates a `TextDocumentPositionParams` object for the current
buffer and cursor position.
+ Parameters: ~
+ {window} (optional, number): window handle or 0
+ for current, defaults to current
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ buffer of `window`
+
Return: ~
`TextDocumentPositionParams` object
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
-make_range_params() *vim.lsp.util.make_range_params()*
+ *vim.lsp.util.make_range_params()*
+make_range_params({window}, {offset_encoding})
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` .
+ Parameters: ~
+ {window} (optional, number): window handle or 0
+ for current, defaults to current
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ buffer of `window`
+
Return: ~
{ textDocument = { uri = `current_file_uri` }, range = {
start = `current_position` , end = `current_position` } }
-make_text_document_params() *vim.lsp.util.make_text_document_params()*
+ *vim.lsp.util.make_text_document_params()*
+make_text_document_params({bufnr})
Creates a `TextDocumentIdentifier` object for the current
buffer.
+ Parameters: ~
+ {bufnr} (optional, number): Buffer handle, defaults to
+ current
+
Return: ~
`TextDocumentIdentifier`
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 47633c750c..097cd38400 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3229,10 +3229,14 @@ A jump table for the options with a short description can be found at |Q_op|.
'inccommand' 'icm' string (default "nosplit")
global
- "nosplit": Shows the effects of a command incrementally, as you type.
- "split" : Also shows partial off-screen results in a preview window.
+ When nonempty, shows the effects of |:substitute|, |:smagic|, and
+ |:snomagic| as you type.
- Works for |:substitute|, |:smagic|, |:snomagic|. |hl-Substitute|
+ Possible values:
+ nosplit Shows the effects of a command incrementally in the
+ buffer.
+ split Like "nosplit", but also shows partial off-screen
+ results in a preview window.
If the preview is too slow (exceeds 'redrawtime') then 'inccommand' is
automatically disabled until |Command-line-mode| is done.
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 08dc0583ac..8f7241dd46 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -421,9 +421,9 @@ get_node_text({node}, {source}) *get_node_text()*
Gets the text corresponding to a given node
Parameters: ~
- {node} the node
- {bsource} The buffer or string from which the node is
- extracted
+ {node} the node
+ {source} The buffer or string from which the node is
+ extracted
get_query({lang}, {query_name}) *get_query()*
Returns the runtime query {query_name} for {lang}.
@@ -530,11 +530,9 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop})
for id, node in pairs(match) do
local name = query.captures[id]
-- `node` was captured by the `name` capture in the match
-<
->
- local node_data = metadata[id] -- Node level metadata
-<
->
+
+ local node_data = metadata[id] -- Node level metadata
+
... use the info here ...
end
end
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 956cb3e624..bc59ea785e 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -180,6 +180,7 @@ Commands:
|:match| can be invoked before highlight group is defined
Events:
+ |SearchWrapped|
|Signal|
|TabNewEntered|
|TermClose|
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 3e57ae7f0f..806748b7cb 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -256,7 +256,7 @@ au BufNewFile,BufRead *.lpc,*.ulpc setf lpc
au BufNewFile,BufRead calendar setf calendar
" C#
-au BufNewFile,BufRead *.cs setf cs
+au BufNewFile,BufRead *.cs,*.csx setf cs
" CSDL
au BufNewFile,BufRead *.csdl setf csdl
@@ -786,6 +786,10 @@ au BufNewFile,BufRead *.hb setf hb
" Httest
au BufNewFile,BufRead *.htt,*.htb setf httest
+" i3 (and sway)
+au BufNewFile,BufRead */i3/config,*/sway/config setf i3config
+au BufNewFile,BufRead */.i3/config,*/.sway/config setf i3config
+
" Icon
au BufNewFile,BufRead *.icn setf icon
@@ -1735,6 +1739,9 @@ au BufNewFile,BufRead *.speedup,*.spdata,*.spd setf spup
" Slice
au BufNewFile,BufRead *.ice setf slice
+" Microsoft Visual Studio Solution
+au BufNewFile,BufRead *.sln setf solution
+
" Spice
au BufNewFile,BufRead *.sp,*.spice setf spice
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 95bc4635b0..72a84dcc53 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1493,11 +1493,7 @@ local function adjust_start_col(lnum, line, items, encoding)
end
end
if min_start_char then
- if encoding == 'utf-8' then
- return min_start_char
- else
- return vim.str_byteindex(line, min_start_char, encoding == 'utf-16')
- end
+ return util._str_byteindex_enc(line, min_start_char, encoding)
else
return nil
end
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 22089aaaa6..c974d1a6b4 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -285,7 +285,7 @@ local function location_handler(_, result, ctx, _)
util.jump_to_location(result[1])
if #result > 1 then
- util.set_qflist(util.locations_to_items(result))
+ vim.fn.setqflist({}, ' ', {title = 'LSP locations', items = util.locations_to_items(result)})
api.nvim_command("copen")
end
else
@@ -379,7 +379,7 @@ local make_call_hierarchy_handler = function(direction)
})
end
end
- util.set_qflist(items)
+ vim.fn.setqflist({}, ' ', {title = 'LSP call hierarchy', items = items})
api.nvim_command("copen")
end
end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index a3a91a34f7..68a030d50b 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -90,6 +90,42 @@ local function split_lines(value)
return split(value, '\n', true)
end
+--- Convert byte index to `encoding` index.
+--- Convenience wrapper around vim.str_utfindex
+---@param line string line to be indexed
+---@param index number byte index (utf-8), or `nil` for length
+---@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
+---@return number `encoding` index of `index` in `line`
+function M._str_utfindex_enc(line, index, encoding)
+ if encoding ~= 'utf-8' then
+ local col32, col16 = vim.str_utfindex(line, index)
+ if encoding == 'utf-32' then
+ return col32
+ else
+ return col16
+ end
+ else
+ return index
+ end
+end
+
+--- Convert UTF index to `encoding` index.
+--- Convenience wrapper around vim.str_byteindex
+---Alternative to vim.str_byteindex that takes an encoding.
+---@param line string line to be indexed
+---@param index number UTF index
+---@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
+---@return number byte (utf-8) index of `encoding` index `index` in `line`
+function M._str_byteindex_enc(line, index, encoding)
+ if encoding ~= 'utf-8' then
+ return vim.str_byteindex(line, index, not encoding or encoding ~= 'utf-32')
+ else
+ return index
+ end
+end
+
+local _str_utfindex_enc = M._str_utfindex_enc
+local _str_byteindex_enc = M._str_byteindex_enc
--- Replaces text in a range with new text.
---
--- CAUTION: Changes in-place!
@@ -237,6 +273,7 @@ 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
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
--- 1-indexed
local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- LSP's line and characters are 0-indexed
@@ -247,13 +284,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
if col > 0 then
local line = get_line(bufnr, position.line)
local ok, result
-
- if offset_encoding == "utf-16" or not offset_encoding then
- ok, result = pcall(vim.str_byteindex, line, col, true)
- elseif offset_encoding == "utf-32" then
- ok, result = pcall(vim.str_byteindex, line, col, false)
- end
-
+ ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding)
if ok then
return result
end
@@ -325,12 +356,15 @@ end
--- Applies a list of text edits to a buffer.
---@param text_edits table list of `TextEdit` objects
---@param bufnr number Buffer id
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to encoding of first client of `bufnr`
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
-function M.apply_text_edits(text_edits, bufnr)
+function M.apply_text_edits(text_edits, bufnr, offset_encoding)
validate {
text_edits = { text_edits, 't', false };
bufnr = { bufnr, 'number', false };
+ offset_encoding = { offset_encoding, 'string', true };
}
+ offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
if not next(text_edits) then return end
if not api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
@@ -367,8 +401,7 @@ function M.apply_text_edits(text_edits, bufnr)
-- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here.
local has_eol_text_edit = false
local max = vim.api.nvim_buf_line_count(bufnr)
- -- TODO handle offset_encoding
- local _, len = vim.str_utfindex(vim.api.nvim_buf_get_lines(bufnr, -2, -1, false)[1] or '')
+ local len = _str_utfindex_enc(vim.api.nvim_buf_get_lines(bufnr, -2, -1, false)[1] or '', nil, offset_encoding)
text_edits = vim.tbl_map(function(text_edit)
if max <= text_edit.range.start.line then
text_edit.range.start.line = max - 1
@@ -1220,17 +1253,57 @@ function M.stylize_markdown(bufnr, contents, opts)
return stripped
end
+---@private
--- Creates autocommands to close a preview window when events happen.
---
----@param events (table) list of events
----@param winnr (number) window id of preview window
+---@param events table list of events
+---@param winnr number window id of preview window
+---@param bufnrs table list of buffers where the preview window will remain visible
---@see |autocmd-events|
-function M.close_preview_autocmd(events, winnr)
+local function close_preview_autocmd(events, winnr, bufnrs)
+ local augroup = 'preview_window_'..winnr
+
+ -- close the preview window when entered a buffer that is not
+ -- the floating window buffer or the buffer that spawned it
+ vim.cmd(string.format([[
+ augroup %s
+ autocmd!
+ autocmd BufEnter * lua vim.lsp.util._close_preview_window(%d, {%s})
+ augroup end
+ ]], augroup, winnr, table.concat(bufnrs, ',')))
+
if #events > 0 then
- api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
+ vim.cmd(string.format([[
+ augroup %s
+ autocmd %s <buffer> lua vim.lsp.util._close_preview_window(%d)
+ augroup end
+ ]], augroup, table.concat(events, ','), winnr))
end
end
+---@private
+--- Closes the preview window
+---
+---@param winnr number window id of preview window
+---@param bufnrs table|nil optional list of ignored buffers
+function M._close_preview_window(winnr, bufnrs)
+ vim.schedule(function()
+ -- exit if we are in one of ignored buffers
+ if bufnrs and vim.tbl_contains(bufnrs, api.nvim_get_current_buf()) then
+ return
+ end
+
+ local augroup = 'preview_window_'..winnr
+ vim.cmd(string.format([[
+ augroup %s
+ autocmd!
+ augroup end
+ augroup! %s
+ ]], augroup, augroup))
+ pcall(vim.api.nvim_win_close, winnr, true)
+ end)
+end
+
---@internal
--- Computes size of float needed to show contents (with optional wrapping)
---
@@ -1337,7 +1410,7 @@ function M.open_floating_preview(contents, syntax, opts)
opts.wrap = opts.wrap ~= false -- wrapping by default
opts.stylize_markdown = opts.stylize_markdown ~= false
opts.focus = opts.focus ~= false
- opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"}
+ opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "InsertCharPre"}
local bufnr = api.nvim_get_current_buf()
@@ -1406,7 +1479,7 @@ function M.open_floating_preview(contents, syntax, opts)
api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
api.nvim_buf_set_keymap(floating_bufnr, "n", "q", "<cmd>bdelete<cr>", {silent = true, noremap = true, nowait = true})
- M.close_preview_autocmd(opts.close_events, floating_winnr)
+ close_preview_autocmd(opts.close_events, floating_winnr, {floating_bufnr, bufnr})
-- save focus_id
if opts.focus_id then
@@ -1432,11 +1505,11 @@ do --[[ References ]]
---
---@param bufnr number Buffer id
---@param references table List of `DocumentHighlight` objects to highlight
- ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32", or nil. Defaults to utf-16
+ ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32", or nil. Defaults to `offset_encoding` of first client of `bufnr`
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight
function M.buf_highlight_references(bufnr, references, offset_encoding)
validate { bufnr = {bufnr, 'n', true} }
- offset_encoding = offset_encoding or 'utf-16'
+ offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
for _, reference in ipairs(references) do
local start_line, start_char = reference["range"]["start"]["line"], reference["range"]["start"]["character"]
local end_line, end_char = reference["range"]["end"]["line"], reference["range"]["end"]["character"]
@@ -1649,43 +1722,78 @@ function M.try_trim_markdown_code_blocks(lines)
return 'markdown'
end
-local str_utfindex = vim.str_utfindex
---@private
-local function make_position_param()
- local row, col = unpack(api.nvim_win_get_cursor(0))
+---@param window (optional, number): window handle or 0 for current, defaults to current
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
+local function make_position_param(window, offset_encoding)
+ window = window or 0
+ local buf = vim.api.nvim_win_get_buf(window)
+ local row, col = unpack(api.nvim_win_get_cursor(window))
+ offset_encoding = offset_encoding or M._get_offset_encoding(buf)
row = row - 1
- local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
+ local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
if not line then
return { line = 0; character = 0; }
end
- -- TODO handle offset_encoding
- local _
- _, col = str_utfindex(line, col)
+
+ col = _str_utfindex_enc(line, col, offset_encoding)
+
return { line = row; character = col; }
end
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
---
+---@param window (optional, number): window handle or 0 for current, defaults to current
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
---@returns `TextDocumentPositionParams` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
-function M.make_position_params()
+function M.make_position_params(window, offset_encoding)
+ window = window or 0
+ local buf = vim.api.nvim_win_get_buf(window)
+ offset_encoding = offset_encoding or M._get_offset_encoding(buf)
return {
- textDocument = M.make_text_document_params();
- position = make_position_param()
+ textDocument = M.make_text_document_params(buf);
+ position = make_position_param(window, offset_encoding)
}
end
+--- Utility function for getting the encoding of the first LSP client on the given buffer.
+---@param bufnr (number) buffer handle or 0 for current, defaults to current
+---@returns (string) encoding first client if there is one, nil otherwise
+function M._get_offset_encoding(bufnr)
+ validate {
+ bufnr = {bufnr, 'n', true};
+ }
+
+ local offset_encoding
+
+ for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do
+ local this_offset_encoding = client.offset_encoding or "utf-16"
+ if not offset_encoding then
+ offset_encoding = this_offset_encoding
+ elseif offset_encoding ~= this_offset_encoding then
+ vim.notify("warning: multiple different client offset_encodings detected for buffer, this is not supported yet", vim.log.levels.WARN)
+ end
+ end
+
+ return offset_encoding
+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`.
---
+---@param window (optional, number): window handle or 0 for current, defaults to current
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
---`current_position`, end = `current_position` } }
-function M.make_range_params()
- local position = make_position_param()
+function M.make_range_params(window, offset_encoding)
+ local buf = vim.api.nvim_win_get_buf(window)
+ offset_encoding = offset_encoding or M._get_offset_encoding(buf)
+ local position = make_position_param(window, offset_encoding)
return {
- textDocument = M.make_text_document_params(),
+ textDocument = M.make_text_document_params(buf),
range = { start = position; ["end"] = position; }
}
end
@@ -1697,27 +1805,29 @@ end
---Defaults to the start of the last visual selection.
---@param end_pos ({number, number}, optional) mark-indexed position.
---Defaults to the end of the last visual selection.
+---@param bufnr (optional, number): buffer handle or 0 for current, defaults to current
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of `bufnr`
---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
---`start_position`, end = `end_position` } }
-function M.make_given_range_params(start_pos, end_pos)
+function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
validate {
start_pos = {start_pos, 't', true};
end_pos = {end_pos, 't', true};
+ offset_encoding = {offset_encoding, 's', true};
}
- local A = list_extend({}, start_pos or api.nvim_buf_get_mark(0, '<'))
- local B = list_extend({}, end_pos or api.nvim_buf_get_mark(0, '>'))
+ bufnr = bufnr or 0
+ offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
+ local A = list_extend({}, start_pos or api.nvim_buf_get_mark(bufnr, '<'))
+ local B = list_extend({}, end_pos or api.nvim_buf_get_mark(bufnr, '>'))
-- convert to 0-index
A[1] = A[1] - 1
B[1] = B[1] - 1
- -- account for encoding.
- -- TODO handle offset_encoding
+ -- account for offset_encoding.
if A[2] > 0 then
- local _, char = M.character_offset(0, A[1], A[2])
- A = {A[1], char}
+ A = {A[1], M.character_offset(bufnr, A[1], A[2], offset_encoding)}
end
if B[2] > 0 then
- local _, char = M.character_offset(0, B[1], B[2])
- B = {B[1], char}
+ B = {B[1], M.character_offset(bufnr, B[1], B[2], offset_encoding)}
end
-- we need to offset the end character position otherwise we loose the last
-- character of the selection, as LSP end position is exclusive
@@ -1726,7 +1836,7 @@ function M.make_given_range_params(start_pos, end_pos)
B[2] = B[2] + 1
end
return {
- textDocument = M.make_text_document_params(),
+ textDocument = M.make_text_document_params(bufnr),
range = {
start = {line = A[1], character = A[2]},
['end'] = {line = B[1], character = B[2]}
@@ -1736,10 +1846,11 @@ end
--- Creates a `TextDocumentIdentifier` object for the current buffer.
---
+---@param bufnr (optional, number): Buffer handle, defaults to current
---@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) }
+function M.make_text_document_params(bufnr)
+ return { uri = vim.uri_from_bufnr(bufnr or 0) }
end
--- Create the workspace params
@@ -1782,14 +1893,16 @@ end
---@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(bufnr, row, col)
- local line = get_line(bufnr, row)
+---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of `buf`
+---@returns (number, number) `offset_encoding` index of the character in line {row} column {col} in buffer {buf}
+function M.character_offset(buf, row, col, offset_encoding)
+ local line = get_line(buf, row)
+ offset_encoding = offset_encoding or M._get_offset_encoding(buf)
-- If the col is past the EOL, use the line length.
if col > #line then
- return str_utfindex(line)
+ return _str_utfindex_enc(line, nil, offset_encoding)
end
- return str_utfindex(line, col)
+ return _str_utfindex_enc(line, col, offset_encoding)
end
--- Helper function to return nested values in language server settings
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index b8255e61ed..ebed502c92 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -164,22 +164,36 @@ function M.parse_query(lang, query)
return self
end
--- TODO(vigoux): support multiline nodes too
-
--- Gets the text corresponding to a given node
---
---@param node the node
----@param bsource The buffer or string from which the node is extracted
+---@param source The buffer or string from which the node is extracted
function M.get_node_text(node, source)
local start_row, start_col, start_byte = node:start()
local end_row, end_col, end_byte = node:end_()
if type(source) == "number" then
- if start_row ~= end_row then
+ local lines
+ local eof_row = a.nvim_buf_line_count(source)
+ if start_row >= eof_row then
return nil
end
- local line = a.nvim_buf_get_lines(source, start_row, start_row+1, true)[1]
- return string.sub(line, start_col+1, end_col)
+
+ if end_col == 0 then
+ lines = a.nvim_buf_get_lines(source, start_row, end_row, true)
+ end_col = -1
+ else
+ lines = a.nvim_buf_get_lines(source, start_row, end_row + 1, true)
+ end
+
+ if #lines == 1 then
+ lines[1] = string.sub(lines[1], start_col+1, end_col)
+ else
+ lines[1] = string.sub(lines[1], start_col+1)
+ lines[#lines] = string.sub(lines[#lines], 1, end_col)
+ end
+
+ return table.concat(lines, "\n")
elseif type(source) == "string" then
return source:sub(start_byte+1, end_byte)
end
@@ -211,11 +225,6 @@ local predicate_handlers = {
["lua-match?"] = function(match, _, source, predicate)
local node = match[predicate[2]]
local regex = predicate[3]
- local start_row, _, end_row, _ = node:range()
- if start_row ~= end_row then
- return false
- end
-
return string.find(M.get_node_text(node, source), regex)
end,
@@ -239,13 +248,8 @@ local predicate_handlers = {
return function(match, _, source, pred)
local node = match[pred[2]]
- local start_row, start_col, end_row, end_col = node:range()
- if start_row ~= end_row then
- return false
- end
-
local regex = compiled_vim_regexes[pred[3]]
- return regex:match_line(source, start_row, start_col, end_col)
+ return regex:match_str(M.get_node_text(node, source))
end
end)(),