From 06347a64cac5e33574713a59ace9d1d0ea4b6f82 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 05:19:46 +0800 Subject: vim-patch:9.1.0443: Can't use blockwise selection with width for getregion() (#28985) Problem: Can't use a blockwise selection with a width for getregion(). Solution: Add support for blockwise selection with width like the return value of getregtype() or the "regtype" value of TextYankPost (zeertzjq). closes: vim/vim#14842 https://github.com/vim/vim/commit/afc2295c2201ae87bfbb42d5f5315ad0583ccabf --- runtime/lua/vim/_meta/vimfn.lua | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index f4daacfb7d..d1455fa993 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3536,14 +3536,13 @@ function vim.fn.getreginfo(regname) end --- The optional argument {opts} is a Dict and supports the --- following items: --- ---- type Specify the region's selection type ---- (default: "v"): ---- "v" for |charwise| mode ---- "V" for |linewise| mode ---- "" for |blockwise-visual| mode +--- type Specify the region's selection type. +--- See |getregtype()| for possible values, +--- except it cannot be an empty string. +--- (default: "v") --- --- exclusive If |TRUE|, use exclusive selection ---- for the end position +--- for the end position. --- (default: follow 'selection') --- --- You can get the last selection type by |visualmode()|. -- cgit From 5d26934c7cda191f0b519c1326fa318b857ffcb8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 24 May 2024 18:31:25 -0500 Subject: feat(lsp): update LSP healthcheck format (#28980) This is mostly an aesthetic change, although there are a few new pieces of information included. Originally I wanted to investigate including server capabilities in the healthcheck, but until we have the ability to fold/unfold text in health checks that would be too much information. --- runtime/lua/vim/lsp/health.lua | 83 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 10 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index a79ae76eb9..b5dc710cc6 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -33,16 +33,22 @@ local function check_active_clients() local clients = vim.lsp.get_clients() if next(clients) then for _, client in pairs(clients) do - local attached_to = table.concat(vim.tbl_keys(client.attached_buffers or {}), ',') - report_info( + local cmd ---@type string + if type(client.config.cmd) == 'table' then + cmd = table.concat(client.config.cmd --[[@as table]], ' ') + elseif type(client.config.cmd) == 'function' then + cmd = tostring(client.config.cmd) + end + report_info(table.concat({ + string.format('%s (id: %d)', client.name, client.id), + string.format(' Root directory: %s', vim.fn.fnamemodify(client.root_dir, ':~')), + string.format(' Command: %s', cmd), + string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })), string.format( - '%s (id=%s, root_dir=%s, attached_to=[%s])', - client.name, - client.id, - vim.fn.fnamemodify(client.root_dir, ':~'), - attached_to - ) - ) + ' Attached buffers: %s', + vim.iter(pairs(client.attached_buffers)):map(tostring):join(', ') + ), + }, '\n')) end else report_info('No active clients') @@ -50,7 +56,7 @@ local function check_active_clients() end local function check_watcher() - vim.health.start('vim.lsp: File watcher') + vim.health.start('vim.lsp: File Watcher') -- Only run the check if file watching has been enabled by a client. local clients = vim.lsp.get_clients() @@ -94,11 +100,68 @@ local function check_watcher() end end +local function check_position_encodings() + vim.health.start('vim.lsp: Position Encodings') + local clients = vim.lsp.get_clients() + if next(clients) then + local position_encodings = {} ---@type table> + for _, client in pairs(clients) do + for bufnr in pairs(client.attached_buffers) do + if not position_encodings[bufnr] then + position_encodings[bufnr] = {} + end + if not position_encodings[bufnr][client.offset_encoding] then + position_encodings[bufnr][client.offset_encoding] = {} + end + table.insert(position_encodings[bufnr][client.offset_encoding], client.id) + end + end + + -- Check if any buffers are attached to multiple clients with different position encodings + local buffers = {} ---@type integer[] + for bufnr, encodings in pairs(position_encodings) do + local list = {} ---@type string[] + for k in pairs(encodings) do + list[#list + 1] = k + end + + if #list > 1 then + buffers[#buffers + 1] = bufnr + end + end + + if #buffers > 0 then + local lines = + { 'Found buffers attached to multiple clients with different position encodings.' } + for _, bufnr in ipairs(buffers) do + local encodings = position_encodings[bufnr] + local parts = {} + for encoding, client_ids in pairs(encodings) do + table.insert( + parts, + string.format('%s (client id(s): %s)', encoding:upper(), table.concat(client_ids, ', ')) + ) + end + table.insert(lines, string.format('- Buffer %d: %s', bufnr, table.concat(parts, ', '))) + end + report_warn( + table.concat(lines, '\n'), + 'Use the positionEncodings client capability to ensure all clients use the same position encoding' + ) + else + report_info('No buffers contain mixed position encodings') + end + else + report_info('No active clients') + end +end + --- Performs a healthcheck for LSP function M.check() check_log() check_active_clients() check_watcher() + check_position_encodings() end return M -- cgit From 8b2b1fba2abfb99186e3a1f0123251a3e2eae3fe Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 3 May 2024 15:53:13 +0800 Subject: fix(float): missing default highlight for title Problem: there is missing default title highlight when highlight not defined in title text chunk. Solution: when attr is not set use default title highlight group. --- runtime/lua/vim/_meta/api.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 64c67be076..ae43863316 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1731,13 +1731,15 @@ function vim.api.nvim_open_term(buffer, opts) end --- --- • title: Title (optional) in window border, string or list. --- List should consist of `[text, highlight]` tuples. If ---- string, the default highlight group is `FloatTitle`. +--- string, or a tuple lacks a highlight, the default +--- highlight group is `FloatTitle`. --- • title_pos: Title position. Must be set with `title` --- option. Value can be one of "left", "center", or "right". --- Default is `"left"`. --- • footer: Footer (optional) in window border, string or --- list. List should consist of `[text, highlight]` tuples. ---- If string, the default highlight group is `FloatFooter`. +--- If string, or a tuple lacks a highlight, the default +--- highlight group is `FloatFooter`. --- • footer_pos: Footer position. Must be set with `footer` --- option. Value can be one of "left", "center", or "right". --- Default is `"left"`. -- cgit From 4757d497f3c85cc343f7dcbc09f95e43ba5c1314 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 16:53:10 +0800 Subject: vim-patch:9.1.0444: Not enough tests for getregion() with multibyte chars (#29000) Problem: Not enough tests for getregion() with multibyte chars. Solution: Add a few more tests (zeertzjq). closes: vim/vim#14844 https://github.com/vim/vim/commit/dff55a335889c746a79974f7c52cdcdebad682c2 --- runtime/lua/vim/_meta/vimfn.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index d1455fa993..f256f63768 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3538,7 +3538,8 @@ function vim.fn.getreginfo(regname) end --- --- type Specify the region's selection type. --- See |getregtype()| for possible values, ---- except it cannot be an empty string. +--- except that the width can be omitted +--- and an empty string cannot be used. --- (default: "v") --- --- exclusive If |TRUE|, use exclusive selection -- cgit From bdb81afab3e5c43a33267666c2689feb284f6b52 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 20:37:33 +0800 Subject: refactor(lua): rewrite vim.highlight.range() (#28986) - Use getregionpos(). - Use a single extmark for non-blockwise selection. --- runtime/lua/vim/highlight.lua | 55 +++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index f278bd357f..89298ce568 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -20,8 +20,8 @@ M.priorities = { --- @class vim.highlight.range.Opts --- @inlinedoc --- ---- Type of range. See [setreg()] ---- (default: `'charwise'`) +--- Type of range. See [getregtype()] +--- (default: `'v'` i.e. charwise) --- @field regtype? string --- --- Indicates whether the range is end-inclusive @@ -49,20 +49,49 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local priority = opts.priority or M.priorities.user local scoped = opts._scoped or false - -- TODO: in case of 'v', 'V' (not block), this should calculate equivalent - -- bounds (row, col, end_row, end_col) as multiline regions are natively - -- supported now - local region = vim.region(bufnr, start, finish, regtype, inclusive) - for linenr, cols in pairs(region) do - local end_row - if cols[2] == -1 then - end_row = linenr + 1 - cols[2] = 0 + local pos1 = type(start) == 'string' and vim.fn.getpos(start) + or { bufnr, start[1] + 1, start[2] + 1, 0 } + local pos2 = type(finish) == 'string' and vim.fn.getpos(finish) + or { bufnr, finish[1] + 1, finish[2] + 1, 0 } + + local buf_line_count = vim.api.nvim_buf_line_count(bufnr) + pos1[2] = math.min(pos1[2], buf_line_count) + pos2[2] = math.min(pos2[2], buf_line_count) + + if pos1[2] <= 0 or pos1[3] <= 0 or pos2[2] <= 0 or pos2[3] <= 0 then + return + end + + vim.api.nvim_buf_call(bufnr, function() + local max_col1 = vim.fn.col({ pos1[2], '$' }) + pos1[3] = math.min(pos1[3], max_col1) + local max_col2 = vim.fn.col({ pos2[2], '$' }) + pos2[3] = math.min(pos2[3], max_col2) + end) + + local region = vim.fn.getregionpos(pos1, pos2, { + type = regtype, + exclusive = not inclusive, + eol = true, + }) + -- For non-blockwise selection, use a single extmark. + if regtype == 'v' or regtype == 'V' then + region = { { region[1][1], region[#region][2] } } + end + + for _, res in ipairs(region) do + local start_row = res[1][2] - 1 + local start_col = res[1][3] - 1 + local end_row = res[2][2] - 1 + local end_col = res[2][3] + if regtype == 'V' then + end_row = end_row + 1 + end_col = 0 end - api.nvim_buf_set_extmark(bufnr, ns, linenr, cols[1], { + api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, { hl_group = higroup, end_row = end_row, - end_col = cols[2], + end_col = end_col, priority = priority, strict = false, scoped = scoped, -- cgit From 520c2657bb6832dc527bff94f313a1cc458238a4 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 17:56:05 +0200 Subject: refactor: move provider-related to where they are used --- runtime/lua/vim/health.lua | 108 -------------------------- runtime/lua/vim/provider/health.lua | 150 ++++++++++++++++++++++++++++++------ 2 files changed, 127 insertions(+), 131 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index f40f04a064..afeba2ee9d 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -275,114 +275,6 @@ function M.error(msg, ...) collect_output(input) end -function M._provider_disabled(provider) - local loaded_var = 'loaded_' .. provider .. '_provider' - local v = vim.g[loaded_var] - if v == 0 then - M.info('Disabled (' .. loaded_var .. '=' .. v .. ').') - return true - end - return false -end - --- Handler for s:system() function. -local function system_handler(self, _, data, event) - if event == 'stderr' then - if self.add_stderr_to_output then - self.output = self.output .. table.concat(data, '') - else - self.stderr = self.stderr .. table.concat(data, '') - end - elseif event == 'stdout' then - self.output = self.output .. table.concat(data, '') - end -end - --- Attempts to construct a shell command from an args list. --- Only for display, to help users debug a failed command. -local function shellify(cmd) - if type(cmd) ~= 'table' then - return cmd - end - local escaped = {} - for i, v in ipairs(cmd) do - if v:match('[^A-Za-z_/.-]') then - escaped[i] = vim.fn.shellescape(v) - else - escaped[i] = v - end - end - return table.concat(escaped, ' ') -end - -function M._cmd_ok(cmd) - local out = vim.fn.system(cmd) - return vim.v.shell_error == 0, out -end - ---- Run a system command and timeout after 30 seconds. ---- ---- @param cmd table List of command arguments to execute ---- @param args? table Optional arguments: ---- - stdin (string): Data to write to the job's stdin ---- - stderr (boolean): Append stderr to stdout ---- - ignore_error (boolean): If true, ignore error output ---- - timeout (number): Number of seconds to wait before timing out (default 30) -function M._system(cmd, args) - args = args or {} - local stdin = args.stdin or '' - local stderr = vim.F.if_nil(args.stderr, false) - local ignore_error = vim.F.if_nil(args.ignore_error, false) - - local shell_error_code = 0 - local opts = { - add_stderr_to_output = stderr, - output = '', - stderr = '', - on_stdout = system_handler, - on_stderr = system_handler, - on_exit = function(_, data) - shell_error_code = data - end, - } - local jobid = vim.fn.jobstart(cmd, opts) - - if jobid < 1 then - local message = - string.format('Command error (job=%d): %s (in %s)', jobid, shellify(cmd), vim.uv.cwd()) - error(message) - return opts.output, 1 - end - - if stdin:find('^%s$') then - vim.fn.chansend(jobid, stdin) - end - - local res = vim.fn.jobwait({ jobid }, vim.F.if_nil(args.timeout, 30) * 1000) - if res[1] == -1 then - error('Command timed out: ' .. shellify(cmd)) - vim.fn.jobstop(jobid) - elseif shell_error_code ~= 0 and not ignore_error then - local emsg = string.format( - 'Command error (job=%d, exit code %d): %s (in %s)', - jobid, - shell_error_code, - shellify(cmd), - vim.uv.cwd() - ) - if opts.output:find('%S') then - emsg = string.format('%s\noutput: %s', emsg, opts.output) - end - if opts.stderr:find('%S') then - emsg = string.format('%s\nstderr: %s', emsg, opts.stderr) - end - error(emsg) - end - - -- return opts.output - return vim.trim(vim.fn.system(cmd)), shell_error_code -end - local path2name = function(path) if path:match('%.lua$') then -- Lua: transform "../lua/vim/lsp/health.lua" into "vim.lsp" diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index 63e0da448a..d6932f651e 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -3,6 +3,112 @@ local iswin = vim.uv.os_uname().sysname == 'Windows_NT' local M = {} +local function cmd_ok(cmd) + local out = vim.fn.system(cmd) + return vim.v.shell_error == 0, out +end + +-- Attempts to construct a shell command from an args list. +-- Only for display, to help users debug a failed command. +local function shellify(cmd) + if type(cmd) ~= 'table' then + return cmd + end + local escaped = {} + for i, v in ipairs(cmd) do + if v:match('[^A-Za-z_/.-]') then + escaped[i] = vim.fn.shellescape(v) + else + escaped[i] = v + end + end + return table.concat(escaped, ' ') +end + +-- Handler for s:system() function. +local function system_handler(self, _, data, event) + if event == 'stderr' then + if self.add_stderr_to_output then + self.output = self.output .. table.concat(data, '') + else + self.stderr = self.stderr .. table.concat(data, '') + end + elseif event == 'stdout' then + self.output = self.output .. table.concat(data, '') + end +end + +--- @param cmd table List of command arguments to execute +--- @param args? table Optional arguments: +--- - stdin (string): Data to write to the job's stdin +--- - stderr (boolean): Append stderr to stdout +--- - ignore_error (boolean): If true, ignore error output +--- - timeout (number): Number of seconds to wait before timing out (default 30) +local function system(cmd, args) + args = args or {} + local stdin = args.stdin or '' + local stderr = vim.F.if_nil(args.stderr, false) + local ignore_error = vim.F.if_nil(args.ignore_error, false) + + local shell_error_code = 0 + local opts = { + add_stderr_to_output = stderr, + output = '', + stderr = '', + on_stdout = system_handler, + on_stderr = system_handler, + on_exit = function(_, data) + shell_error_code = data + end, + } + local jobid = vim.fn.jobstart(cmd, opts) + + if jobid < 1 then + local message = + string.format('Command error (job=%d): %s (in %s)', jobid, shellify(cmd), vim.uv.cwd()) + error(message) + return opts.output, 1 + end + + if stdin:find('^%s$') then + vim.fn.chansend(jobid, stdin) + end + + local res = vim.fn.jobwait({ jobid }, vim.F.if_nil(args.timeout, 30) * 1000) + if res[1] == -1 then + error('Command timed out: ' .. shellify(cmd)) + vim.fn.jobstop(jobid) + elseif shell_error_code ~= 0 and not ignore_error then + local emsg = string.format( + 'Command error (job=%d, exit code %d): %s (in %s)', + jobid, + shell_error_code, + shellify(cmd), + vim.uv.cwd() + ) + if opts.output:find('%S') then + emsg = string.format('%s\noutput: %s', emsg, opts.output) + end + if opts.stderr:find('%S') then + emsg = string.format('%s\nstderr: %s', emsg, opts.stderr) + end + error(emsg) + end + + -- return opts.output + return vim.trim(vim.fn.system(cmd)), shell_error_code +end + +local function provider_disabled(provider) + local loaded_var = 'loaded_' .. provider .. '_provider' + local v = vim.g[loaded_var] + if v == 0 then + health.info('Disabled (' .. loaded_var .. '=' .. v .. ').') + return true + end + return false +end + local function clipboard() health.start('Clipboard (optional)') @@ -10,7 +116,7 @@ local function clipboard() os.getenv('TMUX') and vim.fn.executable('tmux') == 1 and vim.fn.executable('pbpaste') == 1 - and not health._cmd_ok('pbpaste') + and not cmd_ok('pbpaste') then local tmux_version = string.match(vim.fn.system('tmux -V'), '%d+%.%d+') local advice = { @@ -40,7 +146,7 @@ end local function node() health.start('Node.js provider (optional)') - if health._provider_disabled('node') then + if provider_disabled('node') then return end @@ -60,7 +166,7 @@ local function node() end -- local node_v = vim.fn.split(system({'node', '-v'}), "\n")[1] or '' - local ok, node_v = health._cmd_ok({ 'node', '-v' }) + local ok, node_v = cmd_ok({ 'node', '-v' }) health.info('Node.js: ' .. node_v) if not ok or vim.version.lt(node_v, '6.0.0') then health.warn('Nvim node.js host does not support Node ' .. node_v) @@ -97,7 +203,7 @@ local function node() iswin and 'cmd /c ' .. manager .. ' info neovim --json' or manager .. ' info neovim --json' ) local latest_npm - ok, latest_npm = health._cmd_ok(vim.split(latest_npm_cmd, ' ')) + ok, latest_npm = cmd_ok(vim.split(latest_npm_cmd, ' ')) if not ok or latest_npm:find('^%s$') then health.error( 'Failed to run: ' .. latest_npm_cmd, @@ -115,7 +221,7 @@ local function node() local current_npm_cmd = { 'node', host, '--version' } local current_npm - ok, current_npm = health._cmd_ok(current_npm_cmd) + ok, current_npm = cmd_ok(current_npm_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_npm_cmd, ' '), @@ -143,7 +249,7 @@ end local function perl() health.start('Perl provider (optional)') - if health._provider_disabled('perl') then + if provider_disabled('perl') then return end @@ -162,7 +268,7 @@ local function perl() -- we cannot use cpanm that is on the path, as it may not be for the perl -- set with g:perl_host_prog - local ok = health._cmd_ok({ perl_exec, '-W', '-MApp::cpanminus', '-e', '' }) + local ok = cmd_ok({ perl_exec, '-W', '-MApp::cpanminus', '-e', '' }) if not ok then return { perl_exec, '"App::cpanminus" module is not installed' } end @@ -174,7 +280,7 @@ local function perl() 'my $app = App::cpanminus::script->new; $app->parse_options ("--info", "-q", "Neovim::Ext"); exit $app->doit', } local latest_cpan - ok, latest_cpan = health._cmd_ok(latest_cpan_cmd) + ok, latest_cpan = cmd_ok(latest_cpan_cmd) if not ok or latest_cpan:find('^%s*$') then health.error( 'Failed to run: ' .. table.concat(latest_cpan_cmd, ' '), @@ -205,7 +311,7 @@ local function perl() local current_cpan_cmd = { perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION' } local current_cpan - ok, current_cpan = health._cmd_ok(current_cpan_cmd) + ok, current_cpan = cmd_ok(current_cpan_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_cpan_cmd, ' '), @@ -292,7 +398,7 @@ end local function download(url) local has_curl = vim.fn.executable('curl') == 1 if has_curl and vim.fn.system({ 'curl', '-V' }):find('Protocols:.*https') then - local out, rc = health._system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) + local out, rc = system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) if rc ~= 0 then return 'curl error with ' .. url .. ': ' .. rc else @@ -305,7 +411,7 @@ local function download(url) from urllib2 import urlopen\n\ response = urlopen('" .. url .. "')\n\ print(response.read().decode('utf8'))\n" - local out, rc = health._system({ 'python', '-c', script }) + local out, rc = system({ 'python', '-c', script }) if out == '' and rc ~= 0 then return 'python urllib.request error: ' .. rc else @@ -362,7 +468,7 @@ end local function version_info(python) local pypi_version = latest_pypi_version() - local python_version, rc = health._system({ + local python_version, rc = system({ python, '-c', 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))', @@ -373,7 +479,7 @@ local function version_info(python) end local nvim_path - nvim_path, rc = health._system({ + nvim_path, rc = system({ python, '-c', 'import sys; sys.path = [p for p in sys.path if p != ""]; import neovim; print(neovim.__file__)', @@ -398,7 +504,7 @@ local function version_info(python) -- Try to get neovim.VERSION (added in 0.1.11dev). local nvim_version - nvim_version, rc = health._system({ + nvim_version, rc = system({ python, '-c', 'from neovim import VERSION as v; print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))', @@ -445,7 +551,7 @@ local function python() local host_prog_var = pyname .. '_host_prog' local python_multiple = {} - if health._provider_disabled(pyname) then + if provider_disabled(pyname) then return end @@ -487,7 +593,7 @@ local function python() end if pyenv ~= '' then - python_exe = health._system({ pyenv, 'which', pyname }, { stderr = true }) + python_exe = system({ pyenv, 'which', pyname }, { stderr = true }) if python_exe == '' then health.warn('pyenv could not find ' .. pyname .. '.') end @@ -710,9 +816,7 @@ local function python() health.info(msg) health.info( 'Python version: ' - .. health._system( - 'python -c "import platform, sys; sys.stdout.write(platform.python_version())"' - ) + .. system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"') ) health.ok('$VIRTUAL_ENV provides :!python.') end @@ -721,7 +825,7 @@ end local function ruby() health.start('Ruby provider (optional)') - if health._provider_disabled('ruby') then + if provider_disabled('ruby') then return end @@ -732,7 +836,7 @@ local function ruby() ) return end - health.info('Ruby: ' .. health._system({ 'ruby', '-v' })) + health.info('Ruby: ' .. system({ 'ruby', '-v' })) local host, _ = vim.provider.ruby.detect() if (not host) or host:find('^%s*$') then @@ -748,7 +852,7 @@ local function ruby() health.info('Host: ' .. host) local latest_gem_cmd = (iswin and 'cmd /c gem list -ra "^^neovim$"' or 'gem list -ra ^neovim$') - local ok, latest_gem = health._cmd_ok(vim.split(latest_gem_cmd, ' ')) + local ok, latest_gem = cmd_ok(vim.split(latest_gem_cmd, ' ')) if not ok or latest_gem:find('^%s*$') then health.error( 'Failed to run: ' .. latest_gem_cmd, @@ -761,7 +865,7 @@ local function ruby() local current_gem_cmd = { host, '--version' } local current_gem - ok, current_gem = health._cmd_ok(current_gem_cmd) + ok, current_gem = cmd_ok(current_gem_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_gem_cmd, ' '), -- cgit From f03b1622ad1b8e2df16504631f05e7577e217854 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 25 May 2024 21:22:41 +0200 Subject: fix(lsp): handle nil root_dir in health check (#29007) The root directory could show up as something like: Root directory: ~/path/to/cwd/v:null Despite being `nil` --- runtime/lua/vim/lsp/client.lua | 3 +-- runtime/lua/vim/lsp/health.lua | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 4beb7fefda..58ea7d02b3 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -182,7 +182,7 @@ local validate = vim.validate --- It can be `null` if the client supports workspace folders but none are --- configured. --- @field workspace_folders lsp.WorkspaceFolder[]? ---- @field root_dir string +--- @field root_dir string? --- --- @field attached_buffers table --- @@ -470,7 +470,6 @@ function Client.create(config) _on_exit_cbs = ensure_list(config.on_exit), _on_attach_cbs = ensure_list(config.on_attach), _on_error_cb = config.on_error, - _root_dir = config.root_dir, _trace = get_trace(config.trace), --- Contains $/progress report messages. diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index b5dc710cc6..ffe595ab37 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -41,7 +41,10 @@ local function check_active_clients() end report_info(table.concat({ string.format('%s (id: %d)', client.name, client.id), - string.format(' Root directory: %s', vim.fn.fnamemodify(client.root_dir, ':~')), + string.format( + ' Root directory: %s', + client.root_dir and vim.fn.fnamemodify(client.root_dir, ':~') or nil + ), string.format(' Command: %s', cmd), string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })), string.format( -- cgit From 7994fdba6a1e10aad0698dfabcbaf544b4d35eb4 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 25 May 2024 21:23:04 +0200 Subject: fix(snippet): don't override unnamed register on tabstop select (#28998) --- runtime/lua/vim/snippet.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3d8f73f362..3fd2555046 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -315,7 +315,7 @@ local function select_tabstop(tabstop) move_cursor_to(range[1] + 1, range[2] + 1) feedkeys('v') move_cursor_to(range[3] + 1, range[4]) - feedkeys('o') + feedkeys('o_') end end -- cgit From 3d39ea3ea9b6e66640e59731d155d731218e7e62 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 May 2024 07:11:50 +0800 Subject: vim-patch:9.1.0442: hare runtime files outdated (#29011) Problem: hare runtime files outdated Solution: runtime(hare): update hare.vim to match upstream (Amelia Clarke) closes: vim/vim#14836 https://github.com/vim/vim/commit/35dfe58a540e2fb0eff953630f8e4fcbf4bc26ca Co-authored-by: Amelia Clarke --- runtime/lua/vim/filetype.lua | 2 +- runtime/lua/vim/filetype/detect.lua | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index d1fdd0aa16..2ab6cc6059 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1637,7 +1637,7 @@ local filename = { ['.xsdbcmdhistory'] = 'tcl', ['texmf.cnf'] = 'texmf', COPYING = 'text', - README = 'text', + README = detect_seq(detect.haredoc, 'text'), LICENSE = 'text', AUTHORS = 'text', tfrc = 'tf', diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index ba86d8de5a..58d2666564 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -650,6 +650,30 @@ function M.header(_, bufnr) end end +--- Recursively search for Hare source files in a directory and any +--- subdirectories, up to a given depth. +--- @param dir string +--- @param depth number +--- @return boolean +local function is_hare_module(dir, depth) + depth = math.max(depth, 0) + for name, _ in vim.fs.dir(dir, { depth = depth + 1 }) do + if name:find('%.ha$') then + return true + end + end + return false +end + +--- @type vim.filetype.mapfn +function M.haredoc(path, _) + if vim.g.filetype_haredoc then + if is_hare_module(vim.fs.dirname(path), vim.g.haredoc_search_depth or 1) then + return 'haredoc' + end + end +end + --- @type vim.filetype.mapfn function M.html(_, bufnr) for _, line in ipairs(getlines(bufnr, 1, 10)) do -- cgit From 2ed6423c7e9d4911343d3e2049908f4b78ec7a55 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 12:56:32 +0200 Subject: fix(tohtml): replace ipairs with pairs --- runtime/lua/tohtml.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 505de720ba..5a6fc77e5c 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -521,7 +521,7 @@ local function _styletable_extmarks_virt_text(state, extmark) hl_mode = 'blend', hl_group = 'combine', } - for opt, val in ipairs(not_supported) do + for opt, val in pairs(not_supported) do if extmark[4][opt] == val then vim.notify_once( ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) -- cgit From 8cd9feb50166202bf55315934f14f74e63c8fcb4 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 13:08:57 +0200 Subject: fix(tohtml): ignore lsp inlay hints --- runtime/lua/tohtml.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 5a6fc77e5c..f7d8538b8f 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -481,10 +481,17 @@ end --- @param state vim.tohtml.state --- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} -local function _styletable_extmarks_virt_text(state, extmark) +--- @param namespaces table +local function _styletable_extmarks_virt_text(state, extmark, namespaces) if not extmark[4].virt_text then return end + ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only + ---generated in visible lines, and not in the whole buffer. + if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then + vim.notify_once('Info(TOhtml): lsp inlay hints are not supported, HTML may be incorrect') + return + end local styletable = state.style --- @type integer,integer local row, col = extmark[2], extmark[3] @@ -586,7 +593,7 @@ local function styletable_extmarks(state) _styletable_extmarks_conceal(state, v) end for _, v in ipairs(extmarks) do - _styletable_extmarks_virt_text(state, v) + _styletable_extmarks_virt_text(state, v, namespaces) end for _, v in ipairs(extmarks) do _styletable_extmarks_virt_lines(state, v) -- cgit From 88c7997503e12088e134ba663fe352399f8fa104 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 13:28:14 +0200 Subject: fix(tohtml): show how many warnings are hidden --- runtime/lua/tohtml.lua | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index f7d8538b8f..0fc349e86d 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -57,6 +57,26 @@ --- @field [3] any[][] virt_text --- @field [4] any[][] overlay_text +--- @type string[] +local notifications = {} + +---@param msg string +local function notify(msg) + if #notifications == 0 then + vim.schedule(function() + if #notifications > 1 then + vim.notify( + ('TOhtml: %s (+ %d more warnings)'):format(notifications[1], tostring(#notifications - 1)) + ) + elseif #notifications == 1 then + vim.notify('TOhtml: ' .. notifications[1]) + end + notifications = {} + end) + end + table.insert(notifications, msg) +end + local HIDE_ID = -1 -- stylua: ignore start local cterm_8_to_hex={ @@ -215,7 +235,7 @@ local function cterm_to_hex(colorstr) if hex then cterm_color_cache[color] = hex else - vim.notify_once("Info(TOhtml): Couldn't get terminal colors, using fallback") + notify("Couldn't get terminal colors, using fallback") local t_Co = tonumber(vim.api.nvim_eval('&t_Co')) if t_Co <= 8 then cterm_color_cache = cterm_8_to_hex @@ -241,7 +261,7 @@ local function get_background_color() end local hex = try_query_terminal_color('background') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal background colors, using fallback") + notify("Couldn't get terminal background colors, using fallback") hex = vim.o.background == 'light' and '#ffffff' or '#000000' end background_color_cache = hex @@ -259,7 +279,7 @@ local function get_foreground_color() end local hex = try_query_terminal_color('foreground') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal foreground colors, using fallback") + notify("Couldn't get terminal foreground colors, using fallback") hex = vim.o.background == 'light' and '#000000' or '#ffffff' end foreground_color_cache = hex @@ -467,7 +487,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_semantic_tokens') then - vim.notify_once('Info(TOhtml): lsp semantic tokens are not supported, HTML may be incorrect') + notify('lsp semantic tokens are not supported, HTML may be incorrect') return end local srow, scol, erow, ecol = @@ -489,7 +509,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then - vim.notify_once('Info(TOhtml): lsp inlay hints are not supported, HTML may be incorrect') + notify('lsp inlay hints are not supported, HTML may be incorrect') return end local styletable = state.style @@ -530,9 +550,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) } for opt, val in pairs(not_supported) do if extmark[4][opt] == val then - vim.notify_once( - ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) - ) + notify(('extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val)) end end end @@ -618,9 +636,7 @@ local function styletable_folds(state) end end if has_folded and type(({ pcall(vim.api.nvim_eval, vim.o.foldtext) })[2]) == 'table' then - vim.notify_once( - 'Info(TOhtml): foldtext returning a table is half supported, HTML may be incorrect' - ) + notify('foldtext returning a table with highlights is not supported, HTML may be incorrect') end end -- cgit From eb37241d38ad35b9e6bfac6379dd10e60aa0350c Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 26 May 2024 10:27:12 -0700 Subject: fix(tohtml): properly handle multiple hl groups #29012 Problem: :TOhtml doesn't properly handle virtual text when it has multiple highlight groups. It also improperly calculates position offset for multi-byte virt_text characters. Solution: Apply the `vim.api.nvim_strwidth` broadly to properly calculate character offset, and handle the cases where the `hl` argument can be a table of multiple hl groups. --- runtime/lua/tohtml.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 0fc349e86d..5e145950b7 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -188,6 +188,8 @@ local background_color_cache = nil --- @type string? local foreground_color_cache = nil +local len = vim.api.nvim_strwidth + --- @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands --- @param color "background"|"foreground"|integer --- @return string? @@ -312,9 +314,12 @@ local function style_line_insert_virt_text(style_line, col, val) end --- @param state vim.tohtml.state ---- @param hl string|integer|nil +--- @param hl string|integer|string[]|integer[]? --- @return nil|integer local function register_hl(state, hl) + if type(hl) == 'table' then + hl = hl[#hl] + end if type(hl) == 'nil' then return elseif type(hl) == 'string' then @@ -537,7 +542,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) else style_line_insert_virt_text(styletable[row + 1], col + 1, { i[1], hlid }) end - virt_text_len = virt_text_len + #i[1] + virt_text_len = virt_text_len + len(i[1]) end if extmark[4].virt_text_pos == 'overlay' then styletable_insert_range(state, row + 1, col + 1, row + 1, col + virt_text_len + 1, HIDE_ID) @@ -782,7 +787,7 @@ local function styletable_statuscolumn(state) statuscolumn, { winid = state.winid, use_statuscol_lnum = row, highlights = true } ) - local width = vim.api.nvim_strwidth(status.str) + local width = len(status.str) if width > minwidth then minwidth = width end @@ -797,7 +802,7 @@ local function styletable_statuscolumn(state) for k, v in ipairs(hls) do local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil) if k == #hls then - text = text .. (' '):rep(minwidth - vim.api.nvim_strwidth(str)) + text = text .. (' '):rep(minwidth - len(str)) end if text ~= '' then local hlid = register_hl(state, v.group) @@ -817,7 +822,6 @@ local function styletable_listchars(state) local function utf8_sub(str, i, j) return vim.fn.strcharpart(str, i - 1, j and j - i + 1 or nil) end - local len = vim.api.nvim_strwidth --- @type table local listchars = vim.opt_local.listchars:get() local ids = setmetatable({}, { -- cgit From c4eb0b64bd4923a72fe737837cfe234c80fb539c Mon Sep 17 00:00:00 2001 From: Guilherme Soares <48023091+guilhas07@users.noreply.github.com> Date: Mon, 27 May 2024 13:20:03 +0200 Subject: fix(treesitter): find buffer in multiple windows #28922 Problem: 1. When interacting with multiple :InspectTree and the source buffer windows there is a high chance of errors due to the window ids not being updated and validated. 2. Not all InspectTree windows were closed when the source buffer was closed. Solution: 1. Update InspectTree window id on `CursorMoved` event and validate source buffer window id before trying to navigate to it. 2. Close all InspectTree windows --- runtime/lua/vim/treesitter/dev.lua | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua index 5c91f101c0..ca8cf85eda 100644 --- a/runtime/lua/vim/treesitter/dev.lua +++ b/runtime/lua/vim/treesitter/dev.lua @@ -325,7 +325,10 @@ function M.inspect_tree(opts) opts = opts or {} + -- source buffer local buf = api.nvim_get_current_buf() + + -- window id for source buffer local win = api.nvim_get_current_win() local treeview = assert(TSTreeView:new(buf, opts.lang)) @@ -334,12 +337,14 @@ function M.inspect_tree(opts) close_win(vim.b[buf].dev_inspect) end + -- window id for tree buffer local w = opts.winid if not w then vim.cmd(opts.command or '60vnew') w = api.nvim_get_current_win() end + -- tree buffer local b = opts.bufnr if b then api.nvim_win_set_buf(w, b) @@ -375,6 +380,12 @@ function M.inspect_tree(opts) callback = function() local row = api.nvim_win_get_cursor(w)[1] local lnum, col = treeview:get(row).node:start() + + -- update source window if original was closed + if not api.nvim_win_is_valid(win) then + win = vim.fn.win_findbuf(buf)[1] + end + api.nvim_set_current_win(win) api.nvim_win_set_cursor(win, { lnum + 1, col }) end, @@ -432,6 +443,7 @@ function M.inspect_tree(opts) return true end + w = api.nvim_get_current_win() api.nvim_buf_clear_namespace(buf, treeview.ns, 0, -1) local row = api.nvim_win_get_cursor(w)[1] local lnum, col, end_lnum, end_col = treeview:get(row).node:range() @@ -441,6 +453,11 @@ function M.inspect_tree(opts) hl_group = 'Visual', }) + -- update source window if original was closed + if not api.nvim_win_is_valid(win) then + win = vim.fn.win_findbuf(buf)[1] + end + local topline, botline = vim.fn.line('w0', win), vim.fn.line('w$', win) -- Move the cursor if highlighted range is completely out of view @@ -506,7 +523,10 @@ function M.inspect_tree(opts) buffer = buf, once = true, callback = function() - close_win(w) + -- close all tree windows + for _, window in pairs(vim.fn.win_findbuf(b)) do + close_win(window) + end end, }) end -- cgit From 48251134ee59a3e2f0aeb89608fa820c21b25d4f Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 27 May 2024 08:08:23 -0500 Subject: perf: add fast path to vim.validate (#28977) For many small/simple functions (like those found in shared.lua), the runtime of vim.validate can far exceed the runtime of the function itself. Add an "overload" to vim.validate that uses a simple assertion pattern, rather than parsing a full "validation spec". --- runtime/lua/vim/shared.lua | 76 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 14 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index e9e4326057..2641d1feb0 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -214,7 +214,7 @@ end ---@param t table (table) Table ---@return T[] : List of keys function vim.tbl_keys(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table local keys = {} @@ -231,7 +231,7 @@ end ---@param t table (table) Table ---@return T[] : List of values function vim.tbl_values(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') local values = {} for _, v in @@ -332,7 +332,7 @@ end ---@param value any Value to compare ---@return boolean `true` if `t` contains `value` function vim.list_contains(t, value) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table for _, v in ipairs(t) do @@ -350,7 +350,7 @@ end ---@param t table Table to check ---@return boolean `true` if `t` is empty function vim.tbl_isempty(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') return next(t) == nil end @@ -580,7 +580,7 @@ end ---@return fun(table: table, index?: K):K, V # |for-in| iterator over sorted keys and their values ---@return T function vim.spairs(t) - assert(type(t) == 'table', ('expected table, got %s'):format(type(t))) + vim.validate('t', t, 'table') --- @cast t table -- collect the keys @@ -691,7 +691,7 @@ end ---@param t table Table ---@return integer : Number of non-nil values in table function vim.tbl_count(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table local count = 0 @@ -723,7 +723,7 @@ end ---@param s string String to trim ---@return string String with whitespace removed from its beginning and end function vim.trim(s) - vim.validate({ s = { s, 's' } }) + vim.validate('s', s, 'string') return s:match('^%s*(.*%S)') or '' end @@ -733,7 +733,7 @@ end ---@param s string String to escape ---@return string %-escaped pattern string function vim.pesc(s) - vim.validate({ s = { s, 's' } }) + vim.validate('s', s, 'string') return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')) end @@ -743,7 +743,8 @@ end ---@param prefix string Prefix to match ---@return boolean `true` if `prefix` is a prefix of `s` function vim.startswith(s, prefix) - vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } }) + vim.validate('s', s, 'string') + vim.validate('prefix', prefix, 'string') return s:sub(1, #prefix) == prefix end @@ -753,7 +754,8 @@ end ---@param suffix string Suffix to match ---@return boolean `true` if `suffix` is a suffix of `s` function vim.endswith(s, suffix) - vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } }) + vim.validate('s', s, 'string') + vim.validate('suffix', suffix, 'string') return #suffix == 0 or s:sub(-#suffix) == suffix end @@ -877,8 +879,30 @@ do return true end - --- Validates a parameter specification (types and values). Specs are evaluated in alphanumeric - --- order, until the first failure. + --- Validate function arguments. + --- + --- This function has two valid forms: + --- + --- 1. vim.validate(name: str, value: any, type: string, optional?: bool) + --- 2. vim.validate(spec: table) + --- + --- Form 1 validates that argument {name} with value {value} has the type + --- {type}. {type} must be a value returned by |lua-type()|. If {optional} is + --- true, then {value} may be null. This form is significantly faster and + --- should be preferred for simple cases. + --- + --- Example: + --- + --- ```lua + --- function vim.startswith(s, prefix) + --- vim.validate('s', s, 'string') + --- vim.validate('prefix', prefix, 'string') + --- ... + --- end + --- ``` + --- + --- Form 2 validates a parameter specification (types and values). Specs are + --- evaluated in alphanumeric order, until the first failure. --- --- Usage example: --- @@ -930,8 +954,32 @@ do --- only if the argument is valid. Can optionally return an additional --- informative error message as the second returned value. --- - msg: (optional) error string if validation fails - function vim.validate(opt) - local ok, err_msg = is_valid(opt) + --- @overload fun(name: string, val: any, expected: string, optional?: boolean) + function vim.validate(opt, ...) + local ok = false + local err_msg ---@type string? + local narg = select('#', ...) + if narg == 0 then + ok, err_msg = is_valid(opt) + elseif narg >= 2 then + -- Overloaded signature for fast/simple cases + local name = opt --[[@as string]] + local v, expected, optional = ... ---@type string, string, boolean? + local actual = type(v) + + ok = (actual == expected) or (v == nil and optional == true) + if not ok then + err_msg = ('%s: expected %s, got %s%s'):format( + name, + expected, + actual, + v and (' (%s)'):format(v) or '' + ) + end + else + error('invalid arguments') + end + if not ok then error(err_msg, 2) end -- cgit From 292365fa1b8f543ffa2240bb30af34051ad2d7c8 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Mon, 27 May 2024 11:06:03 -0400 Subject: fix(lsp): do not detach from buffer if there are uninitialized clients (#29029) Problem: if on_lines is called before the LSP is initialized, the buffer is detached. Solution: check for uninitialized clients before detaching. --- runtime/lua/vim/lsp.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 1592fd3151..60b3f3e502 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -577,7 +577,8 @@ local function buf_attach(bufnr) api.nvim_buf_attach(bufnr, false, { on_lines = function(_, _, changedtick, firstline, lastline, new_lastline) if #lsp.get_clients({ bufnr = bufnr }) == 0 then - return true -- detach + -- detach if there are no clients + return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 end util.buf_versions[bufnr] = changedtick changetracking.send_changes(bufnr, firstline, lastline, new_lastline) -- cgit From 608543f8a90b08cbe84cea878a14f053789f45a4 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 27 May 2024 08:18:10 -0700 Subject: fix(snippet): cancel snippet session when leaving the buffer (#29031) --- runtime/lua/vim/snippet.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3fd2555046..8e384e0f97 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -395,6 +395,15 @@ local function setup_autocmds(bufnr) end end, }) + + vim.api.nvim_create_autocmd('BufLeave', { + group = snippet_group, + desc = 'Stop the snippet session when leaving the buffer', + buffer = bufnr, + callback = function() + M.stop() + end, + }) end --- Expands the given snippet text. -- cgit From 6e8a728e3dad747d0c46dc47a530b76e8997bc08 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 20:35:37 +0200 Subject: refactor: fix luals type warnings --- runtime/lua/tohtml.lua | 4 +- runtime/lua/vim/_meta.lua | 2 + runtime/lua/vim/_meta/vimfn.lua | 2 +- runtime/lua/vim/deprecated/health.lua | 2 +- runtime/lua/vim/health.lua | 12 ++--- runtime/lua/vim/health/health.lua | 3 +- runtime/lua/vim/lsp/util.lua | 4 +- runtime/lua/vim/provider/health.lua | 82 +++++++++++++++++------------------ 8 files changed, 56 insertions(+), 55 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 5e145950b7..120247ed4e 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -65,9 +65,7 @@ local function notify(msg) if #notifications == 0 then vim.schedule(function() if #notifications > 1 then - vim.notify( - ('TOhtml: %s (+ %d more warnings)'):format(notifications[1], tostring(#notifications - 1)) - ) + vim.notify(('TOhtml: %s (+ %d more warnings)'):format(notifications[1], #notifications - 1)) elseif #notifications == 1 then vim.notify('TOhtml: ' .. notifications[1]) end diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 731dd5b923..c9f207cb20 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -34,3 +34,5 @@ vim.uri_from_fname = uri.uri_from_fname vim.uri_from_bufnr = uri.uri_from_bufnr vim.uri_to_fname = uri.uri_to_fname vim.uri_to_bufnr = uri.uri_to_bufnr + +vim.provider = require('vim.provider') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index f256f63768..84bb26a135 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1642,7 +1642,7 @@ function vim.fn.execute(command, silent) end --- If {expr} starts with "./" the |current-directory| is used. --- --- @param expr any ---- @return any +--- @return string function vim.fn.exepath(expr) end --- The result is a Number, which is |TRUE| if {expr} is diff --git a/runtime/lua/vim/deprecated/health.lua b/runtime/lua/vim/deprecated/health.lua index 0f6b1f578c..64a755b248 100644 --- a/runtime/lua/vim/deprecated/health.lua +++ b/runtime/lua/vim/deprecated/health.lua @@ -1,7 +1,7 @@ local M = {} local health = vim.health -local deprecated = {} +local deprecated = {} ---@type {[1]: string, [2]: table, [3]: string}[] function M.check() if next(deprecated) == nil then diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index afeba2ee9d..236f9da752 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -104,10 +104,10 @@ local function filepath_to_healthcheck(path) local subpath = path:gsub('.*lua/', '') if vim.fs.basename(subpath) == 'health.lua' then -- */health.lua - name = assert(vim.fs.dirname(subpath)) + name = vim.fs.dirname(subpath) else -- */health/init.lua - name = assert(vim.fs.dirname(assert(vim.fs.dirname(subpath)))) + name = vim.fs.dirname(vim.fs.dirname(subpath)) end name = name:gsub('/', '.') @@ -301,11 +301,13 @@ end local PATTERNS = { '/autoload/health/*.vim', '/lua/**/**/health.lua', '/lua/**/**/health/init.lua' } --- :checkhealth completion function used by cmdexpand.c get_healthcheck_names() M._complete = function() - local unique = vim + local unique = vim ---@type table + ---@param pattern string .iter(vim.tbl_map(function(pattern) return vim.tbl_map(path2name, vim.api.nvim_get_runtime_file(pattern, true)) end, PATTERNS)) :flatten() + ---@param t table :fold({}, function(t, name) t[name] = true -- Remove duplicates return t @@ -364,7 +366,7 @@ function M._check(mods, plugin_names) vim.fn.call(func, {}) else local f = assert(loadstring(func)) - local ok, output = pcall(f) + local ok, output = pcall(f) ---@type boolean, string if not ok then M.error( string.format('Failed to run healthcheck for "%s" plugin. Exception:\n%s\n', name, output) @@ -391,7 +393,7 @@ function M._check(mods, plugin_names) end s_output[#s_output + 1] = '' s_output = vim.list_extend(header, s_output) - vim.fn.append('$', s_output) + vim.fn.append(vim.fn.line('$'), s_output) vim.cmd.redraw() end diff --git a/runtime/lua/vim/health/health.lua b/runtime/lua/vim/health/health.lua index 5bc03199ee..235dacb82a 100644 --- a/runtime/lua/vim/health/health.lua +++ b/runtime/lua/vim/health/health.lua @@ -239,6 +239,7 @@ local function check_tmux() return end + ---@param option string local get_tmux_option = function(option) local cmd = 'tmux show-option -qvg ' .. option -- try global scope local out = vim.fn.system(vim.fn.split(cmd)) @@ -378,7 +379,7 @@ local function check_terminal() 'SSH_TTY', }) do if vim.env[env_var] then - health.info(vim.fn.printf('$%s="%s"', env_var, vim.env[env_var])) + health.info(string.format('$%s="%s"', env_var, vim.env[env_var])) end end end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 5a229a1169..0099e82f52 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -616,7 +616,7 @@ function M.rename(old_fname, new_fname, opts) buf_rename[b] = { from = old_bname, to = new_bname } end - local newdir = assert(vim.fs.dirname(new_fname)) + local newdir = vim.fs.dirname(new_fname) vim.fn.mkdir(newdir, 'p') local ok, err = os.rename(old_fname_full, new_fname) @@ -625,7 +625,7 @@ function M.rename(old_fname, new_fname, opts) local old_undofile = vim.fn.undofile(old_fname_full) if uv.fs_stat(old_undofile) ~= nil then local new_undofile = vim.fn.undofile(new_fname) - vim.fn.mkdir(assert(vim.fs.dirname(new_undofile)), 'p') + vim.fn.mkdir(vim.fs.dirname(new_undofile), 'p') os.rename(old_undofile, new_undofile) end diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index d6932f651e..fa2c452268 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -95,10 +95,10 @@ local function system(cmd, args) error(emsg) end - -- return opts.output return vim.trim(vim.fn.system(cmd)), shell_error_code end +---@param provider string local function provider_disabled(provider) local loaded_var = 'loaded_' .. provider .. '_provider' local v = vim.g[loaded_var] @@ -126,9 +126,9 @@ local function clipboard() health.error('pbcopy does not work with tmux version: ' .. tmux_version, advice) end - local clipboard_tool = vim.fn['provider#clipboard#Executable']() + local clipboard_tool = vim.fn['provider#clipboard#Executable']() ---@type string if vim.g.clipboard ~= nil and clipboard_tool == '' then - local error_message = vim.fn['provider#clipboard#Error']() + local error_message = vim.fn['provider#clipboard#Error']() ---@type string health.error( error_message, "Use the example in :help g:clipboard as a template, or don't set g:clipboard at all." @@ -179,7 +179,7 @@ local function node() ) end - local node_detect_table = vim.fn['provider#node#Detect']() + local node_detect_table = vim.fn['provider#node#Detect']() ---@type string[] local host = node_detect_table[1] if host:find('^%s*$') then health.warn('Missing "neovim" npm (or yarn, pnpm) package.', { @@ -290,7 +290,7 @@ local function perl() elseif latest_cpan[1] == '!' then local cpanm_errs = vim.split(latest_cpan, '!') if cpanm_errs[1]:find("Can't write to ") then - local advice = {} + local advice = {} ---@type string[] for i = 2, #cpanm_errs do advice[#advice + 1] = cpanm_errs[i] end @@ -303,7 +303,7 @@ local function perl() return end end - latest_cpan = vim.fn.matchstr(latest_cpan, [[\(\.\?\d\)\+]]) + latest_cpan = tostring(vim.fn.matchstr(latest_cpan, [[\(\.\?\d\)\+]])) if latest_cpan:find('^%s*$') then health.error('Cannot parse version number from cpanm output: ' .. latest_cpan) return @@ -349,9 +349,11 @@ local function python_exepath(invocation) return vim.fs.normalize(vim.trim(p.stdout)) end --- Check if pyenv is available and a valid pyenv root can be found, then return --- their respective paths. If either of those is invalid, return two empty --- strings, effectively ignoring pyenv. +--- Check if pyenv is available and a valid pyenv root can be found, then return +--- their respective paths. If either of those is invalid, return two empty +--- strings, effectively ignoring pyenv. +--- +--- @return {[1]: string, [2]: string} local function check_for_pyenv() local pyenv_path = vim.fn.resolve(vim.fn.exepath('pyenv')) @@ -394,7 +396,9 @@ local function check_bin(bin) return true end --- Fetch the contents of a URL. +--- Fetch the contents of a URL. +--- +--- @param url string local function download(url) local has_curl = vim.fn.executable('curl') == 1 if has_curl and vim.fn.system({ 'curl', '-V' }):find('Protocols:.*https') then @@ -429,25 +433,24 @@ local function download(url) return message end --- Get the latest Nvim Python client (pynvim) version from PyPI. +--- Get the latest Nvim Python client (pynvim) version from PyPI. local function latest_pypi_version() local pypi_version = 'unable to get pypi response' local pypi_response = download('https://pypi.python.org/pypi/pynvim/json') if pypi_response ~= '' then local pcall_ok, output = pcall(vim.fn.json_decode, pypi_response) - local pypi_data - if pcall_ok then - pypi_data = output - else + if not pcall_ok then return 'error: ' .. pypi_response end + local pypi_data = output local pypi_element = pypi_data['info'] or {} pypi_version = pypi_element['version'] or 'unable to parse' end return pypi_version end +--- @param s string local function is_bad_response(s) local lower = s:lower() return vim.startswith(lower, 'unable') @@ -455,16 +458,18 @@ local function is_bad_response(s) or vim.startswith(lower, 'outdated') end --- Get version information using the specified interpreter. The interpreter is --- used directly in case breaking changes were introduced since the last time --- Nvim's Python client was updated. --- --- Returns: { --- {python executable version}, --- {current nvim version}, --- {current pypi nvim status}, --- {installed version status} --- } +--- Get version information using the specified interpreter. The interpreter is +--- used directly in case breaking changes were introduced since the last time +--- Nvim's Python client was updated. +--- +--- @param python string +--- +--- Returns: { +--- {python executable version}, +--- {current nvim version}, +--- {current pypi nvim status}, +--- {installed version status} +--- } local function version_info(python) local pypi_version = latest_pypi_version() @@ -512,9 +517,9 @@ local function version_info(python) if rc ~= 0 or nvim_version == '' then nvim_version = 'unable to find pynvim module version' local base = vim.fs.basename(nvim_path) - local metas = vim.fn.glob(base .. '-*/METADATA', 1, 1) - vim.list_extend(metas, vim.fn.glob(base .. '-*/PKG-INFO', 1, 1)) - vim.list_extend(metas, vim.fn.glob(base .. '.egg-info/PKG-INFO', 1, 1)) + local metas = vim.fn.glob(base .. '-*/METADATA', true, 1) + vim.list_extend(metas, vim.fn.glob(base .. '-*/PKG-INFO', true, 1)) + vim.list_extend(metas, vim.fn.glob(base .. '.egg-info/PKG-INFO', true, 1)) metas = table.sort(metas, compare) if metas and next(metas) ~= nil then @@ -544,14 +549,13 @@ end local function python() health.start('Python 3 provider (optional)') - local pyname = 'python3' ---@type string? local python_exe = '' local virtual_env = os.getenv('VIRTUAL_ENV') local venv = virtual_env and vim.fn.resolve(virtual_env) or '' - local host_prog_var = pyname .. '_host_prog' - local python_multiple = {} + local host_prog_var = 'python3_host_prog' + local python_multiple = {} ---@type string[] - if provider_disabled(pyname) then + if provider_disabled('python3') then return end @@ -564,8 +568,7 @@ local function python() health.info(message) end - local pythonx_warnings - pyname, pythonx_warnings = vim.provider.python.detect_by_module('neovim') + local pyname, pythonx_warnings = vim.provider.python.detect_by_module('neovim') if not pyname then health.warn( @@ -653,12 +656,7 @@ local function python() ) health.warn('pyenv is not set up optimally.', advice) elseif venv ~= '' then - local venv_root - if pyenv_root ~= '' then - venv_root = pyenv_root - else - venv_root = vim.fs.dirname(venv) - end + local venv_root = pyenv_root ~= '' and pyenv_root or vim.fs.dirname(venv) if vim.startswith(vim.fn.resolve(python_exe), venv_root .. '/') then local advice = string.format( @@ -743,9 +741,9 @@ local function python() health.ok('no $VIRTUAL_ENV') return end - local errors = {} + local errors = {} ---@type string[] -- Keep hints as dict keys in order to discard duplicates. - local hints = {} + local hints = {} ---@type table -- The virtualenv should contain some Python executables, and those -- executables should be first both on Nvim's $PATH and the $PATH of -- subshells launched from Nvim. -- cgit From ff097f2091e7a970e5b12960683b4dade5563040 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 4 Feb 2024 14:13:23 -0800 Subject: feat(lsp): completion side effects --- runtime/lua/vim/lsp.lua | 5 +- runtime/lua/vim/lsp/_completion.lua | 276 -------------- runtime/lua/vim/lsp/client.lua | 23 +- runtime/lua/vim/lsp/completion.lua | 734 ++++++++++++++++++++++++++++++++++++ runtime/lua/vim/lsp/handlers.lua | 2 +- runtime/lua/vim/lsp/protocol.lua | 10 +- 6 files changed, 757 insertions(+), 293 deletions(-) delete mode 100644 runtime/lua/vim/lsp/_completion.lua create mode 100644 runtime/lua/vim/lsp/completion.lua (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 1592fd3151..da3d4d91f2 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -3,7 +3,6 @@ local validate = vim.validate local lsp = vim._defer_require('vim.lsp', { _changetracking = ..., --- @module 'vim.lsp._changetracking' - _completion = ..., --- @module 'vim.lsp._completion' _dynamic = ..., --- @module 'vim.lsp._dynamic' _snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar' _tagfunc = ..., --- @module 'vim.lsp._tagfunc' @@ -11,6 +10,7 @@ local lsp = vim._defer_require('vim.lsp', { buf = ..., --- @module 'vim.lsp.buf' client = ..., --- @module 'vim.lsp.client' codelens = ..., --- @module 'vim.lsp.codelens' + completion = ..., --- @module 'vim.lsp.completion' diagnostic = ..., --- @module 'vim.lsp.diagnostic' handlers = ..., --- @module 'vim.lsp.handlers' inlay_hint = ..., --- @module 'vim.lsp.inlay_hint' @@ -1002,8 +1002,7 @@ end --- - findstart=0: column where the completion starts, or -2 or -3 --- - findstart=1: list of matches (actually just calls |complete()|) function lsp.omnifunc(findstart, base) - log.debug('omnifunc.findstart', { findstart = findstart, base = base }) - return vim.lsp._completion.omnifunc(findstart, base) + return vim.lsp.completion._omnifunc(findstart, base) end --- @class vim.lsp.formatexpr.Opts diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua deleted file mode 100644 index a169f96565..0000000000 --- a/runtime/lua/vim/lsp/_completion.lua +++ /dev/null @@ -1,276 +0,0 @@ -local M = {} -local api = vim.api -local lsp = vim.lsp -local protocol = lsp.protocol -local ms = protocol.Methods - ---- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] - --- TODO(mariasolos): Remove this declaration once we figure out a better way to handle --- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). ---- @class lsp.ItemDefaults ---- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil ---- @field insertTextFormat lsp.InsertTextFormat? ---- @field insertTextMode lsp.InsertTextMode? ---- @field data any - ----@param input string unparsed snippet ----@return string parsed snippet -local function parse_snippet(input) - local ok, parsed = pcall(function() - return vim.lsp._snippet_grammar.parse(input) - end) - return ok and tostring(parsed) or input -end - ---- 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 ---- ----@param item lsp.CompletionItem ----@return string -local function get_completion_word(item) - if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.textEdit.newText - else - return parse_snippet(item.textEdit.newText) - end - elseif item.insertText ~= nil and item.insertText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.insertText - else - return parse_snippet(item.insertText) - end - end - return item.label -end - ---- Applies the given defaults to the completion item, modifying it in place. ---- ---- @param item lsp.CompletionItem ---- @param defaults lsp.ItemDefaults? -local function apply_defaults(item, defaults) - if not defaults then - return - end - - item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat - item.insertTextMode = item.insertTextMode or defaults.insertTextMode - item.data = item.data or defaults.data - if defaults.editRange then - local textEdit = item.textEdit or {} - item.textEdit = textEdit - textEdit.newText = textEdit.newText or item.textEditText or item.insertText - if defaults.editRange.start then - textEdit.range = textEdit.range or defaults.editRange - elseif defaults.editRange.insert then - textEdit.insert = defaults.editRange.insert - textEdit.replace = defaults.editRange.replace - end - end -end - ----@param result vim.lsp.CompletionResult ----@return lsp.CompletionItem[] -local function get_items(result) - if result.items then - for _, item in ipairs(result.items) do - ---@diagnostic disable-next-line: param-type-mismatch - apply_defaults(item, result.itemDefaults) - end - return result.items - else - return result - end -end - ---- Turns the result of a `textDocument/completion` request into vim-compatible ---- |complete-items|. ---- ----@param result vim.lsp.CompletionResult Result of `textDocument/completion` ----@param prefix string prefix to filter the completion items ----@return table[] ----@see complete-items -function M._lsp_to_complete_items(result, prefix) - local items = get_items(result) - if vim.tbl_isempty(items) then - return {} - end - - local function matches_prefix(item) - return vim.startswith(get_completion_word(item), prefix) - end - - items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] - table.sort(items, function(a, b) - return (a.sortText or a.label) < (b.sortText or b.label) - end) - - local matches = {} - for _, item in ipairs(items) do - local info = '' - local documentation = item.documentation - if documentation then - if type(documentation) == 'string' and documentation ~= '' then - info = documentation - elseif type(documentation) == 'table' and type(documentation.value) == 'string' then - info = documentation.value - else - vim.notify( - ('invalid documentation value %s'):format(vim.inspect(documentation)), - vim.log.levels.WARN - ) - end - end - local word = get_completion_word(item) - table.insert(matches, { - word = word, - abbr = item.label, - kind = protocol.CompletionItemKind[item.kind] or 'Unknown', - menu = item.detail or '', - info = #info > 0 and info or nil, - icase = 1, - dup = 1, - empty = 1, - user_data = { - nvim = { - lsp = { - completion_item = item, - }, - }, - }, - }) - end - return matches -end - ----@param lnum integer 0-indexed ----@param items lsp.CompletionItem[] -local function adjust_start_col(lnum, line, items, encoding) - local min_start_char = nil - for _, item in pairs(items) do - if item.textEdit and item.textEdit.range.start.line == lnum then - if min_start_char and min_start_char ~= item.textEdit.range.start.character then - return nil - end - min_start_char = item.textEdit.range.start.character - end - end - if min_start_char then - return vim.lsp.util._str_byteindex_enc(line, min_start_char, encoding) - else - return nil - end -end - ----@private ----@param line string line content ----@param lnum integer 0-indexed line number ----@param client_start_boundary integer 0-indexed word boundary ----@param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character ----@param result vim.lsp.CompletionResult ----@param encoding string ----@return table[] matches ----@return integer? server_start_boundary -function M._convert_results( - line, - lnum, - cursor_col, - client_start_boundary, - server_start_boundary, - result, - encoding -) - -- Completion response items may be relative to a position different than `client_start_boundary`. - -- Concrete example, with lua-language-server: - -- - -- require('plenary.asy| - -- ▲ ▲ ▲ - -- │ │ └── cursor_pos: 20 - -- │ └────── client_start_boundary: 17 - -- └────────────── textEdit.range.start.character: 9 - -- .newText = 'plenary.async' - -- ^^^ - -- prefix (We'd remove everything not starting with `asy`, - -- so we'd eliminate the `plenary.async` result - -- - -- `adjust_start_col` is used to prefer the language server boundary. - -- - local candidates = get_items(result) - local curstartbyte = adjust_start_col(lnum, line, candidates, encoding) - if server_start_boundary == nil then - server_start_boundary = curstartbyte - elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then - server_start_boundary = client_start_boundary - end - local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col) - local matches = M._lsp_to_complete_items(result, prefix) - return matches, server_start_boundary -end - ----@param findstart integer 0 or 1, decides behavior ----@param base integer findstart=0, text to match against ----@return integer|table Decided by {findstart}: ---- - findstart=0: column where the completion starts, or -2 or -3 ---- - findstart=1: list of matches (actually just calls |complete()|) -function M.omnifunc(findstart, base) - assert(base) -- silence luals - local bufnr = api.nvim_get_current_buf() - local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) - local remaining = #clients - if remaining == 0 then - return findstart == 1 and -1 or {} - end - - local win = api.nvim_get_current_win() - local cursor = api.nvim_win_get_cursor(win) - local lnum = cursor[1] - 1 - local cursor_col = cursor[2] - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) - local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] - local server_start_boundary = nil - local items = {} - - local function on_done() - local mode = api.nvim_get_mode()['mode'] - if mode == 'i' or mode == 'ic' then - vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) - end - end - - local util = vim.lsp.util - for _, client in ipairs(clients) do - local params = util.make_position_params(win, client.offset_encoding) - client.request(ms.textDocument_completion, params, function(err, result) - if err then - vim.lsp.log.warn(err.message) - end - if result and vim.fn.mode() == 'i' then - local matches - matches, server_start_boundary = M._convert_results( - line, - lnum, - cursor_col, - client_start_boundary, - server_start_boundary, - result, - client.offset_encoding - ) - vim.list_extend(items, matches) - end - remaining = remaining - 1 - if remaining == 0 then - vim.schedule(on_done) - end - end, bufnr) - end - - -- Return -2 to signal that we should continue completion so that we can - -- async complete. - return -2 -end - -return M diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 4beb7fefda..c8616bf728 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -869,7 +869,8 @@ end --- @param command lsp.Command --- @param context? {bufnr: integer} --- @param handler? lsp.Handler only called if a server command -function Client:_exec_cmd(command, context, handler) +--- @param on_unsupported? function handler invoked when the command is not supported by the client. +function Client:_exec_cmd(command, context, handler, on_unsupported) context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]] context.bufnr = context.bufnr or api.nvim_get_current_buf() context.client_id = self.id @@ -883,14 +884,18 @@ function Client:_exec_cmd(command, context, handler) local command_provider = self.server_capabilities.executeCommandProvider local commands = type(command_provider) == 'table' and command_provider.commands or {} if not vim.list_contains(commands, cmdname) then - vim.notify_once( - string.format( - 'Language server `%s` does not support command `%s`. This command may require a client extension.', - self.name, - cmdname - ), - vim.log.levels.WARN - ) + if on_unsupported then + on_unsupported() + else + vim.notify_once( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + self.name, + cmdname + ), + vim.log.levels.WARN + ) + end return end -- Not using command directly to exclude extra properties, diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua new file mode 100644 index 0000000000..25b3d53c8c --- /dev/null +++ b/runtime/lua/vim/lsp/completion.lua @@ -0,0 +1,734 @@ +local M = {} + +local api = vim.api +local lsp = vim.lsp +local protocol = lsp.protocol +local ms = protocol.Methods + +local rtt_ms = 50 +local ns_to_ms = 0.000001 + +--- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] + +-- TODO(mariasolos): Remove this declaration once we figure out a better way to handle +-- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). +--- @nodoc +--- @class lsp.ItemDefaults +--- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil +--- @field insertTextFormat lsp.InsertTextFormat? +--- @field insertTextMode lsp.InsertTextMode? +--- @field data any + +--- @nodoc +--- @class vim.lsp.completion.BufHandle +--- @field clients table +--- @field triggers table + +--- @type table +local buf_handles = {} + +--- @nodoc +--- @class vim.lsp.completion.Context +local Context = { + cursor = nil, --- @type { [1]: integer, [2]: integer }? + last_request_time = nil, --- @type integer? + pending_requests = {}, --- @type function[] + isIncomplete = false, +} + +--- @nodoc +function Context:cancel_pending() + for _, cancel in ipairs(self.pending_requests) do + cancel() + end + + self.pending_requests = {} +end + +--- @nodoc +function Context:reset() + -- Note that the cursor isn't reset here, it needs to survive a `CompleteDone` event. + self.isIncomplete = false + self.last_request_time = nil + self:cancel_pending() +end + +--- @type uv.uv_timer_t? +local completion_timer = nil + +--- @return uv.uv_timer_t +local function new_timer() + return assert(vim.uv.new_timer()) +end + +local function reset_timer() + if completion_timer then + completion_timer:stop() + completion_timer:close() + end + + completion_timer = nil +end + +--- @param window integer +--- @param warmup integer +--- @return fun(sample: number): number +local function exp_avg(window, warmup) + local count = 0 + local sum = 0 + local value = 0 + + return function(sample) + if count < warmup then + count = count + 1 + sum = sum + sample + value = sum / count + else + local factor = 2.0 / (window + 1) + value = value * (1 - factor) + sample * factor + end + return value + end +end +local compute_new_average = exp_avg(10, 10) + +--- @return number +local function next_debounce() + if not Context.last_request_time then + return rtt_ms + end + + local ms_since_request = (vim.uv.hrtime() - Context.last_request_time) * ns_to_ms + return math.max((ms_since_request - rtt_ms) * -1, 0) +end + +--- @param input string Unparsed snippet +--- @return string # Parsed snippet if successful, else returns its input +local function parse_snippet(input) + local ok, parsed = pcall(function() + return lsp._snippet_grammar.parse(input) + end) + return ok and tostring(parsed) or input +end + +--- @param item lsp.CompletionItem +--- @param suffix? string +local function apply_snippet(item, suffix) + if item.textEdit then + vim.snippet.expand(item.textEdit.newText .. suffix) + elseif item.insertText then + vim.snippet.expand(item.insertText .. suffix) + end +end + +--- Returns text that should be inserted when a 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 +--- +--- @param item lsp.CompletionItem +--- @return string +local function get_completion_word(item) + if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then + if item.insertTextFormat == protocol.InsertTextFormat.PlainText then + return item.textEdit.newText + else + return parse_snippet(item.textEdit.newText) + end + elseif item.insertText ~= nil and item.insertText ~= '' then + if item.insertTextFormat == protocol.InsertTextFormat.PlainText then + return item.insertText + else + return parse_snippet(item.insertText) + end + end + return item.label +end + +--- Applies the given defaults to the completion item, modifying it in place. +--- +--- @param item lsp.CompletionItem +--- @param defaults lsp.ItemDefaults? +local function apply_defaults(item, defaults) + if not defaults then + return + end + + item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat + item.insertTextMode = item.insertTextMode or defaults.insertTextMode + item.data = item.data or defaults.data + if defaults.editRange then + local textEdit = item.textEdit or {} + item.textEdit = textEdit + textEdit.newText = textEdit.newText or item.textEditText or item.insertText + if defaults.editRange.start then + textEdit.range = textEdit.range or defaults.editRange + elseif defaults.editRange.insert then + textEdit.insert = defaults.editRange.insert + textEdit.replace = defaults.editRange.replace + end + end +end + +--- @param result vim.lsp.CompletionResult +--- @return lsp.CompletionItem[] +local function get_items(result) + if result.items then + -- When we have a list, apply the defaults and return an array of items. + for _, item in ipairs(result.items) do + ---@diagnostic disable-next-line: param-type-mismatch + apply_defaults(item, result.itemDefaults) + end + return result.items + else + -- Else just return the items as they are. + return result + end +end + +--- Turns the result of a `textDocument/completion` request into vim-compatible +--- |complete-items|. +--- +--- @private +--- @param result vim.lsp.CompletionResult Result of `textDocument/completion` +--- @param prefix string prefix to filter the completion items +--- @param client_id integer? Client ID +--- @return table[] +--- @see complete-items +function M._lsp_to_complete_items(result, prefix, client_id) + local items = get_items(result) + if vim.tbl_isempty(items) then + return {} + end + + local function matches_prefix(item) + return vim.startswith(get_completion_word(item), prefix) + end + + items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] + table.sort(items, function(a, b) + return (a.sortText or a.label) < (b.sortText or b.label) + end) + + local matches = {} + for _, item in ipairs(items) do + local info = '' + local documentation = item.documentation + if documentation then + if type(documentation) == 'string' and documentation ~= '' then + info = documentation + elseif type(documentation) == 'table' and type(documentation.value) == 'string' then + info = documentation.value + else + vim.notify( + ('invalid documentation value %s'):format(vim.inspect(documentation)), + vim.log.levels.WARN + ) + end + end + local word = get_completion_word(item) + table.insert(matches, { + word = word, + abbr = item.label, + kind = protocol.CompletionItemKind[item.kind] or 'Unknown', + menu = item.detail or '', + info = #info > 0 and info or '', + icase = 1, + dup = 1, + empty = 1, + user_data = { + nvim = { + lsp = { + completion_item = item, + client_id = client_id, + }, + }, + }, + }) + end + return matches +end + +--- @param lnum integer 0-indexed +--- @param line string +--- @param items lsp.CompletionItem[] +--- @param encoding string +--- @return integer? +local function adjust_start_col(lnum, line, items, encoding) + local min_start_char = nil + for _, item in pairs(items) do + if item.textEdit and item.textEdit.range.start.line == lnum then + if min_start_char and min_start_char ~= item.textEdit.range.start.character then + return nil + end + min_start_char = item.textEdit.range.start.character + end + end + if min_start_char then + return lsp.util._str_byteindex_enc(line, min_start_char, encoding) + else + return nil + end +end + +--- @private +--- @param line string line content +--- @param lnum integer 0-indexed line number +--- @param cursor_col integer +--- @param client_id integer client ID +--- @param client_start_boundary integer 0-indexed word boundary +--- @param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character +--- @param result vim.lsp.CompletionResult +--- @param encoding string +--- @return table[] matches +--- @return integer? server_start_boundary +function M._convert_results( + line, + lnum, + cursor_col, + client_id, + client_start_boundary, + server_start_boundary, + result, + encoding +) + -- Completion response items may be relative to a position different than `client_start_boundary`. + -- Concrete example, with lua-language-server: + -- + -- require('plenary.asy| + -- ▲ ▲ ▲ + -- │ │ └── cursor_pos: 20 + -- │ └────── client_start_boundary: 17 + -- └────────────── textEdit.range.start.character: 9 + -- .newText = 'plenary.async' + -- ^^^ + -- prefix (We'd remove everything not starting with `asy`, + -- so we'd eliminate the `plenary.async` result + -- + -- `adjust_start_col` is used to prefer the language server boundary. + -- + local candidates = get_items(result) + local curstartbyte = adjust_start_col(lnum, line, candidates, encoding) + if server_start_boundary == nil then + server_start_boundary = curstartbyte + elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then + server_start_boundary = client_start_boundary + end + local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col) + local matches = M._lsp_to_complete_items(result, prefix, client_id) + return matches, server_start_boundary +end + +--- Implements 'omnifunc' compatible LSP completion. +--- +--- @see |complete-functions| +--- @see |complete-items| +--- @see |CompleteDone| +--- +--- @param findstart integer 0 or 1, decides behavior +--- @param base integer findstart=0, text to match against +--- +--- @return integer|table Decided by {findstart}: +--- - findstart=0: column where the completion starts, or -2 or -3 +--- - findstart=1: list of matches (actually just calls |complete()|) +function M._omnifunc(findstart, base) + vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) + assert(base) -- silence luals + local bufnr = api.nvim_get_current_buf() + local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) + local remaining = #clients + if remaining == 0 then + return findstart == 1 and -1 or {} + end + + local win = api.nvim_get_current_win() + local cursor = api.nvim_win_get_cursor(win) + local lnum = cursor[1] - 1 + local cursor_col = cursor[2] + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] + local server_start_boundary = nil + local items = {} + + local function on_done() + local mode = api.nvim_get_mode()['mode'] + if mode == 'i' or mode == 'ic' then + vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) + end + end + + local util = vim.lsp.util + for _, client in ipairs(clients) do + local params = util.make_position_params(win, client.offset_encoding) + client.request(ms.textDocument_completion, params, function(err, result) + if err then + lsp.log.warn(err.message) + end + if result and vim.fn.mode() == 'i' then + local matches + matches, server_start_boundary = M._convert_results( + line, + lnum, + cursor_col, + client.id, + client_start_boundary, + server_start_boundary, + result, + client.offset_encoding + ) + vim.list_extend(items, matches) + end + remaining = remaining - 1 + if remaining == 0 then + vim.schedule(on_done) + end + end, bufnr) + end + + -- Return -2 to signal that we should continue completion so that we can + -- async complete. + return -2 +end + +--- @param clients table +--- @param bufnr integer +--- @param win integer +--- @param callback fun(responses: table) +--- @return function # Cancellation function +local function request(clients, bufnr, win, callback) + local responses = {} --- @type table + local request_ids = {} --- @type table + local remaining_requests = vim.tbl_count(clients) + + for client_id, client in pairs(clients) do + local params = lsp.util.make_position_params(win, client.offset_encoding) + local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result) + responses[client_id] = { err = err, result = result } + remaining_requests = remaining_requests - 1 + if remaining_requests == 0 then + callback(responses) + end + end, bufnr) + + if ok then + request_ids[client_id] = request_id + end + end + + return function() + for client_id, request_id in pairs(request_ids) do + local client = lsp.get_client_by_id(client_id) + if client then + client.cancel_request(request_id) + end + end + end +end + +--- @param handle vim.lsp.completion.BufHandle +local function on_insert_char_pre(handle) + if tonumber(vim.fn.pumvisible()) == 1 then + if Context.isIncomplete then + reset_timer() + + local debounce_ms = next_debounce() + if debounce_ms == 0 then + vim.schedule(M.trigger) + else + completion_timer = new_timer() + completion_timer:start(debounce_ms, 0, vim.schedule_wrap(M.trigger)) + end + end + + return + end + + local char = api.nvim_get_vvar('char') + if not completion_timer and handle.triggers[char] then + completion_timer = assert(vim.uv.new_timer()) + completion_timer:start(25, 0, function() + reset_timer() + vim.schedule(M.trigger) + end) + end +end + +local function on_insert_leave() + reset_timer() + Context.cursor = nil + Context:reset() +end + +local function on_complete_done() + local completed_item = api.nvim_get_vvar('completed_item') + if not completed_item or not completed_item.user_data or not completed_item.user_data.nvim then + Context:reset() + return + end + + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(0)) --- @type integer, integer + cursor_row = cursor_row - 1 + local completion_item = completed_item.user_data.nvim.lsp.completion_item --- @type lsp.CompletionItem + local client_id = completed_item.user_data.nvim.lsp.client_id --- @type integer + if not completion_item or not client_id then + Context:reset() + return + end + + local bufnr = api.nvim_get_current_buf() + local expand_snippet = completion_item.insertTextFormat == protocol.InsertTextFormat.Snippet + and (completion_item.textEdit ~= nil or completion_item.insertText ~= nil) + + Context:reset() + + local client = lsp.get_client_by_id(client_id) + if not client then + return + end + + local offset_encoding = client.offset_encoding or 'utf-16' + local resolve_provider = (client.server_capabilities.completionProvider or {}).resolveProvider + + local function clear_word() + if not expand_snippet then + return nil + end + + -- Remove the already inserted word. + local start_char = cursor_col - #completed_item.word + local line = api.nvim_buf_get_lines(bufnr, cursor_row, cursor_row + 1, true)[1] + api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, #line, { '' }) + return line:sub(cursor_col + 1) + end + + --- @param suffix? string + local function apply_snippet_and_command(suffix) + if expand_snippet then + apply_snippet(completion_item, suffix) + end + + local command = completion_item.command + if command then + client:_exec_cmd(command, { bufnr = bufnr }, nil, function() + vim.lsp.log.warn( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + client.name, + command.command + ) + ) + end) + end + end + + if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then + local suffix = clear_word() + lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, offset_encoding) + apply_snippet_and_command(suffix) + elseif resolve_provider and type(completion_item) == 'table' then + local changedtick = vim.b[bufnr].changedtick + + --- @param result lsp.CompletionItem + client.request(ms.completionItem_resolve, completion_item, function(err, result) + if changedtick ~= vim.b[bufnr].changedtick then + return + end + + local suffix = clear_word() + if err then + vim.notify_once(err.message, vim.log.levels.WARN) + elseif result and result.additionalTextEdits then + lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, offset_encoding) + if result.command then + completion_item.command = result.command + end + end + + apply_snippet_and_command(suffix) + end, bufnr) + else + local suffix = clear_word() + apply_snippet_and_command(suffix) + end +end + +--- @class vim.lsp.completion.BufferOpts +--- @field autotrigger? boolean Whether to trigger completion automatically. Default: false + +--- @param client_id integer +---@param bufnr integer +---@param opts vim.lsp.completion.BufferOpts +local function enable_completions(client_id, bufnr, opts) + if not buf_handles[bufnr] then + buf_handles[bufnr] = { clients = {}, triggers = {} } + + -- Attach to buffer events. + api.nvim_buf_attach(bufnr, false, { + on_detach = function(_, buf) + buf_handles[buf] = nil + end, + on_reload = function(_, buf) + M.enable(true, client_id, buf, opts) + end, + }) + + -- Set up autocommands. + local group = + api.nvim_create_augroup(string.format('vim/lsp/completion-%d', bufnr), { clear = true }) + api.nvim_create_autocmd('CompleteDone', { + group = group, + buffer = bufnr, + callback = function() + local reason = api.nvim_get_vvar('event').reason --- @type string + if reason == 'accept' then + on_complete_done() + end + end, + }) + if opts.autotrigger then + api.nvim_create_autocmd('InsertCharPre', { + group = group, + buffer = bufnr, + callback = function() + on_insert_char_pre(buf_handles[bufnr]) + end, + }) + api.nvim_create_autocmd('InsertLeave', { + group = group, + buffer = bufnr, + callback = on_insert_leave, + }) + end + end + + if not buf_handles[bufnr].clients[client_id] then + local client = lsp.get_client_by_id(client_id) + assert(client, 'invalid client ID') + + -- Add the new client to the buffer's clients. + buf_handles[bufnr].clients[client_id] = client + + -- Add the new client to the clients that should be triggered by its trigger characters. + --- @type string[] + local triggers = vim.tbl_get( + client.server_capabilities, + 'completionProvider', + 'triggerCharacters' + ) or {} + for _, char in ipairs(triggers) do + local clients_for_trigger = buf_handles[bufnr].triggers[char] + if not clients_for_trigger then + clients_for_trigger = {} + buf_handles[bufnr].triggers[char] = clients_for_trigger + end + local client_exists = vim.iter(clients_for_trigger):any(function(c) + return c.id == client_id + end) + if not client_exists then + table.insert(clients_for_trigger, client) + end + end + end +end + +--- @param client_id integer +--- @param bufnr integer +local function disable_completions(client_id, bufnr) + local handle = buf_handles[bufnr] + if not handle then + return + end + + handle.clients[client_id] = nil + if not next(handle.clients) then + buf_handles[bufnr] = nil + api.nvim_del_augroup_by_name(string.format('vim/lsp/completion-%d', bufnr)) + else + for char, clients in pairs(handle.triggers) do + --- @param c vim.lsp.Client + handle.triggers[char] = vim.tbl_filter(function(c) + return c.id ~= client_id + end, clients) + end + end +end + +--- Enables or disables completions from the given language client in the given buffer. +--- +--- @param enable boolean True to enable, false to disable +--- @param client_id integer Client ID +--- @param bufnr integer Buffer handle, or 0 for the current buffer +--- @param opts? vim.lsp.completion.BufferOpts +function M.enable(enable, client_id, bufnr, opts) + bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr + + if enable then + enable_completions(client_id, bufnr, opts or {}) + else + disable_completions(client_id, bufnr) + end +end + +--- Trigger LSP completion in the current buffer. +function M.trigger() + reset_timer() + Context:cancel_pending() + + local win = api.nvim_get_current_win() + local bufnr = api.nvim_get_current_buf() + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local clients = (buf_handles[bufnr] or {}).clients or {} + local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') + local start_time = vim.uv.hrtime() + Context.last_request_time = start_time + + local cancel_request = request(clients, bufnr, win, function(responses) + local end_time = vim.uv.hrtime() + rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) + + Context.pending_requests = {} + Context.isIncomplete = false + + local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row + local mode = api.nvim_get_mode().mode + if row_changed or not (mode == 'i' or mode == 'ic') then + return + end + + local matches = {} + local server_start_boundary --- @type integer? + for client_id, response in pairs(responses) do + if response.err then + vim.notify_once(response.err.message, vim.log.levels.warn) + end + + local result = response.result + if result then + Context.isIncomplete = Context.isIncomplete or result.isIncomplete + local client = lsp.get_client_by_id(client_id) + local encoding = client and client.offset_encoding or 'utf-16' + local client_matches + client_matches, server_start_boundary = M._convert_results( + line, + cursor_row - 1, + cursor_col, + client_id, + word_boundary, + nil, + result, + encoding + ) + vim.list_extend(matches, client_matches) + end + end + local start_col = (server_start_boundary or word_boundary) + 1 + vim.fn.complete(start_col, matches) + end) + + table.insert(Context.pending_requests, cancel_request) +end + +return M diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index f9d394642c..38c43893eb 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -3,7 +3,7 @@ local protocol = require('vim.lsp.protocol') local ms = protocol.Methods local util = require('vim.lsp.util') local api = vim.api -local completion = require('vim.lsp._completion') +local completion = require('vim.lsp.completion') --- @type table local M = {} diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 419c2ff644..8ac4cc794b 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -738,14 +738,16 @@ function protocol.make_client_capabilities() completion = { dynamicRegistration = false, completionItem = { - -- Until we can actually expand snippet, move cursor and allow for true snippet experience, - -- this should be disabled out of the box. - -- However, users can turn this back on if they have a snippet plugin. - snippetSupport = false, + snippetSupport = true, commitCharactersSupport = false, preselectSupport = false, deprecatedSupport = false, documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, + resolveSupport = { + properties = { + 'additionalTextEdits', + }, + }, }, completionItemKind = { valueSet = get_value_set(constants.CompletionItemKind), -- cgit From 90a4b1a59cf0c204cb39ec7789ab8783626e449d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 28 May 2024 03:07:13 -0700 Subject: refactor: deprecate vim.region() #28416 Problem: `vim.region()` is redundant with `getregionpos()`. Solution: Deprecate `vim.region()`. --- runtime/lua/vim/_editor.lua | 3 +++ runtime/lua/vim/lsp/buf.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 5e9be509c8..9f952db4fc 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -494,6 +494,7 @@ do vim.t = make_dict_accessor('t') end +--- @deprecated --- Gets a dict of line segment ("chunk") positions for the region from `pos1` to `pos2`. --- --- Input and output positions are byte positions, (0,0)-indexed. "End of line" column @@ -507,6 +508,8 @@ end ---@return table region Dict of the form `{linenr = {startcol,endcol}}`. `endcol` is exclusive, and ---whole lines are returned as `{startcol,endcol} = {0,-1}`. function vim.region(bufnr, pos1, pos2, regtype, inclusive) + vim.deprecate('vim.region', 'vim.fn.getregionpos()', '0.13') + if not vim.api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 49833eaeec..299b68e134 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -135,7 +135,7 @@ end ---@param mode "v"|"V" ---@return table {start={row,col}, end={row,col}} using (1, 0) indexing local function range_from_selection(bufnr, mode) - -- TODO: Use `vim.region()` instead https://github.com/neovim/neovim/pull/13896 + -- TODO: Use `vim.fn.getregionpos()` instead. -- [bufnum, lnum, col, off]; both row and column 1-indexed local start = vim.fn.getpos('v') -- cgit From 8ba73f0e4cc6c82032a348a1d6c8d794ed150fd7 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 08:51:44 -0500 Subject: feat(diagnostic): add vim.diagnostic.jump() (#26745) Deprecate vim.diagnostic.goto_prev() and vim.diagnostic.goto_next() in favor of a unified vim.diagnostic.jump() interface. We cannot name the function "goto()" because some of our tooling (luacheck and stylua) fail to parse it, presumably because "goto" is a keyword in newer versions of Lua. vim.diagnostic.jump() also allows moving to a specific diagnostic and moving by multiple diagnostics at a time (useful for creating mappings that use v:count). --- runtime/lua/vim/diagnostic.lua | 193 ++++++++++++++++++++++++++++++----------- 1 file changed, 142 insertions(+), 51 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 348204abb7..8e68e9608a 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -835,21 +835,36 @@ local function filter_highest(diagnostics) end end ---- @param position {[1]: integer, [2]: integer} --- @param search_forward boolean ---- @param bufnr integer ---- @param opts vim.diagnostic.GotoOpts ---- @param namespace integer[]|integer +--- @param opts vim.diagnostic.JumpOpts? --- @return vim.Diagnostic? -local function next_diagnostic(position, search_forward, bufnr, opts, namespace) +local function next_diagnostic(search_forward, opts) + opts = opts or {} + + -- Support deprecated win_id alias + if opts.win_id then + vim.deprecate('opts.win_id', 'opts.winid', '0.13') + opts.winid = opts.win_id + opts.win_id = nil + end + + -- Support deprecated cursor_position alias + if opts.cursor_position then + vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') + opts.pos = opts.cursor_position + opts.cursor_position = nil + end + + local winid = opts.winid or api.nvim_get_current_win() + local bufnr = api.nvim_win_get_buf(winid) + local position = opts.pos or api.nvim_win_get_cursor(winid) + + -- Adjust row to be 0-indexed position[1] = position[1] - 1 - bufnr = get_bufnr(bufnr) - local wrap = if_nil(opts.wrap, true) - local get_opts = vim.deepcopy(opts) - get_opts.namespace = get_opts.namespace or namespace + local wrap = if_nil(opts.wrap, true) - local diagnostics = get_diagnostics(bufnr, get_opts, true) + local diagnostics = get_diagnostics(bufnr, opts, true) if opts._highest then filter_highest(diagnostics) @@ -902,32 +917,41 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) end end ---- @param opts vim.diagnostic.GotoOpts? ---- @param pos {[1]:integer,[2]:integer}|false -local function diagnostic_move_pos(opts, pos) - opts = opts or {} - - local float = if_nil(opts.float, true) - local win_id = opts.win_id or api.nvim_get_current_win() - - if not pos then +--- Move the cursor to the given diagnostic. +--- +--- @param diagnostic vim.Diagnostic? +--- @param opts vim.diagnostic.JumpOpts? +local function goto_diagnostic(diagnostic, opts) + if not diagnostic then api.nvim_echo({ { 'No more valid diagnostics to move to', 'WarningMsg' } }, true, {}) return end - api.nvim_win_call(win_id, function() + opts = opts or {} + + -- Support deprecated win_id alias + if opts.win_id then + vim.deprecate('opts.win_id', 'opts.winid', '0.13') + opts.winid = opts.win_id + opts.win_id = nil + end + + local winid = opts.winid or api.nvim_get_current_win() + + api.nvim_win_call(winid, function() -- Save position in the window's jumplist vim.cmd("normal! m'") - api.nvim_win_set_cursor(win_id, { pos[1] + 1, pos[2] }) + api.nvim_win_set_cursor(winid, { diagnostic.lnum + 1, diagnostic.col }) -- Open folds under the cursor vim.cmd('normal! zv') end) + local float = if_nil(opts.float, true) if float then local float_opts = type(float) == 'table' and float or {} vim.schedule(function() M.open_float(vim.tbl_extend('keep', float_opts, { - bufnr = api.nvim_win_get_buf(win_id), + bufnr = api.nvim_win_get_buf(winid), scope = 'cursor', focus = false, })) @@ -1114,24 +1138,24 @@ end --- Get the previous diagnostic closest to the cursor position. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return vim.Diagnostic? : Previous diagnostic function M.get_prev(opts) - opts = opts or {} - - local win_id = opts.win_id or api.nvim_get_current_win() - local bufnr = api.nvim_win_get_buf(win_id) - local cursor_position = opts.cursor_position or api.nvim_win_get_cursor(win_id) - - return next_diagnostic(cursor_position, false, bufnr, opts, opts.namespace) + return next_diagnostic(false, opts) end --- Return the position of the previous diagnostic in the current buffer. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return table|false: Previous diagnostic position as a `(row, col)` tuple --- or `false` if there is no prior diagnostic. +---@deprecated function M.get_prev_pos(opts) + vim.deprecate( + 'vim.diagnostic.get_prev_pos()', + 'access the lnum and col fields from get_prev() instead', + '0.13' + ) local prev = M.get_prev(opts) if not prev then return false @@ -1141,31 +1165,33 @@ function M.get_prev_pos(opts) end --- Move to the previous diagnostic in the current buffer. ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts +---@deprecated function M.goto_prev(opts) - return diagnostic_move_pos(opts, M.get_prev_pos(opts)) + vim.deprecate('vim.diagnostic.goto_prev()', 'vim.diagnostic.jump()', '0.13') + goto_diagnostic(M.get_prev(opts), opts) end --- Get the next diagnostic closest to the cursor position. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return vim.Diagnostic? : Next diagnostic function M.get_next(opts) - opts = opts or {} - - local win_id = opts.win_id or api.nvim_get_current_win() - local bufnr = api.nvim_win_get_buf(win_id) - local cursor_position = opts.cursor_position or api.nvim_win_get_cursor(win_id) - - return next_diagnostic(cursor_position, true, bufnr, opts, opts.namespace) + return next_diagnostic(true, opts) end --- Return the position of the next diagnostic in the current buffer. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return table|false : Next diagnostic position as a `(row, col)` tuple or false if no next --- diagnostic. +---@deprecated function M.get_next_pos(opts) + vim.deprecate( + 'vim.diagnostic.get_next_pos()', + 'access the lnum and col fields from get_next() instead', + '0.13' + ) local next = M.get_next(opts) if not next then return false @@ -1187,12 +1213,21 @@ end --- @field severity? vim.diagnostic.SeverityFilter --- Configuration table with the following keys: ---- @class vim.diagnostic.GotoOpts : vim.diagnostic.GetOpts +--- @class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts +--- +--- The diagnostic to jump to. Mutually exclusive with {count}, {namespace}, +--- and {severity}. +--- @field diagnostic? vim.Diagnostic +--- +--- The number of diagnostics to move by, starting from {pos}. A positive +--- integer moves forward by {count} diagnostics, while a negative integer moves +--- backward by {count} diagnostics. Mutually exclusive with {diagnostic}. +--- @field count? integer --- ---- Cursor position as a `(row, col)` tuple. ---- See |nvim_win_get_cursor()|. ---- (default: current cursor position) ---- @field cursor_position? {[1]:integer,[2]:integer} +--- Cursor position as a `(row, col)` tuple. See |nvim_win_get_cursor()|. Used +--- to find the nearest diagnostic when {count} is used. Only used when {count} +--- is non-nil. Default is the current cursor position. +--- @field pos? {[1]:integer,[2]:integer} --- --- Whether to loop around file or not. Similar to 'wrapscan'. --- (default: `true`) @@ -1214,13 +1249,69 @@ end --- --- Window ID --- (default: `0`) ---- @field win_id? integer +--- @field winid? integer + +--- Move to a diagnostic. +--- +--- @param opts vim.diagnostic.JumpOpts +--- @return vim.Diagnostic? # The diagnostic that was moved to. +function M.jump(opts) + -- One of "diagnostic" or "count" must be provided + assert( + opts.diagnostic or opts.count, + 'One of "diagnostic" or "count" must be specified in the options to vim.diagnostic.jump()' + ) + + if opts.diagnostic then + goto_diagnostic(opts.diagnostic, opts) + return opts.diagnostic + end + + local count = opts.count + if count == 0 then + return nil + end + + -- Support deprecated cursor_position alias + if opts.cursor_position then + vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') + opts.pos = opts.cursor_position + opts.cursor_position = nil + end + + -- Copy the opts table so that we can modify it + local opts_ = vim.deepcopy(opts, true) + + local diag = nil + while count ~= 0 do + local next = next_diagnostic(count > 0, opts_) + if not next then + break + end + + -- Update cursor position + opts_.pos = { next.lnum + 1, next.col } + + if count > 0 then + count = count - 1 + else + count = count + 1 + end + diag = next + end + + goto_diagnostic(diag, opts) + + return diag +end --- Move to the next diagnostic. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts +---@deprecated function M.goto_next(opts) - diagnostic_move_pos(opts, M.get_next_pos(opts)) + vim.deprecate('vim.diagnostic.goto_next()', 'vim.diagnostic.jump()', '0.13') + goto_diagnostic(M.get_next(opts), opts) end M.handlers.signs = { @@ -1688,7 +1779,7 @@ end --- ---@param opts vim.diagnostic.Opts.Float? ---@return integer? float_bufnr ----@return integer? win_id +---@return integer? winid function M.open_float(opts, ...) -- Support old (bufnr, opts) signature local bufnr --- @type integer? -- cgit From e6cfcaed184d4ecdc8a8638429e1bd9e1b3251dc Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 25 May 2024 10:23:05 -0700 Subject: feat(snippet): add default keymaps during snippet session --- runtime/lua/vim/snippet.lua | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3d8f73f362..1ec5235d7b 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -2,6 +2,8 @@ local G = vim.lsp._snippet_grammar local snippet_group = vim.api.nvim_create_augroup('vim/snippet', {}) local snippet_ns = vim.api.nvim_create_namespace('vim/snippet') local hl_group = 'SnippetTabstop' +local jump_forward_key = '' +local jump_backward_key = '' --- Returns the 0-based cursor position. --- @@ -182,6 +184,8 @@ end --- @field extmark_id integer --- @field tabstops table --- @field current_tabstop vim.snippet.Tabstop +--- @field tab_keymaps { i: table?, s: table? } +--- @field shift_tab_keymaps { i: table?, s: table? } local Session = {} --- Creates a new snippet session in the current buffer. @@ -197,6 +201,8 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) extmark_id = snippet_extmark, tabstops = {}, current_tabstop = Tabstop.new(0, bufnr, { 0, 0, 0, 0 }), + tab_keymaps = { i = nil, s = nil }, + shift_tab_keymaps = { i = nil, s = nil }, }, { __index = Session }) -- Create the tabstops. @@ -207,9 +213,64 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) end end + self:set_keymaps() + return self end +--- Sets the snippet navigation keymaps. +--- +--- @package +function Session:set_keymaps() + local function maparg(key, mode) + local map = vim.fn.maparg(key, mode, false, true) --[[ @as table ]] + if not vim.tbl_isempty(map) and map.buffer == 1 then + return map + else + return nil + end + end + + local function set(jump_key, direction) + vim.keymap.set({ 'i', 's' }, jump_key, function() + return vim.snippet.active({ direction = direction }) + and 'lua vim.snippet.jump(' .. direction .. ')' + or jump_key + end, { expr = true, silent = true, buffer = self.bufnr }) + end + + self.tab_keymaps = { + i = maparg(jump_forward_key, 'i'), + s = maparg(jump_forward_key, 's'), + } + self.shift_tab_keymaps = { + i = maparg(jump_backward_key, 'i'), + s = maparg(jump_backward_key, 's'), + } + set(jump_forward_key, 1) + set(jump_backward_key, -1) +end + +--- Restores/deletes the keymaps used for snippet navigation. +--- +--- @package +function Session:restore_keymaps() + local function restore(keymap, lhs, mode) + if keymap then + vim.api.nvim_buf_call(self.bufnr, function() + vim.fn.mapset(keymap) + end) + else + vim.api.nvim_buf_del_keymap(self.bufnr, mode, lhs) + end + end + + restore(self.tab_keymaps.i, jump_forward_key, 'i') + restore(self.tab_keymaps.s, jump_forward_key, 's') + restore(self.shift_tab_keymaps.i, jump_backward_key, 'i') + restore(self.shift_tab_keymaps.s, jump_backward_key, 's') +end + --- Returns the destination tabstop index when jumping in the given direction. --- --- @package @@ -619,6 +680,8 @@ function M.stop() return end + M._session:restore_keymaps() + vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._session.bufnr }) vim.api.nvim_buf_clear_namespace(M._session.bufnr, snippet_ns, 0, -1) -- cgit From 1c6d9200521acb2329be55ab8bec3056deade66a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 13:24:16 -0500 Subject: feat(defaults): use vim.diagnostic.jump() for default mappings (#29066) This allows the mappings to work with a count and also enables new ]D and [D mappings to go to the last/first diagnostic in the buffer. --- runtime/lua/vim/_defaults.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 5b964b84a0..26d8729029 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -180,12 +180,20 @@ do --- See |[d-default|, |]d-default|, and |CTRL-W_d-default|. do vim.keymap.set('n', ']d', function() - vim.diagnostic.goto_next({ float = false }) - end, { desc = 'Jump to the next diagnostic' }) + vim.diagnostic.jump({ count = vim.v.count1, float = false }) + end, { desc = 'Jump to the next diagnostic in the current buffer' }) vim.keymap.set('n', '[d', function() - vim.diagnostic.goto_prev({ float = false }) - end, { desc = 'Jump to the previous diagnostic' }) + vim.diagnostic.jump({ count = -vim.v.count1, float = false }) + end, { desc = 'Jump to the previous diagnostic in the current buffer' }) + + vim.keymap.set('n', ']D', function() + vim.diagnostic.jump({ count = math.huge, wrap = false, float = false }) + end, { desc = 'Jump to the last diagnostic in the current buffer' }) + + vim.keymap.set('n', '[D', function() + vim.diagnostic.jump({ count = -math.huge, wrap = false, float = false }) + end, { desc = 'Jump to the first diagnostic in the current buffer' }) vim.keymap.set('n', 'd', function() vim.diagnostic.open_float() -- cgit From efa45832ea02e777ce3f5556ef3cd959c164ec24 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 14:54:50 -0500 Subject: feat: add "jump" options to vim.diagnostic.config() (#29067) Problem: There is no easy way to configure the behavior of the default diagnostic "jump" mappings. For example, some users way want to show the floating window, and some may not (likewise, some way want to only move between warnings/errors, or disable the "wrap" parameter). Solution: Add a "jump" table to vim.diagnostic.config() that sets default values for vim.diagnostic.jump(). Alternatives: Users can override the default mappings to use the exact options to vim.diagnostic.jump() that they want, but this has a couple issues: - While the default mappings are not complicated, they are also not trivial, so overriding them requires users to understand implementation details (specifically things like setting "count" properly). - If plugins want to change the default mappings, or configure the behavior in any way (e.g. floating window display), it becomes even harder for users to tweak specific behavior. vim.diagnostic.config() already works quite well as the "entry point" for tuning knobs with diagnostic UI elements, so this fits in nicely and composes well with existing mental models and idioms. --- runtime/lua/vim/_defaults.lua | 8 ++++---- runtime/lua/vim/diagnostic.lua | 41 ++++++++++++++++++++++++++++++++++------- runtime/lua/vim/shared.lua | 2 +- 3 files changed, 39 insertions(+), 12 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 26d8729029..79fe5a8513 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -180,19 +180,19 @@ do --- See |[d-default|, |]d-default|, and |CTRL-W_d-default|. do vim.keymap.set('n', ']d', function() - vim.diagnostic.jump({ count = vim.v.count1, float = false }) + vim.diagnostic.jump({ count = vim.v.count1 }) end, { desc = 'Jump to the next diagnostic in the current buffer' }) vim.keymap.set('n', '[d', function() - vim.diagnostic.jump({ count = -vim.v.count1, float = false }) + vim.diagnostic.jump({ count = -vim.v.count1 }) end, { desc = 'Jump to the previous diagnostic in the current buffer' }) vim.keymap.set('n', ']D', function() - vim.diagnostic.jump({ count = math.huge, wrap = false, float = false }) + vim.diagnostic.jump({ count = math.huge, wrap = false }) end, { desc = 'Jump to the last diagnostic in the current buffer' }) vim.keymap.set('n', '[D', function() - vim.diagnostic.jump({ count = -math.huge, wrap = false, float = false }) + vim.diagnostic.jump({ count = -math.huge, wrap = false }) end, { desc = 'Jump to the first diagnostic in the current buffer' }) vim.keymap.set('n', 'd', function() diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 8e68e9608a..dca7698356 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -42,7 +42,7 @@ local M = {} --- --- @field namespace? integer ---- Each of the configuration options below accepts one of the following: +--- Many of the configuration options below accept one of the following: --- - `false`: Disable this feature --- - `true`: Enable this feature, use default settings. --- - `table`: Enable this feature with overrides. Use an empty table to use default values. @@ -78,6 +78,9 @@ local M = {} --- - {reverse}? (boolean) Reverse sort order --- (default: `false`) --- @field severity_sort? boolean|{reverse?:boolean} +--- +--- Default values for |vim.diagnostic.jump()|. See |vim.diagnostic.Opts.Jump|. +--- @field jump? vim.diagnostic.Opts.Jump --- @class (private) vim.diagnostic.OptsResolved --- @field float vim.diagnostic.Opts.Float @@ -241,6 +244,20 @@ local M = {} --- whole line the sign is placed in. --- @field linehl? table +--- @class vim.diagnostic.Opts.Jump +--- +--- Default value of the {float} parameter of |vim.diagnostic.jump()|. +--- @field float? boolean|vim.diagnostic.Opts.Float +--- +--- Default value of the {wrap} parameter of |vim.diagnostic.jump()|. +--- @field wrap? boolean +--- +--- Default value of the {severity} parameter of |vim.diagnostic.jump()|. +--- @field severity? vim.diagnostic.SeverityFilter +--- +--- Default value of the {_highest} parameter of |vim.diagnostic.jump()|. +--- @field package _highest? boolean + -- TODO: inherit from `vim.diagnostic.Opts`, implement its fields. --- Optional filters |kwargs|, or `nil` for all. --- @class vim.diagnostic.Filter @@ -284,6 +301,13 @@ local global_diagnostic_options = { float = true, update_in_insert = false, severity_sort = false, + jump = { + -- Do not show floating window + float = false, + + -- Wrap around buffer + wrap = true, + }, } --- @class (private) vim.diagnostic.Handler @@ -1212,7 +1236,8 @@ end --- See |diagnostic-severity|. --- @field severity? vim.diagnostic.SeverityFilter ---- Configuration table with the following keys: +--- Configuration table with the keys listed below. Some parameters can have their default values +--- changed with |vim.diagnostic.config()|. --- @class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts --- --- The diagnostic to jump to. Mutually exclusive with {count}, {namespace}, @@ -1256,12 +1281,17 @@ end --- @param opts vim.diagnostic.JumpOpts --- @return vim.Diagnostic? # The diagnostic that was moved to. function M.jump(opts) + vim.validate('opts', opts, 'table') + -- One of "diagnostic" or "count" must be provided assert( opts.diagnostic or opts.count, 'One of "diagnostic" or "count" must be specified in the options to vim.diagnostic.jump()' ) + -- Apply configuration options from vim.diagnostic.config() + opts = vim.tbl_deep_extend('keep', opts, global_diagnostic_options.jump) + if opts.diagnostic then goto_diagnostic(opts.diagnostic, opts) return opts.diagnostic @@ -1279,18 +1309,15 @@ function M.jump(opts) opts.cursor_position = nil end - -- Copy the opts table so that we can modify it - local opts_ = vim.deepcopy(opts, true) - local diag = nil while count ~= 0 do - local next = next_diagnostic(count > 0, opts_) + local next = next_diagnostic(count > 0, opts) if not next then break end -- Update cursor position - opts_.pos = { next.lnum + 1, next.col } + opts.pos = { next.lnum + 1, next.col } if count > 0 then count = count - 1 diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 2641d1feb0..0ec79e1dc7 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -379,7 +379,7 @@ local function tbl_extend(behavior, deep_extend, ...) for i = 1, select('#', ...) do local tbl = select(i, ...) - vim.validate({ ['after the second argument'] = { tbl, 't' } }) + vim.validate('after the second argument', tbl, 'table') --- @cast tbl table if tbl then for k, v in pairs(tbl) do -- cgit From 025c87441502cf570bad7b71f40bc6fe88989297 Mon Sep 17 00:00:00 2001 From: crwebb85 <51029315+crwebb85@users.noreply.github.com> Date: Thu, 30 May 2024 02:59:23 -0400 Subject: fix(lsp): clear lsp client diagnostics (#29050) Problem: When an lsp client is stopped, the client will only clear the diagnostics for the attached buffers but not the unattached buffers. Solution: Reset the diagnostics for the whole namespace rather than for only the attached buffers. --- runtime/lua/vim/lsp.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 94c31359da..96dbf97146 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -391,8 +391,8 @@ end local function on_client_exit(code, signal, client_id) local client = all_clients[client_id] - for bufnr in pairs(client.attached_buffers) do - vim.schedule(function() + vim.schedule(function() + for bufnr in pairs(client.attached_buffers) do if client and client.attached_buffers[bufnr] then api.nvim_exec_autocmds('LspDetach', { buffer = bufnr, @@ -401,15 +401,16 @@ local function on_client_exit(code, signal, client_id) }) end - local namespace = vim.lsp.diagnostic.get_namespace(client_id) - vim.diagnostic.reset(namespace, bufnr) client.attached_buffers[bufnr] = nil if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then reset_defaults(bufnr) end - end) - end + end + + local namespace = vim.lsp.diagnostic.get_namespace(client_id) + vim.diagnostic.reset(namespace) + end) local name = client.name or 'unknown' -- cgit From 0df2c6b5d09fab392dd1a14e4b2e6a3b03203aaa Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 28 May 2024 21:37:46 +0200 Subject: feat(lsp): use fuzzy match on filterText instead of prefix match The `complete()` mechanism matches completion candidates against the typed text, so strict pre-filtering isn't necessary. This is a first step towards supporting postfix snippets (like `items@insert` in luals) --- runtime/lua/vim/lsp/completion.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 25b3d53c8c..f9b0563b86 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -201,11 +201,17 @@ function M._lsp_to_complete_items(result, prefix, client_id) return {} end - local function matches_prefix(item) - return vim.startswith(get_completion_word(item), prefix) - end + if prefix ~= '' then + ---@param item lsp.CompletionItem + local function match_prefix(item) + if item.filterText then + return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) + end + return true + end - items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] + items = vim.tbl_filter(match_prefix, items) --[[@as lsp.CompletionItem[]|]] + end table.sort(items, function(a, b) return (a.sortText or a.label) < (b.sortText or b.label) end) -- cgit From b2bad0ac91ddb9b33c3547b6fd4f7278794818d9 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 28 May 2024 23:20:25 +0200 Subject: feat(lsp): support postfix snippets in completion --- runtime/lua/vim/lsp/completion.lua | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index f9b0563b86..39c0c5fa29 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -129,18 +129,33 @@ end --- @param item lsp.CompletionItem --- @return string local function get_completion_word(item) - if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.textEdit.newText - else - return parse_snippet(item.textEdit.newText) - end - elseif item.insertText ~= nil and item.insertText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.insertText - else + if item.insertTextFormat == protocol.InsertTextFormat.Snippet then + if item.textEdit then + -- Use label instead of text if text has different starting characters. + -- label is used as abbr (=displayed), but word is used for filtering + -- This is required for things like postfix completion. + -- E.g. in lua: + -- + -- local f = {} + -- f@| + -- ▲ + -- └─ cursor + -- + -- item.textEdit.newText: table.insert(f, $0) + -- label: insert + -- + -- Typing `i` would remove the candidate because newText starts with `t`. + local text = item.insertText or item.textEdit.newText + return #text < #item.label and text or item.label + elseif item.insertText and item.insertText ~= '' then return parse_snippet(item.insertText) + else + return item.label end + elseif item.textEdit then + return item.textEdit.newText + elseif item.insertText and item.insertText ~= '' then + return item.insertText end return item.label end -- cgit From 5c33815448e11b514678f39cecc74e68131d4628 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 30 May 2024 10:46:26 +0200 Subject: refactor(lsp): replace util.buf_versions with changedtick (#28943) `lsp.util.buf_versions` was already derived from changedtick (`on_lines` from `buf_attach` synced the version) As far as I can tell there is no need to keep track of the state in a separate table. --- runtime/lua/vim/lsp.lua | 5 +---- runtime/lua/vim/lsp/_changetracking.lua | 3 +-- runtime/lua/vim/lsp/client.lua | 5 ++--- runtime/lua/vim/lsp/inlay_hint.lua | 4 ++-- runtime/lua/vim/lsp/semantic_tokens.lua | 6 +++--- runtime/lua/vim/lsp/util.lua | 16 +++++++++++----- 6 files changed, 20 insertions(+), 19 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 96dbf97146..c2deac0113 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -484,7 +484,6 @@ local function text_document_did_save_handler(bufnr) text = lsp._buf_get_full_text(bufnr), }, }) - util.buf_versions[bufnr] = 0 end local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save') if save_capability then @@ -520,7 +519,6 @@ local function buf_detach_client(bufnr, client) end client.attached_buffers[bufnr] = nil - util.buf_versions[bufnr] = nil local namespace = lsp.diagnostic.get_namespace(client.id) vim.diagnostic.reset(namespace, bufnr) @@ -576,12 +574,11 @@ local function buf_attach(bufnr) }) -- First time, so attach and set up stuff. api.nvim_buf_attach(bufnr, false, { - on_lines = function(_, _, changedtick, firstline, lastline, new_lastline) + on_lines = function(_, _, _, firstline, lastline, new_lastline) if #lsp.get_clients({ bufnr = bufnr }) == 0 then -- detach if there are no clients return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 end - util.buf_versions[bufnr] = changedtick changetracking.send_changes(bufnr, firstline, lastline, new_lastline) end, diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua index b2be53269f..ce701f0772 100644 --- a/runtime/lua/vim/lsp/_changetracking.lua +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -1,6 +1,5 @@ local protocol = require('vim.lsp.protocol') local sync = require('vim.lsp.sync') -local util = require('vim.lsp.util') local api = vim.api local uv = vim.uv @@ -277,7 +276,7 @@ local function send_changes(bufnr, sync_kind, state, buf_state) client.notify(protocol.Methods.textDocument_didChange, { textDocument = { uri = uri, - version = util.buf_versions[bufnr], + version = vim.b[bufnr].changedtick, }, contentChanges = changes, }) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 327cd19125..b28fe2f797 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -673,8 +673,8 @@ function Client:_request(method, params, handler, bufnr) end -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state changetracking.flush(self, bufnr) - local version = lsp.util.buf_versions[bufnr] bufnr = resolve_bufnr(bufnr) + local version = vim.b[bufnr].changedtick log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) local success, request_id = self.rpc.request(method, params, function(err, result) local context = { @@ -922,14 +922,13 @@ function Client:_text_document_did_open_handler(bufnr) local params = { textDocument = { - version = 0, + version = vim.b[bufnr].changedtick, uri = vim.uri_from_bufnr(bufnr), languageId = self.get_language_id(bufnr, filetype), text = lsp._buf_get_full_text(bufnr), }, } self.notify(ms.textDocument_didOpen, params) - lsp.util.buf_versions[bufnr] = params.textDocument.version -- Next chance we get, we should re-do the diagnostics vim.schedule(function() diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index f98496456b..78f309abf7 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -43,7 +43,7 @@ function M.on_inlayhint(err, result, ctx, _) return end local bufnr = assert(ctx.bufnr) - if util.buf_versions[bufnr] ~= ctx.version then + if vim.b[bufnr].changedtick ~= ctx.version then return end local client_id = ctx.client_id @@ -324,7 +324,7 @@ api.nvim_set_decoration_provider(namespace, { return end - if bufstate.version ~= util.buf_versions[bufnr] then + if bufstate.version ~= vim.b[bufnr].changedtick then return end diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index ef2502b12e..278014a4ea 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -116,7 +116,7 @@ local function tokens_to_ranges(data, bufnr, client, request) if elapsed_ns > yield_interval_ns then vim.schedule(function() - coroutine.resume(co, util.buf_versions[bufnr]) + coroutine.resume(co, vim.b[bufnr].changedtick) end) if request.version ~= coroutine.yield() then -- request became stale since the last time the coroutine ran. @@ -275,7 +275,7 @@ end --- ---@package function STHighlighter:send_request() - local version = util.buf_versions[self.bufnr] + local version = vim.b[self.bufnr].changedtick self:reset_timer() @@ -418,7 +418,7 @@ end function STHighlighter:on_win(topline, botline) for client_id, state in pairs(self.client_state) do local current_result = state.current_result - if current_result.version and current_result.version == util.buf_versions[self.bufnr] then + if current_result.version and current_result.version == vim.b[self.bufnr].changedtick then if not current_result.namespace_cleared then api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) current_result.namespace_cleared = true diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0099e82f52..d1f0e97065 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -509,8 +509,7 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) and ( text_document.version and text_document.version > 0 - and M.buf_versions[bufnr] - and M.buf_versions[bufnr] > text_document.version + and vim.b[bufnr].changedtick > text_document.version ) then print('Buffer ', text_document.uri, ' newer than edits.') @@ -2200,9 +2199,16 @@ function M._refresh(method, opts) end end -M._get_line_byte_from_position = get_line_byte_from_position - ---@nodoc -M.buf_versions = {} ---@type table +---@deprecated +---@type table +M.buf_versions = setmetatable({}, { + __index = function(_, bufnr) + vim.deprecate('vim.lsp.util.buf_versions', 'vim.b.changedtick', '0.13') + return vim.b[bufnr].changedtick + end, +}) + +M._get_line_byte_from_position = get_line_byte_from_position return M -- cgit From 07af492f635c51d44d02d8012611cc5e11a4af19 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 31 May 2024 12:07:31 +0200 Subject: vim-patch:9.1.0453: filetype: rasi files are not recognized Problem: filetype: rasi files are not recognized Solution: regonize '*.rasi' files as rasi filetype, include a filetype and syntax plugin (Pierrick Guillaume) ported from: https://github.com/Fymyte/rasi.vim closes: vim/vim#14821 https://github.com/vim/vim/commit/280e5b13ca568ed592a894140bf1ac74356f4b33 Co-authored-by: Pierrick Guillaume --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2ab6cc6059..500632a2b2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -873,6 +873,7 @@ local extension = { t6 = 'raku', p6 = 'raku', raml = 'raml', + rasi = 'rasi', rbs = 'rbs', rego = 'rego', rem = 'remind', -- cgit From 6566a59b3a6c8dabfa40f8debd0de96d875825e9 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 31 May 2024 08:41:10 -0400 Subject: refactor(lsp): use predefined types in util function signatures (#29095) --- runtime/lua/vim/lsp/util.lua | 60 +++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 29 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d1f0e97065..b33f6ccf69 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -173,11 +173,11 @@ local _str_byteindex_enc = M._str_byteindex_enc --- CAUTION: Changes in-place! --- ---@deprecated ----@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 (table) list of strings to replace the original ----@return table The modified {lines} object +---@param lines string[] Original list of strings +---@param A [integer, integer] Start position; a 2-tuple of {line,col} numbers +---@param B [integer, integer] End position; a 2-tuple {line,col} numbers +---@param new_lines string[] list of strings to replace the original +---@return string[] The modified {lines} object function M.set_lines(lines, A, B, new_lines) vim.deprecate('vim.lsp.util.set_lines()', 'nil', '0.12') -- 0-indexing to 1-indexing @@ -343,7 +343,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding) end --- Applies a list of text edits to a buffer. ----@param text_edits table list of `TextEdit` objects +---@param text_edits lsp.TextEdit[] ---@param bufnr integer Buffer id ---@param offset_encoding string utf-8|utf-16|utf-32 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit @@ -481,8 +481,8 @@ end --- Applies a `TextDocumentEdit`, which is a list of changes to a single --- document. --- ----@param text_document_edit table: a `TextDocumentEdit` object ----@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) +---@param text_document_edit lsp.TextDocumentEdit +---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) ---@param offset_encoding? string ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit function M.apply_text_document_edit(text_document_edit, index, offset_encoding) @@ -533,6 +533,7 @@ local function path_under_prefix(path, prefix) end --- Get list of buffers whose filename matches the given path prefix (normalized full path) +---@param prefix string ---@return integer[] local function get_bufs_with_prefix(prefix) prefix = path_components(prefix) @@ -677,7 +678,7 @@ end --- Applies a `WorkspaceEdit`. --- ----@param workspace_edit table `WorkspaceEdit` +---@param workspace_edit lsp.WorkspaceEdit ---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) @@ -723,8 +724,8 @@ end --- Note that if the input is of type `MarkupContent` and its kind is `plaintext`, --- then the corresponding value is returned without further modifications. --- ----@param input (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent) ----@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}. +---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent +---@param contents string[]|nil List of strings to extend with converted lines. Defaults to {}. ---@return string[] 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) @@ -759,11 +760,11 @@ end --- Converts `textDocument/signatureHelp` response to markdown lines. --- ----@param signature_help table Response of `textDocument/SignatureHelp` +---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp` ---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block ---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets ----@return table|nil table list of lines of converted markdown. ----@return table|nil table of active hl +---@return string[]|nil table list of lines of converted markdown. +---@return number[]|nil table of active hl ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers) if not signature_help.signatures then @@ -960,7 +961,7 @@ end --- Shows document and optionally jumps to the location. --- ----@param location table (`Location`|`LocationLink`) +---@param location lsp.Location|lsp.LocationLink ---@param offset_encoding string|nil utf-8|utf-16|utf-32 ---@param opts table|nil options --- - reuse_win (boolean) Jump to existing window if buffer is already open. @@ -1017,7 +1018,7 @@ end --- Jumps to a location. --- ----@param location table (`Location`|`LocationLink`) +---@param location lsp.Location|lsp.LocationLink ---@param offset_encoding string|nil utf-8|utf-16|utf-32 ---@param reuse_win boolean|nil Jump to existing window if buffer is already open. ---@return boolean `true` if the jump succeeded @@ -1038,7 +1039,7 @@ end --- - for Location, range is shown (e.g., function definition) --- - for LocationLink, targetRange is shown (e.g., body of function definition) --- ----@param location table a single `Location` or `LocationLink` +---@param location lsp.Location|lsp.LocationLink ---@param opts table ---@return integer|nil buffer id of float window ---@return integer|nil window id of float window @@ -1154,7 +1155,7 @@ end --- If you want to open a popup with fancy markdown, use `open_floating_preview` instead --- ---@param bufnr integer ----@param contents table of lines to show in window +---@param contents string[] of lines to show in window ---@param opts table with optional fields --- - height of floating window --- - width of floating window @@ -1669,7 +1670,7 @@ do --[[ References ]] --- Shows a list of document highlights for a certain buffer. --- ---@param bufnr integer Buffer id - ---@param references table List of `DocumentHighlight` objects to highlight + ---@param references lsp.DocumentHighlight[] objects to highlight ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32". ---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent function M.buf_highlight_references(bufnr, references, offset_encoding) @@ -1873,7 +1874,7 @@ end --- CAUTION: Modifies the input in-place! --- ---@deprecated ----@param lines table list of lines +---@param lines string[] list of lines ---@return string filetype or "markdown" if it was unchanged. function M.try_trim_markdown_code_blocks(lines) vim.deprecate('vim.lsp.util.try_trim_markdown_code_blocks()', 'nil', '0.12') @@ -1898,7 +1899,7 @@ function M.try_trim_markdown_code_blocks(lines) end ---@param window integer|nil: 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` +---@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 = api.nvim_win_get_buf(window) @@ -1919,7 +1920,7 @@ end --- ---@param window integer|nil: window handle or 0 for current, defaults to current ---@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` ----@return table `TextDocumentPositionParams` object +---@return lsp.TextDocumentPositionParams ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams function M.make_position_params(window, offset_encoding) window = window or 0 @@ -1932,7 +1933,7 @@ function M.make_position_params(window, offset_encoding) end --- Utility function for getting the encoding of the first LSP client on the given buffer. ----@param bufnr (integer) buffer handle or 0 for current, defaults to current +---@param bufnr integer buffer handle or 0 for current, defaults to current ---@return string encoding first client if there is one, nil otherwise function M._get_offset_encoding(bufnr) validate({ @@ -2033,15 +2034,16 @@ end --- Creates a `TextDocumentIdentifier` object for the current buffer. --- ---@param bufnr integer|nil: Buffer handle, defaults to current ----@return table `TextDocumentIdentifier` +---@return lsp.TextDocumentIdentifier ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier function M.make_text_document_params(bufnr) return { uri = vim.uri_from_bufnr(bufnr or 0) } end --- Create the workspace params ----@param added table ----@param removed table +---@param added lsp.WorkspaceFolder[] +---@param removed lsp.WorkspaceFolder[] +---@return lsp.WorkspaceFoldersChangeEvent function M.make_workspace_params(added, removed) return { event = { added = added, removed = removed } } end @@ -2049,8 +2051,8 @@ end --- Returns indentation size. --- ---@see 'shiftwidth' ----@param bufnr (integer|nil): Buffer handle, defaults to current ----@return (integer) indentation size +---@param bufnr integer|nil: Buffer handle, defaults to current +---@return integer indentation size function M.get_effective_tabstop(bufnr) validate({ bufnr = { bufnr, 'n', true } }) local bo = bufnr and vim.bo[bufnr] or vim.bo @@ -2060,7 +2062,7 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ----@param options table|nil with valid `FormattingOptions` entries +---@param options lsp.FormattingOptions|nil with valid `FormattingOptions` entries ---@return lsp.DocumentFormattingParams object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) -- cgit From 4cff4185647c17b1a397c4c26ff7d8b0738f6396 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 30 May 2024 19:57:47 -0500 Subject: fix(vim.text): remove assert from vim.text.hexdecode Instead, return nil plus an error message if the input is invalid. --- runtime/lua/vim/text.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/text.lua b/runtime/lua/vim/text.lua index bc90d490aa..0be3396464 100644 --- a/runtime/lua/vim/text.lua +++ b/runtime/lua/vim/text.lua @@ -18,15 +18,19 @@ end --- Hex decode a string. --- --- @param enc string String to decode ---- @return string : Decoded string +--- @return string? : Decoded string +--- @return string? : Error message, if any function M.hexdecode(enc) - assert(#enc % 2 == 0, 'string must have an even number of hex characters') + if #enc % 2 ~= 0 then + return nil, 'string must have an even number of hex characters' + end + local str = {} ---@type string[] for i = 1, #enc, 2 do local n = assert(tonumber(enc:sub(i, i + 1), 16)) str[#str + 1] = string.char(n) end - return table.concat(str) + return table.concat(str), nil end return M -- cgit From d62d181ce065556be51d5eda0425aa42f427cc27 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 31 May 2024 10:48:05 -0400 Subject: refactor(lsp): use tuple syntax in generated protocol types (#29110) --- runtime/lua/vim/lsp/_meta/protocol.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index 9a11972007..cbddd24630 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -3235,7 +3235,7 @@ error('Cannot require a meta file') --- ---*Note*: a label of type string should be a substring of its containing signature label. ---Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. ----@field label string|{ [1]: uinteger, [2]: uinteger } +---@field label string|[uinteger, uinteger] --- ---The human-readable doc-comment of this parameter. Will be shown ---in the UI but can be omitted. -- cgit From cc1f2d2ca6caa3da4cb7910f74fed4375202e888 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Thu, 30 May 2024 10:24:54 +0200 Subject: perf(lsp): don't copy completion items in filter pass --- runtime/lua/vim/lsp/completion.lua | 100 ++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 46 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 39c0c5fa29..8777947acf 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -201,6 +201,24 @@ local function get_items(result) end end +---@param item lsp.CompletionItem +---@return string +local function get_doc(item) + local doc = item.documentation + if not doc then + return '' + end + if type(doc) == 'string' then + return doc + end + if type(doc) == 'table' and type(doc.value) == 'string' then + return doc.value + end + + vim.notify('invalid documentation value: ' .. vim.inspect(doc), vim.log.levels.WARN) + return '' +end + --- Turns the result of a `textDocument/completion` request into vim-compatible --- |complete-items|. --- @@ -216,58 +234,48 @@ function M._lsp_to_complete_items(result, prefix, client_id) return {} end - if prefix ~= '' then - ---@param item lsp.CompletionItem - local function match_prefix(item) - if item.filterText then - return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) - end - return true + local matches = prefix == '' and function() + return true + end or function(item) + if item.filterText then + return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) end - - items = vim.tbl_filter(match_prefix, items) --[[@as lsp.CompletionItem[]|]] + return true end - table.sort(items, function(a, b) - return (a.sortText or a.label) < (b.sortText or b.label) - end) - - local matches = {} + local candidates = {} for _, item in ipairs(items) do - local info = '' - local documentation = item.documentation - if documentation then - if type(documentation) == 'string' and documentation ~= '' then - info = documentation - elseif type(documentation) == 'table' and type(documentation.value) == 'string' then - info = documentation.value - else - vim.notify( - ('invalid documentation value %s'):format(vim.inspect(documentation)), - vim.log.levels.WARN - ) - end - end - local word = get_completion_word(item) - table.insert(matches, { - word = word, - abbr = item.label, - kind = protocol.CompletionItemKind[item.kind] or 'Unknown', - menu = item.detail or '', - info = #info > 0 and info or '', - icase = 1, - dup = 1, - empty = 1, - user_data = { - nvim = { - lsp = { - completion_item = item, - client_id = client_id, + if matches(item) then + local word = get_completion_word(item) + table.insert(candidates, { + word = word, + abbr = item.label, + kind = protocol.CompletionItemKind[item.kind] or 'Unknown', + menu = item.detail or '', + info = get_doc(item), + icase = 1, + dup = 1, + empty = 1, + user_data = { + nvim = { + lsp = { + completion_item = item, + client_id = client_id, + }, }, }, - }, - }) + }) + end end - return matches + ---@diagnostic disable-next-line: no-unknown + table.sort(candidates, function(a, b) + ---@type lsp.CompletionItem + local itema = a.user_data.nvim.lsp.completion_item + ---@type lsp.CompletionItem + local itemb = b.user_data.nvim.lsp.completion_item + return (itema.sortText or itema.label) < (itemb.sortText or itemb.label) + end) + + return candidates end --- @param lnum integer 0-indexed -- cgit From 4c938f6d72710507db22074951eee23869ed49e0 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Thu, 30 May 2024 10:46:47 +0200 Subject: refactor(lsp): share completion request logic between omnifunc & trigger --- runtime/lua/vim/lsp/completion.lua | 209 +++++++++++++++---------------------- 1 file changed, 85 insertions(+), 124 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 8777947acf..c514c5ef4d 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -348,78 +348,6 @@ function M._convert_results( return matches, server_start_boundary end ---- Implements 'omnifunc' compatible LSP completion. ---- ---- @see |complete-functions| ---- @see |complete-items| ---- @see |CompleteDone| ---- ---- @param findstart integer 0 or 1, decides behavior ---- @param base integer findstart=0, text to match against ---- ---- @return integer|table Decided by {findstart}: ---- - findstart=0: column where the completion starts, or -2 or -3 ---- - findstart=1: list of matches (actually just calls |complete()|) -function M._omnifunc(findstart, base) - vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) - assert(base) -- silence luals - local bufnr = api.nvim_get_current_buf() - local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) - local remaining = #clients - if remaining == 0 then - return findstart == 1 and -1 or {} - end - - local win = api.nvim_get_current_win() - local cursor = api.nvim_win_get_cursor(win) - local lnum = cursor[1] - 1 - local cursor_col = cursor[2] - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) - local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] - local server_start_boundary = nil - local items = {} - - local function on_done() - local mode = api.nvim_get_mode()['mode'] - if mode == 'i' or mode == 'ic' then - vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) - end - end - - local util = vim.lsp.util - for _, client in ipairs(clients) do - local params = util.make_position_params(win, client.offset_encoding) - client.request(ms.textDocument_completion, params, function(err, result) - if err then - lsp.log.warn(err.message) - end - if result and vim.fn.mode() == 'i' then - local matches - matches, server_start_boundary = M._convert_results( - line, - lnum, - cursor_col, - client.id, - client_start_boundary, - server_start_boundary, - result, - client.offset_encoding - ) - vim.list_extend(items, matches) - end - remaining = remaining - 1 - if remaining == 0 then - vim.schedule(on_done) - end - end, bufnr) - end - - -- Return -2 to signal that we should continue completion so that we can - -- async complete. - return -2 -end - --- @param clients table --- @param bufnr integer --- @param win integer @@ -455,6 +383,64 @@ local function request(clients, bufnr, win, callback) end end +local function trigger(bufnr, clients) + reset_timer() + Context:cancel_pending() + + local win = api.nvim_get_current_win() + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') + local start_time = vim.uv.hrtime() + Context.last_request_time = start_time + + local cancel_request = request(clients, bufnr, win, function(responses) + local end_time = vim.uv.hrtime() + rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) + + Context.pending_requests = {} + Context.isIncomplete = false + + local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row + local mode = api.nvim_get_mode().mode + if row_changed or not (mode == 'i' or mode == 'ic') then + return + end + + local matches = {} + local server_start_boundary --- @type integer? + for client_id, response in pairs(responses) do + if response.err then + vim.notify_once(response.err.message, vim.log.levels.warn) + end + + local result = response.result + if result then + Context.isIncomplete = Context.isIncomplete or result.isIncomplete + local client = lsp.get_client_by_id(client_id) + local encoding = client and client.offset_encoding or 'utf-16' + local client_matches + client_matches, server_start_boundary = M._convert_results( + line, + cursor_row - 1, + cursor_col, + client_id, + word_boundary, + nil, + result, + encoding + ) + vim.list_extend(matches, client_matches) + end + end + local start_col = (server_start_boundary or word_boundary) + 1 + vim.fn.complete(start_col, matches) + end) + + table.insert(Context.pending_requests, cancel_request) +end + --- @param handle vim.lsp.completion.BufHandle local function on_insert_char_pre(handle) if tonumber(vim.fn.pumvisible()) == 1 then @@ -701,63 +687,38 @@ end --- Trigger LSP completion in the current buffer. function M.trigger() - reset_timer() - Context:cancel_pending() - - local win = api.nvim_get_current_win() local bufnr = api.nvim_get_current_buf() - local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) local clients = (buf_handles[bufnr] or {}).clients or {} - local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local start_time = vim.uv.hrtime() - Context.last_request_time = start_time - - local cancel_request = request(clients, bufnr, win, function(responses) - local end_time = vim.uv.hrtime() - rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) - - Context.pending_requests = {} - Context.isIncomplete = false - - local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row - local mode = api.nvim_get_mode().mode - if row_changed or not (mode == 'i' or mode == 'ic') then - return - end + trigger(bufnr, clients) +end - local matches = {} - local server_start_boundary --- @type integer? - for client_id, response in pairs(responses) do - if response.err then - vim.notify_once(response.err.message, vim.log.levels.warn) - end +--- Implements 'omnifunc' compatible LSP completion. +--- +--- @see |complete-functions| +--- @see |complete-items| +--- @see |CompleteDone| +--- +--- @param findstart integer 0 or 1, decides behavior +--- @param base integer findstart=0, text to match against +--- +--- @return integer|table Decided by {findstart}: +--- - findstart=0: column where the completion starts, or -2 or -3 +--- - findstart=1: list of matches (actually just calls |complete()|) +function M._omnifunc(findstart, base) + vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) + assert(base) -- silence luals + local bufnr = api.nvim_get_current_buf() + local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) + local remaining = #clients + if remaining == 0 then + return findstart == 1 and -1 or {} + end - local result = response.result - if result then - Context.isIncomplete = Context.isIncomplete or result.isIncomplete - local client = lsp.get_client_by_id(client_id) - local encoding = client and client.offset_encoding or 'utf-16' - local client_matches - client_matches, server_start_boundary = M._convert_results( - line, - cursor_row - 1, - cursor_col, - client_id, - word_boundary, - nil, - result, - encoding - ) - vim.list_extend(matches, client_matches) - end - end - local start_col = (server_start_boundary or word_boundary) + 1 - vim.fn.complete(start_col, matches) - end) + trigger(bufnr, clients) - table.insert(Context.pending_requests, cancel_request) + -- Return -2 to signal that we should continue completion so that we can + -- async complete. + return -2 end return M -- cgit From 138a93a057dabd70673b7466bf5af41bd66f1385 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Thu, 30 May 2024 10:51:52 +0200 Subject: perf(lsp): avoid repeated table lookup in completion.enable --- runtime/lua/vim/lsp/completion.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index c514c5ef4d..b77bf3e3c2 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -575,8 +575,10 @@ end ---@param bufnr integer ---@param opts vim.lsp.completion.BufferOpts local function enable_completions(client_id, bufnr, opts) - if not buf_handles[bufnr] then - buf_handles[bufnr] = { clients = {}, triggers = {} } + local buf_handle = buf_handles[bufnr] + if not buf_handle then + buf_handle = { clients = {}, triggers = {} } + buf_handles[bufnr] = buf_handle -- Attach to buffer events. api.nvim_buf_attach(bufnr, false, { @@ -617,12 +619,12 @@ local function enable_completions(client_id, bufnr, opts) end end - if not buf_handles[bufnr].clients[client_id] then + if not buf_handle.clients[client_id] then local client = lsp.get_client_by_id(client_id) assert(client, 'invalid client ID') -- Add the new client to the buffer's clients. - buf_handles[bufnr].clients[client_id] = client + buf_handle.clients[client_id] = client -- Add the new client to the clients that should be triggered by its trigger characters. --- @type string[] @@ -632,10 +634,10 @@ local function enable_completions(client_id, bufnr, opts) 'triggerCharacters' ) or {} for _, char in ipairs(triggers) do - local clients_for_trigger = buf_handles[bufnr].triggers[char] + local clients_for_trigger = buf_handle.triggers[char] if not clients_for_trigger then clients_for_trigger = {} - buf_handles[bufnr].triggers[char] = clients_for_trigger + buf_handle.triggers[char] = clients_for_trigger end local client_exists = vim.iter(clients_for_trigger):any(function(c) return c.id == client_id -- cgit From 7a8f42dc036f3bc6e8b106c580e0cd50dbed465e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 06:06:12 +0800 Subject: vim-patch:e299591: runtime(doc): clarify 'shortmess' flag "S" (#29131) fixes: vim/vim#14893 https://github.com/vim/vim/commit/e299591498a20c5c587364e4df57f947dfc02897 Co-authored-by: Christian Brabandt --- runtime/lua/vim/_meta/options.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 428b7c4d4f..2eae0d27a7 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -5781,8 +5781,8 @@ vim.bo.sw = vim.bo.shiftwidth --- message; also for quickfix message (e.g., ":cn") --- s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* --- "search hit TOP, continuing at BOTTOM" messages; when using ---- the search count do not show "W" after the count message (see ---- S below) +--- the search count do not show "W" before the count message +--- (see `shm-S` below) --- t truncate file message at the start if it is too long *shm-t* --- to fit on the command-line, "<" will appear in the left most --- column; ignored in Ex mode @@ -5804,7 +5804,11 @@ vim.bo.sw = vim.bo.shiftwidth --- `:silent` was used for the command; note that this also --- affects messages from 'autoread' reloading --- S do not show search count message when searching, e.g. *shm-S* ---- "[1/5]" +--- "[1/5]". When the "S" flag is not present (e.g. search count +--- is shown), the "search hit BOTTOM, continuing at TOP" and +--- "search hit TOP, continuing at BOTTOM" messages are only +--- indicated by a "W" (Mnemonic: Wrapped) letter before the +--- search count statistics. --- --- This gives you the opportunity to avoid that a change between buffers --- requires you to hit , but still gives as useful a message as -- cgit From 19be3d26830ced203631045f2f622e75e6d857a7 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 2 Jun 2024 09:54:15 +0200 Subject: fix(lsp): trim trailing whitespace from completion words (#29122) the `complete()` mechanism doesn't play nicely with trailing newlines or tabs. A newline causes it to insert a null character, showing up as `^@`. --- runtime/lua/vim/lsp/completion.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index b77bf3e3c2..f8e17ae2f0 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -153,7 +153,8 @@ local function get_completion_word(item) return item.label end elseif item.textEdit then - return item.textEdit.newText + local word = item.textEdit.newText + return word:match('^(%S*)') or word elseif item.insertText and item.insertText ~= '' then return item.insertText end -- cgit From 659d3dcd2edf1b178a20015cab399390ffda1a32 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 2 Jun 2024 17:31:37 +0200 Subject: vim-patch:9.1.0460: filetype: lintstagedrc files are not recognized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: filetype: lintstagedrc files are not recognized Solution: recognize '.lintstagedrc' files as json filetype (İlyas Akın) see: https://github.com/lint-staged/lint-staged closes: vim/vim#14897 https://github.com/vim/vim/commit/7577afd5efd0f7ebf0dbbca09713185024263ed7 Co-authored-by: İlyas Akın --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 500632a2b2..c8f9bcfd84 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1451,6 +1451,7 @@ local filename = { ['.firebaserc'] = 'json', ['.prettierrc'] = 'json', ['.stylelintrc'] = 'json', + ['.lintstagedrc'] = 'json', ['flake.lock'] = 'json', ['.babelrc'] = 'jsonc', ['.eslintrc'] = 'jsonc', -- cgit From a9c89bcbf69a3d0ef47f324a47ff6eb482467e70 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 11:55:20 +0200 Subject: fix(gx): allow `@` in url This will make `gx` work for links for the form https://hachyderm.io/@neovim. --- runtime/lua/vim/ui.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 99b9b78e2a..f168da4955 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -179,7 +179,13 @@ function M._get_url() current_node = current_node:parent() end end - return vim.fn.expand('') + + local old_isfname = vim.o.isfname + vim.cmd [[set isfname+=@-@]] + local url = vim.fn.expand('') + vim.o.isfname = old_isfname + + return url end return M -- cgit From 5aa9906676f3ad040b0ccb75eb5fd560def1e0ec Mon Sep 17 00:00:00 2001 From: ippachi Date: Tue, 4 Jun 2024 01:07:09 +0900 Subject: fix(lsp): use client.id instead of pairs index (#29143) Problem: Completion side effects not working randomly. Solution: When creating the table of LSP responses, the table index was used, but this is not the same as the actual client_id, so it was changed to use the client_id directly. --- runtime/lua/vim/lsp/completion.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index f8e17ae2f0..c9326a0681 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -349,7 +349,7 @@ function M._convert_results( return matches, server_start_boundary end ---- @param clients table +--- @param clients table # keys != client_id --- @param bufnr integer --- @param win integer --- @param callback fun(responses: table) @@ -359,7 +359,8 @@ local function request(clients, bufnr, win, callback) local request_ids = {} --- @type table local remaining_requests = vim.tbl_count(clients) - for client_id, client in pairs(clients) do + for _, client in pairs(clients) do + local client_id = client.id local params = lsp.util.make_position_params(win, client.offset_encoding) local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result) responses[client_id] = { err = err, result = result } -- cgit From 2f5b8a009280eba995aecf67d1e8d99b7c72c51c Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 4 Jun 2024 09:39:28 +0200 Subject: vim-patch:9.1.0464: no whitespace padding in commentstring option in ftplugins Problem: no whitespace padding in commentstring option in ftplugins Solution: Change default to include whitespace padding, update existing filetype plugins with the new default value (Riley Bruins) closes: vim/vim#14843 https://github.com/vim/vim/commit/0a0830624a260660c7fa692ecb7e6e5de09114ba Co-authored-by: Riley Bruins --- runtime/lua/vim/_meta/options.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 2eae0d27a7..93ef75aeb3 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -974,8 +974,8 @@ vim.bo.comments = vim.o.comments vim.bo.com = vim.bo.comments --- A template for a comment. The "%s" in the value is replaced with the ---- comment text. For example, C uses "/*%s*/". Used for `commenting` and to ---- add markers for folding, see `fold-marker`. +--- comment text, and should be padded with a space when possible. +--- Used for `commenting` and to add markers for folding, see `fold-marker`. --- --- @type string vim.o.commentstring = "" -- cgit From aa9f21ee953dd37c189a3a0388af84c87f7591ba Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 4 Jun 2024 11:55:59 +0300 Subject: fix(filetype): fix typos in filetype detection --- runtime/lua/vim/filetype/detect.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 58d2666564..c56ece6289 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -594,7 +594,7 @@ function M.frm(_, bufnr) end --- @type vim.filetype.mapfn -function M.fvwm_1(_, _) +function M.fvwm_v1(_, _) return 'fvwm', function(bufnr) vim.b[bufnr].fvwm_version = 1 end @@ -1355,7 +1355,7 @@ end function M.sgml(_, bufnr) local lines = table.concat(getlines(bufnr, 1, 5)) if lines:find('linuxdoc') then - return 'smgllnx' + return 'sgmllnx' elseif lines:find(' Date: Tue, 4 Jun 2024 09:06:02 -0400 Subject: refactor(lua): use tuple syntax everywhere #29111 --- runtime/lua/tohtml.lua | 12 ++++++------ runtime/lua/vim/_meta/api_keysets_extra.lua | 4 ++-- runtime/lua/vim/_meta/builtin_types.lua | 2 +- runtime/lua/vim/_meta/spell.lua | 2 +- runtime/lua/vim/_meta/vimfn.lua | 2 +- runtime/lua/vim/deprecated/health.lua | 2 +- runtime/lua/vim/diagnostic.lua | 8 ++++---- runtime/lua/vim/filetype.lua | 2 +- runtime/lua/vim/lsp/completion.lua | 2 +- runtime/lua/vim/lsp/inlay_hint.lua | 2 +- runtime/lua/vim/provider/health.lua | 2 +- runtime/lua/vim/shared.lua | 2 +- runtime/lua/vim/treesitter.lua | 2 +- runtime/lua/vim/treesitter/dev.lua | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 120247ed4e..a67e1c69e2 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -46,7 +46,7 @@ --- @field [integer] vim.tohtml.line (integer: (1-index, exclusive)) --- @class (private) vim.tohtml.line ---- @field virt_lines {[integer]:{[1]:string,[2]:integer}[]} +--- @field virt_lines {[integer]:[string,integer][]} --- @field pre_text string[][] --- @field hide? boolean --- @field [integer] vim.tohtml.cell? (integer: (1-index, exclusive)) @@ -481,7 +481,7 @@ local function styletable_treesitter(state) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] --- @param namespaces table local function _styletable_extmarks_highlight(state, extmark, namespaces) if not extmark[4].hl_group then @@ -503,7 +503,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] --- @param namespaces table local function _styletable_extmarks_virt_text(state, extmark, namespaces) if not extmark[4].virt_text then @@ -559,7 +559,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] local function _styletable_extmarks_virt_lines(state, extmark) ---TODO(altermo) if the fold start is equal to virt_line start then the fold hides the virt_line if not extmark[4].virt_lines then @@ -580,7 +580,7 @@ local function _styletable_extmarks_virt_lines(state, extmark) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] local function _styletable_extmarks_conceal(state, extmark) if not extmark[4].conceal or state.opt.conceallevel == 0 then return @@ -648,7 +648,7 @@ local function styletable_conceal(state) local bufnr = state.bufnr vim.api.nvim_buf_call(bufnr, function() for row = 1, state.buflen do - --- @type table + --- @type table local conceals = {} local line_len_exclusive = #vim.fn.getline(row) + 1 for col = 1, line_len_exclusive do diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index 76b56b04e7..e1f12868d0 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -26,13 +26,13 @@ error('Cannot require a meta file') --- @field url? boolean --- @field hl_mode? string --- ---- @field virt_text? {[1]: string, [2]: string}[] +--- @field virt_text? [string, string][] --- @field virt_text_hide? boolean --- @field virt_text_repeat_linebreak? boolean --- @field virt_text_win_col? integer --- @field virt_text_pos? string --- ---- @field virt_lines? {[1]: string, [2]: string}[][] +--- @field virt_lines? [string, string][][] --- @field virt_lines_above? boolean --- @field virt_lines_leftcol? boolean --- diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua index 9f0d2e7038..53dd8d95e9 100644 --- a/runtime/lua/vim/_meta/builtin_types.lua +++ b/runtime/lua/vim/_meta/builtin_types.lua @@ -25,7 +25,7 @@ --- @field variables table --- @field windows integer[] ---- @alias vim.fn.getjumplist.ret {[1]: vim.fn.getjumplist.ret.item[], [2]: integer} +--- @alias vim.fn.getjumplist.ret [vim.fn.getjumplist.ret.item[], integer] --- @class vim.fn.getjumplist.ret.item --- @field bufnr integer diff --git a/runtime/lua/vim/_meta/spell.lua b/runtime/lua/vim/_meta/spell.lua index c636db3b53..b4e3bf6ca4 100644 --- a/runtime/lua/vim/_meta/spell.lua +++ b/runtime/lua/vim/_meta/spell.lua @@ -20,7 +20,7 @@ --- ``` --- --- @param str string ---- @return {[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[] +--- @return [string, 'bad'|'rare'|'local'|'caps', integer][] --- List of tuples with three items: --- - The badly spelled word. --- - The type of the spelling error: diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 84bb26a135..a1600e1cb5 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -9796,7 +9796,7 @@ function vim.fn.synIDtrans(synID) end --- --- @param lnum integer --- @param col integer ---- @return {[1]: integer, [2]: string, [3]: integer} +--- @return [integer, string, integer] function vim.fn.synconcealed(lnum, col) end --- Return a |List|, which is the stack of syntax items at the diff --git a/runtime/lua/vim/deprecated/health.lua b/runtime/lua/vim/deprecated/health.lua index 64a755b248..eed889d90a 100644 --- a/runtime/lua/vim/deprecated/health.lua +++ b/runtime/lua/vim/deprecated/health.lua @@ -1,7 +1,7 @@ local M = {} local health = vim.health -local deprecated = {} ---@type {[1]: string, [2]: table, [3]: string}[] +local deprecated = {} ---@type [string, table, string][] function M.check() if next(deprecated) == nil then diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index dca7698356..c6649ae09b 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -108,7 +108,7 @@ local M = {} --- If {scope} is "line" or "cursor", use this position rather than the cursor --- position. If a number, interpreted as a line number; otherwise, a --- (row, col) tuple. ---- @field pos? integer|{[1]:integer,[2]:integer} +--- @field pos? integer|[integer,integer] --- --- Sort diagnostics by severity. --- Overrides the setting from |vim.diagnostic.config()|. @@ -122,7 +122,7 @@ local M = {} --- String to use as the header for the floating window. If a table, it is --- interpreted as a `[text, hl_group]` tuple. --- Overrides the setting from |vim.diagnostic.config()|. ---- @field header? string|{[1]:string,[2]:any} +--- @field header? string|[string,any] --- --- Include the diagnostic source in the message. --- Use "if_many" to only show sources if there is more than one source of @@ -203,7 +203,7 @@ local M = {} --- @field hl_mode? 'replace'|'combine'|'blend' --- --- See |nvim_buf_set_extmark()|. ---- @field virt_text? {[1]:string,[2]:any}[] +--- @field virt_text? [string,any][] --- --- See |nvim_buf_set_extmark()|. --- @field virt_text_pos? 'eol'|'overlay'|'right_align'|'inline' @@ -1252,7 +1252,7 @@ end --- Cursor position as a `(row, col)` tuple. See |nvim_win_get_cursor()|. Used --- to find the nearest diagnostic when {count} is used. Only used when {count} --- is non-nil. Default is the current cursor position. ---- @field pos? {[1]:integer,[2]:integer} +--- @field pos? [integer,integer] --- --- Whether to loop around file or not. Similar to 'wrapscan'. --- (default: `true`) diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c8f9bcfd84..cc2fbe0cec 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -4,7 +4,7 @@ local fn = vim.fn local M = {} --- @alias vim.filetype.mapfn fun(path:string,bufnr:integer, ...):string?, fun(b:integer)? ---- @alias vim.filetype.maptbl {[1]:string|vim.filetype.mapfn, [2]:{priority:integer}} +--- @alias vim.filetype.maptbl [string|vim.filetype.mapfn, {priority:integer}] --- @alias vim.filetype.mapping.value string|vim.filetype.mapfn|vim.filetype.maptbl --- @alias vim.filetype.mapping table diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index c9326a0681..4b7deabf41 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -30,7 +30,7 @@ local buf_handles = {} --- @nodoc --- @class vim.lsp.completion.Context local Context = { - cursor = nil, --- @type { [1]: integer, [2]: integer }? + cursor = nil, --- @type [integer, integer]? last_request_time = nil, --- @type integer? pending_requests = {}, --- @type function[] isIncomplete = false, diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 78f309abf7..8fd4ceefd2 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -348,7 +348,7 @@ api.nvim_set_decoration_provider(namespace, { text = text .. part.value end end - local vt = {} --- @type {[1]: string, [2]: string?}[] + local vt = {} --- @type [string, string?][] if hint.paddingLeft then vt[#vt + 1] = { ' ' } end diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index fa2c452268..860f839f23 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -353,7 +353,7 @@ end --- their respective paths. If either of those is invalid, return two empty --- strings, effectively ignoring pyenv. --- ---- @return {[1]: string, [2]: string} +--- @return [string, string] local function check_for_pyenv() local pyenv_path = vim.fn.resolve(vim.fn.exepath('pyenv')) diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 0ec79e1dc7..9d54a80144 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -789,7 +789,7 @@ do } --- @nodoc - --- @class vim.validate.Spec {[1]: any, [2]: string|string[], [3]: boolean } + --- @class vim.validate.Spec [any, string|string[], boolean] --- @field [1] any Argument value --- @field [2] string|string[]|fun(v:any):boolean, string? Type name, or callable --- @field [3]? boolean diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index db544c1ab1..e36aacfd94 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -335,7 +335,7 @@ end --- --- 0-indexed (row, col) tuple. Defaults to cursor position in the --- current window. Required if {bufnr} is not the current buffer ---- @field pos { [1]: integer, [2]: integer }? +--- @field pos [integer, integer]? --- --- Parser language. (default: from buffer filetype) --- @field lang string? diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua index ca8cf85eda..56608bbf14 100644 --- a/runtime/lua/vim/treesitter/dev.lua +++ b/runtime/lua/vim/treesitter/dev.lua @@ -174,7 +174,7 @@ end --- @param source_buf integer --- @param inspect_buf integer --- @param inspect_win integer ---- @param pos? { [1]: integer, [2]: integer } +--- @param pos? [integer, integer] local function set_inspector_cursor(treeview, lang, source_buf, inspect_buf, inspect_win, pos) api.nvim_buf_clear_namespace(inspect_buf, treeview.ns, 0, -1) -- cgit From 2e6d295f799c27372e5c0c44727fa613c81717fd Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Tue, 4 Jun 2024 17:21:37 +0200 Subject: fix(lsp): account for changedtick version gap on modified reset (#29170) Follow up to https://github.com/neovim/neovim/pull/28943 Fixes https://github.com/neovim/neovim/issues/29163 --- runtime/lua/vim/lsp/util.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b33f6ccf69..3215b40d1d 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -502,6 +502,11 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) should_check_version = false end + -- changedtick increases on save but server only receives version updates + -- on line changes (via didChange) + -- This allows a gap of 1 to account for the servers outdated view + local version_offset = vim.b[bufnr].modified and 0 or 1 + -- `VersionedTextDocumentIdentifier`s version may be null -- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier if @@ -509,7 +514,7 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) and ( text_document.version and text_document.version > 0 - and vim.b[bufnr].changedtick > text_document.version + and vim.b[bufnr].changedtick > (text_document.version + version_offset) ) then print('Buffer ', text_document.uri, ' newer than edits.') -- cgit From 43581011e41b54473427c2e90450a4f3126b7e66 Mon Sep 17 00:00:00 2001 From: jdrouhard Date: Tue, 4 Jun 2024 10:22:02 -0500 Subject: fix(lsp): remove superfluous on_detach callback from semantic tokens module (#29174) LspDetach is now triggered by the main on_detach callback that is added when an LSP client is attached to a buffer. The semantic_tokens module already includes a LspDetach handler that does the right thing. When the LspDetach trigger was added to the main LSP on_detach, it created a race condition in semantic tokens when a buffer was deleted that would trigger both its own on_detach and the LspDetach handlers. If the former came last, an error was thrown trying to delete a non-existent augroup (destroy() was being called twice). --- runtime/lua/vim/lsp/semantic_tokens.lua | 6 ------ 1 file changed, 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index 278014a4ea..b2a8360aa2 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -197,12 +197,6 @@ function STHighlighter.new(bufnr) highlighter:send_request() end end, - on_detach = function(_, buf) - local highlighter = STHighlighter.active[buf] - if highlighter then - highlighter:destroy() - end - end, }) api.nvim_create_autocmd({ 'BufWinEnter', 'InsertLeave' }, { -- cgit From 230bc34ca541cfe109cd44241eb588d2a8fdda66 Mon Sep 17 00:00:00 2001 From: Saltaformajo Date: Tue, 4 Jun 2024 18:23:57 +0300 Subject: fix(lsp): check if buffer is valid before LspDetach autocmd (#29162) --- runtime/lua/vim/lsp.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index c2deac0113..540b1e9658 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -393,7 +393,7 @@ local function on_client_exit(code, signal, client_id) vim.schedule(function() for bufnr in pairs(client.attached_buffers) do - if client and client.attached_buffers[bufnr] then + if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then api.nvim_exec_autocmds('LspDetach', { buffer = bufnr, modeline = false, -- cgit From f69937fdbd162630c35e119e67bbbf052558c0e0 Mon Sep 17 00:00:00 2001 From: Andre Toerien <49614525+AThePeanut4@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:35:44 +0200 Subject: fix(diagnostic): fix float scope filtering (#29134) --- runtime/lua/vim/diagnostic.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index c6649ae09b..9342727b2e 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -1857,16 +1857,19 @@ function M.open_float(opts, ...) if scope == 'line' then --- @param d vim.Diagnostic diagnostics = vim.tbl_filter(function(d) - return lnum >= d.lnum and lnum <= d.end_lnum + return lnum >= d.lnum + and lnum <= d.end_lnum + and (d.lnum == d.end_lnum or lnum ~= d.end_lnum or d.end_col ~= 0) end, diagnostics) elseif scope == 'cursor' then - -- LSP servers can send diagnostics with `end_col` past the length of the line + -- If `col` is past the end of the line, show if the cursor is on the last char in the line local line_length = #api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] --- @param d vim.Diagnostic diagnostics = vim.tbl_filter(function(d) - return d.lnum == lnum - and math.min(d.col, line_length - 1) <= col - and (d.end_col >= col or d.end_lnum > lnum) + return lnum >= d.lnum + and lnum <= d.end_lnum + and (lnum ~= d.lnum or col >= math.min(d.col, line_length - 1)) + and ((d.lnum == d.end_lnum and d.col == d.end_col) or lnum ~= d.end_lnum or col < d.end_col) end, diagnostics) end -- cgit From 164338330b74e6e7c7cbb61e49c810dd82599236 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 14:44:31 +0800 Subject: vim-patch:9.1.0463: no fuzzy-matching support for insert-completion Problem: no fuzzy-matching support for insert-completion Solution: enable insert-mode completion with fuzzy-matching using :set completopt+=fuzzy (glepnir). closes: vim/vim#14878 https://github.com/vim/vim/commit/a218cc6cdabae1113647b817c4eefc2b60a6902f Co-authored-by: glepnir --- runtime/lua/vim/_meta/options.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 93ef75aeb3..92c54c397f 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -1061,6 +1061,10 @@ vim.bo.cfu = vim.bo.completefunc --- completion in the preview window. Only works in --- combination with "menu" or "menuone". --- +--- popup Show extra information about the currently selected +--- completion in a popup window. Only works in combination +--- with "menu" or "menuone". Overrides "preview". +--- --- noinsert Do not insert any text for a match until the user selects --- a match from the menu. Only works in combination with --- "menu" or "menuone". No effect if "longest" is present. @@ -1069,9 +1073,10 @@ vim.bo.cfu = vim.bo.completefunc --- select one from the menu. Only works in combination with --- "menu" or "menuone". --- ---- popup Show extra information about the currently selected ---- completion in a popup window. Only works in combination ---- with "menu" or "menuone". Overrides "preview". +--- fuzzy Enable `fuzzy-matching` for completion candidates. This +--- allows for more flexible and intuitive matching, where +--- characters can be skipped and matches can be found even +--- if the exact sequence is not typed. --- --- @type string vim.o.completeopt = "menu,preview" -- cgit From c2e836c41cabef3c5e269b5f6401f272112c75e1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 15:01:23 +0800 Subject: vim-patch:2a2c4ff: runtime(doc): clarify how fuzzy 'completeopt' should work related: vim/vim#14912 https://github.com/vim/vim/commit/2a2c4fffd7e04f74b316209404767f128684a9e1 Co-authored-by: Christian Brabandt --- runtime/lua/vim/_meta/options.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 92c54c397f..0b4294ae4b 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -1076,7 +1076,10 @@ vim.bo.cfu = vim.bo.completefunc --- fuzzy Enable `fuzzy-matching` for completion candidates. This --- allows for more flexible and intuitive matching, where --- characters can be skipped and matches can be found even ---- if the exact sequence is not typed. +--- if the exact sequence is not typed. Only makes a +--- difference how completion candidates are reduced from the +--- list of alternatives, but not how the candidates are +--- collected (using different completion types). --- --- @type string vim.o.completeopt = "menu,preview" -- cgit From 43bd9c9c1cacb2f069c7e84330a608623c874d74 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 16:47:43 +0800 Subject: fix(lua): don't clamp -1 or v:maxcol in vim.highlight.range() (#29203) --- runtime/lua/vim/highlight.lua | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 89298ce568..e972ffaa8c 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -49,10 +49,22 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local priority = opts.priority or M.priorities.user local scoped = opts._scoped or false + local v_maxcol = vim.v.maxcol + local pos1 = type(start) == 'string' and vim.fn.getpos(start) - or { bufnr, start[1] + 1, start[2] + 1, 0 } + or { + bufnr, + start[1] + 1, + start[2] ~= -1 and start[2] ~= v_maxcol and start[2] + 1 or v_maxcol, + 0, + } local pos2 = type(finish) == 'string' and vim.fn.getpos(finish) - or { bufnr, finish[1] + 1, finish[2] + 1, 0 } + or { + bufnr, + finish[1] + 1, + finish[2] ~= -1 and start[2] ~= v_maxcol and finish[2] + 1 or v_maxcol, + 0, + } local buf_line_count = vim.api.nvim_buf_line_count(bufnr) pos1[2] = math.min(pos1[2], buf_line_count) @@ -63,10 +75,14 @@ function M.range(bufnr, ns, higroup, start, finish, opts) end vim.api.nvim_buf_call(bufnr, function() - local max_col1 = vim.fn.col({ pos1[2], '$' }) - pos1[3] = math.min(pos1[3], max_col1) - local max_col2 = vim.fn.col({ pos2[2], '$' }) - pos2[3] = math.min(pos2[3], max_col2) + if pos1[3] ~= v_maxcol then + local max_col1 = vim.fn.col({ pos1[2], '$' }) + pos1[3] = math.min(pos1[3], max_col1) + end + if pos2[3] ~= v_maxcol then + local max_col2 = vim.fn.col({ pos2[2], '$' }) + pos2[3] = math.min(pos2[3], max_col2) + end end) local region = vim.fn.getregionpos(pos1, pos2, { @@ -77,6 +93,14 @@ function M.range(bufnr, ns, higroup, start, finish, opts) -- For non-blockwise selection, use a single extmark. if regtype == 'v' or regtype == 'V' then region = { { region[1][1], region[#region][2] } } + if + regtype == 'V' + or region[1][2][2] == pos1[2] and pos1[3] == v_maxcol + or region[1][2][2] == pos2[2] and pos2[3] == v_maxcol + then + region[1][2][2] = region[1][2][2] + 1 + region[1][2][3] = 0 + end end for _, res in ipairs(region) do @@ -84,10 +108,6 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local start_col = res[1][3] - 1 local end_row = res[2][2] - 1 local end_col = res[2][3] - if regtype == 'V' then - end_row = end_row + 1 - end_col = 0 - end api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, { hl_group = higroup, end_row = end_row, -- cgit From d7651b27d54a87c5783c0a579af11da9a16a39aa Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:27:56 -0500 Subject: fix(tui): move $COLORTERM check to _defaults.lua (#29197) We currently check $COLORTERM in the TUI process to determine if the terminal supports 24 bit color (truecolor). If $COLORTERM is "truecolor" or "24bit" then we automatically assume that the terminal supports truecolor, but if $COLORTERM is set to any other value we still query the terminal. The `rgb` flag of the UI struct is a boolean which only indicates whether the UI supports truecolor, but does not have a 3rd state that we can use to represent "we don't know if the UI supports truecolor". We currently use `rgb=false` to represent this "we don't know" state, and we use XTGETTCAP and DECRQSS queries to determine at runtime if the terminal supports truecolor. However, if $COLORTERM is set to a value besides "truecolor" or "24bit" (e.g. "256" or "16) that is a clear indication that the terminal _does not_ support truecolor, so it is incorrect to treat `rgb=false` as "we don't know" in that case. Instead, in the TUI process we only check for the terminfo capabilities. This must be done in the TUI process because we do not have access to this information in the core Neovim process when `_defaults.lua` runs. If the TUI cannot determine truecolor support from terminfo alone, we set `rgb=false` to indicate "we don't know if the terminal supports truecolor yet, keep checking". When we get to `_defaults.lua`, we can then check $COLORTERM and only query the terminal if it is unset. This means that users can explicitly opt out of truecolor determination by setting `COLORTERM=256` (or similar) in their environment. --- runtime/lua/vim/_defaults.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 79fe5a8513..01dcd4bf74 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -470,10 +470,14 @@ do --- response indicates that it does support truecolor enable 'termguicolors', --- but only if the user has not already disabled it. do - if tty.rgb then - -- The TUI was able to determine truecolor support + local colorterm = os.getenv('COLORTERM') + if tty.rgb or colorterm == 'truecolor' or colorterm == '24bit' then + -- The TUI was able to determine truecolor support or $COLORTERM explicitly indicates + -- truecolor support setoption('termguicolors', true) - else + elseif colorterm == nil or colorterm == '' then + -- Neither the TUI nor $COLORTERM indicate that truecolor is supported, so query the + -- terminal local caps = {} ---@type table require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found) if not found then -- cgit From 1d4e894403638a94ac58766cdcbc7f3128db318b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 6 Jun 2024 05:50:44 +0800 Subject: vim-patch:9.1.0469: Cannot have buffer-local value for 'completeopt' Problem: Cannot have buffer-local value for 'completeopt' (Nick Jensen). Solution: Make 'completeopt' global-local (zeertzjq). Also for some reason test Test_ColonEight_MultiByte seems to be failing sporadically now. Let's mark it as flaky. fixes: vim/vim#5487 closes: vim/vim#14922 https://github.com/vim/vim/commit/529b9ad62a0e843ee56ef609aef7e51b7dc8a4c8 --- runtime/lua/vim/_meta/options.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 0b4294ae4b..155c93726b 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -1084,6 +1084,8 @@ vim.bo.cfu = vim.bo.completefunc --- @type string vim.o.completeopt = "menu,preview" vim.o.cot = vim.o.completeopt +vim.bo.completeopt = vim.o.completeopt +vim.bo.cot = vim.bo.completeopt vim.go.completeopt = vim.o.completeopt vim.go.cot = vim.go.completeopt -- cgit From cb6c0fda718e4503fc1bfc49a9fe92411f5f9005 Mon Sep 17 00:00:00 2001 From: sus-domesticus <134197728+sus-domesticus@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:16:43 +0300 Subject: feat(editorconfig): add support for spelling_language (#28638) --- runtime/lua/editorconfig.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/editorconfig.lua b/runtime/lua/editorconfig.lua index dcd7425c29..e65d267a70 100644 --- a/runtime/lua/editorconfig.lua +++ b/runtime/lua/editorconfig.lua @@ -190,6 +190,27 @@ function properties.insert_final_newline(bufnr, val) end end +--- A code of the format ss or ss-TT, where ss is an ISO 639 language code and TT is an ISO 3166 territory identifier. +--- Sets the 'spelllang' option. +function properties.spelling_language(bufnr, val) + local error_msg = + 'spelling_language must be of the format ss or ss-TT, where ss is an ISO 639 language code and TT is an ISO 3166 territory identifier.' + + assert(val:len() == 2 or val:len() == 5, error_msg) + + local language_code = val:sub(1, 2):lower() + assert(language_code:match('%l%l'), error_msg) + if val:len() == 2 then + vim.bo[bufnr].spelllang = language_code + else + assert(val:sub(3, 3) == '-', error_msg) + + local territory_code = val:sub(4, 5):lower() + assert(territory_code:match('%l%l'), error_msg) + vim.bo[bufnr].spelllang = language_code .. '_' .. territory_code + end +end + --- @private --- Modified version of [glob2regpat()] that does not match path separators on `*`. --- -- cgit From 8c5af0eb85a3932f6ca018d2aa681521369a26be Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Fri, 7 Jun 2024 04:55:14 +0200 Subject: docs: misc (#28837) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danymat Co-authored-by: Gregory Anders Co-authored-by: Jakub Okoński Co-authored-by: John L. Villalovos Co-authored-by: Maria José Solano Co-authored-by: Michaili K Co-authored-by: TheLeoP Co-authored-by: Tobias Schmitz Co-authored-by: W20MC <157727813+W20MC@users.noreply.github.com> Co-authored-by: Will Hopkins Co-authored-by: Yifan Hu <141280278+b0ae989c@users.noreply.github.com> Co-authored-by: glepnir Co-authored-by: prljav <74116121+prljav@users.noreply.github.com> --- runtime/lua/vim/_editor.lua | 5 ++--- runtime/lua/vim/_meta/api.lua | 14 +++++++------- runtime/lua/vim/_options.lua | 1 - runtime/lua/vim/diagnostic.lua | 2 ++ runtime/lua/vim/lsp.lua | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 9f952db4fc..c7c8362bfb 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -608,10 +608,9 @@ end --- Displays a notification to the user. --- ---- This function can be overridden by plugins to display notifications using a ---- custom provider (such as the system notification provider). By default, +--- This function can be overridden by plugins to display notifications using +--- a custom provider (such as the system notification provider). By default, --- writes to |:messages|. ---- ---@param msg string Content of the notification to show to the user. ---@param level integer|nil One of the values from |vim.log.levels|. ---@param opts table|nil Optional parameters. Unused by default. diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index c99eefa4f6..bb27ee4269 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -276,14 +276,14 @@ function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start --- @return boolean function vim.api.nvim_buf_attach(buffer, send_buffer, opts) end ---- call a function with buffer as temporary current buffer +--- Call a function with buffer as temporary current buffer. --- --- This temporarily switches current buffer to "buffer". If the current ---- window already shows "buffer", the window is not switched If a window ---- inside the current tabpage (including a float) already shows the buffer ---- One of these windows will be set as current window temporarily. Otherwise ---- a temporary scratch window (called the "autocmd window" for historical ---- reasons) will be used. +--- window already shows "buffer", the window is not switched. If a window +--- inside the current tabpage (including a float) already shows the buffer, +--- then one of these windows will be set as current window temporarily. +--- Otherwise a temporary scratch window (called the "autocmd window" for +--- historical reasons) will be used. --- --- This is useful e.g. to call Vimscript functions that only work with the --- current buffer/window currently, like `termopen()`. @@ -1953,7 +1953,7 @@ function vim.api.nvim_set_current_win(window) end --- --- • on_win: called when starting to redraw a specific window. --- ``` ---- ["win", winid, bufnr, topline, botline] +--- ["win", winid, bufnr, toprow, botrow] --- ``` --- --- • on_line: called for each buffer line being redrawn. (The diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua index b41e298dd7..4a360c18e4 100644 --- a/runtime/lua/vim/_options.lua +++ b/runtime/lua/vim/_options.lua @@ -95,7 +95,6 @@ local api = vim.api -- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded. --- Can be done in a separate PR. local key_value_options = { fillchars = true, fcs = true, diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 9342727b2e..c8e34258f5 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -247,9 +247,11 @@ local M = {} --- @class vim.diagnostic.Opts.Jump --- --- Default value of the {float} parameter of |vim.diagnostic.jump()|. +--- (default: false) --- @field float? boolean|vim.diagnostic.Opts.Float --- --- Default value of the {wrap} parameter of |vim.diagnostic.jump()|. +--- (default: true) --- @field wrap? boolean --- --- Default value of the {severity} parameter of |vim.diagnostic.jump()|. diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 540b1e9658..49a24f873c 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -201,10 +201,10 @@ end --- Predicate used to decide if a client should be re-used. Used on all --- running clients. The default implementation re-uses a client if name and --- root_dir matches. ---- @field reuse_client fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean +--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean --- --- Buffer handle to attach to if starting or re-using a client (0 for current). ---- @field bufnr integer +--- @field bufnr? integer --- --- Suppress error reporting if the LSP server fails to start (default false). --- @field silent? boolean -- cgit From 6e45cd7f0026ee33b8c397b810dcfe5b4678bbd8 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 7 Jun 2024 11:36:46 +0200 Subject: fix(lsp): revert buf_versions deprecation/replacement (#29217) * Revert "fix(lsp): account for changedtick version gap on modified reset (#29170)" This reverts commit 2e6d295f799c27372e5c0c44727fa613c81717fd. * Revert "refactor(lsp): replace util.buf_versions with changedtick (#28943)" This reverts commit 5c33815448e11b514678f39cecc74e68131d4628. --- runtime/lua/vim/lsp.lua | 5 ++++- runtime/lua/vim/lsp/_changetracking.lua | 3 ++- runtime/lua/vim/lsp/client.lua | 5 +++-- runtime/lua/vim/lsp/inlay_hint.lua | 4 ++-- runtime/lua/vim/lsp/semantic_tokens.lua | 6 +++--- runtime/lua/vim/lsp/util.lua | 21 +++++---------------- 6 files changed, 19 insertions(+), 25 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 49a24f873c..eb50a0b880 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -484,6 +484,7 @@ local function text_document_did_save_handler(bufnr) text = lsp._buf_get_full_text(bufnr), }, }) + util.buf_versions[bufnr] = 0 end local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save') if save_capability then @@ -519,6 +520,7 @@ local function buf_detach_client(bufnr, client) end client.attached_buffers[bufnr] = nil + util.buf_versions[bufnr] = nil local namespace = lsp.diagnostic.get_namespace(client.id) vim.diagnostic.reset(namespace, bufnr) @@ -574,11 +576,12 @@ local function buf_attach(bufnr) }) -- First time, so attach and set up stuff. api.nvim_buf_attach(bufnr, false, { - on_lines = function(_, _, _, firstline, lastline, new_lastline) + on_lines = function(_, _, changedtick, firstline, lastline, new_lastline) if #lsp.get_clients({ bufnr = bufnr }) == 0 then -- detach if there are no clients return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 end + util.buf_versions[bufnr] = changedtick changetracking.send_changes(bufnr, firstline, lastline, new_lastline) end, diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua index ce701f0772..b2be53269f 100644 --- a/runtime/lua/vim/lsp/_changetracking.lua +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -1,5 +1,6 @@ local protocol = require('vim.lsp.protocol') local sync = require('vim.lsp.sync') +local util = require('vim.lsp.util') local api = vim.api local uv = vim.uv @@ -276,7 +277,7 @@ local function send_changes(bufnr, sync_kind, state, buf_state) client.notify(protocol.Methods.textDocument_didChange, { textDocument = { uri = uri, - version = vim.b[bufnr].changedtick, + version = util.buf_versions[bufnr], }, contentChanges = changes, }) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index b28fe2f797..327cd19125 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -673,8 +673,8 @@ function Client:_request(method, params, handler, bufnr) end -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state changetracking.flush(self, bufnr) + local version = lsp.util.buf_versions[bufnr] bufnr = resolve_bufnr(bufnr) - local version = vim.b[bufnr].changedtick log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) local success, request_id = self.rpc.request(method, params, function(err, result) local context = { @@ -922,13 +922,14 @@ function Client:_text_document_did_open_handler(bufnr) local params = { textDocument = { - version = vim.b[bufnr].changedtick, + version = 0, uri = vim.uri_from_bufnr(bufnr), languageId = self.get_language_id(bufnr, filetype), text = lsp._buf_get_full_text(bufnr), }, } self.notify(ms.textDocument_didOpen, params) + lsp.util.buf_versions[bufnr] = params.textDocument.version -- Next chance we get, we should re-do the diagnostics vim.schedule(function() diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 8fd4ceefd2..2d784816cb 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -43,7 +43,7 @@ function M.on_inlayhint(err, result, ctx, _) return end local bufnr = assert(ctx.bufnr) - if vim.b[bufnr].changedtick ~= ctx.version then + if util.buf_versions[bufnr] ~= ctx.version then return end local client_id = ctx.client_id @@ -324,7 +324,7 @@ api.nvim_set_decoration_provider(namespace, { return end - if bufstate.version ~= vim.b[bufnr].changedtick then + if bufstate.version ~= util.buf_versions[bufnr] then return end diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index b2a8360aa2..279956658c 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -116,7 +116,7 @@ local function tokens_to_ranges(data, bufnr, client, request) if elapsed_ns > yield_interval_ns then vim.schedule(function() - coroutine.resume(co, vim.b[bufnr].changedtick) + coroutine.resume(co, util.buf_versions[bufnr]) end) if request.version ~= coroutine.yield() then -- request became stale since the last time the coroutine ran. @@ -269,7 +269,7 @@ end --- ---@package function STHighlighter:send_request() - local version = vim.b[self.bufnr].changedtick + local version = util.buf_versions[self.bufnr] self:reset_timer() @@ -412,7 +412,7 @@ end function STHighlighter:on_win(topline, botline) for client_id, state in pairs(self.client_state) do local current_result = state.current_result - if current_result.version and current_result.version == vim.b[self.bufnr].changedtick then + if current_result.version and current_result.version == util.buf_versions[self.bufnr] then if not current_result.namespace_cleared then api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) current_result.namespace_cleared = true diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 3215b40d1d..fc027cfcc0 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -502,11 +502,6 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) should_check_version = false end - -- changedtick increases on save but server only receives version updates - -- on line changes (via didChange) - -- This allows a gap of 1 to account for the servers outdated view - local version_offset = vim.b[bufnr].modified and 0 or 1 - -- `VersionedTextDocumentIdentifier`s version may be null -- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier if @@ -514,7 +509,8 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) and ( text_document.version and text_document.version > 0 - and vim.b[bufnr].changedtick > (text_document.version + version_offset) + and M.buf_versions[bufnr] + and M.buf_versions[bufnr] > text_document.version ) then print('Buffer ', text_document.uri, ' newer than edits.') @@ -2206,16 +2202,9 @@ function M._refresh(method, opts) end end ----@nodoc ----@deprecated ----@type table -M.buf_versions = setmetatable({}, { - __index = function(_, bufnr) - vim.deprecate('vim.lsp.util.buf_versions', 'vim.b.changedtick', '0.13') - return vim.b[bufnr].changedtick - end, -}) - M._get_line_byte_from_position = get_line_byte_from_position +---@nodoc +M.buf_versions = {} ---@type table + return M -- cgit From 2ce4a4d91e4abee0aab8b98c47eea9fbd4849ba6 Mon Sep 17 00:00:00 2001 From: Al Colmenar <57642956+alcolmenar@users.noreply.github.com> Date: Fri, 7 Jun 2024 02:54:43 -0700 Subject: fix(lsp): fix reverse sorting of same position text edits (#29212) Problem: Text edits with the same position (both line and character) were being reverse sorted prior to being applied which differs from the lsp spec Solution: Change the sort order for just the same position edits --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index fc027cfcc0..3d61af8b15 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -391,7 +391,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) return a.range.start.character > b.range.start.character end if a._index ~= b._index then - return a._index > b._index + return a._index < b._index end end) -- cgit From f3632e14e3a75114415050ab01c2d04a06036009 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:33:40 +0200 Subject: feat: get/set namespace properties #28728 ref https://github.com/neovim/neovim/pull/28432 ref https://github.com/neovim/neovim/issues/28469 --- runtime/lua/vim/_meta/api.lua | 51 +++++++++++++---------------------- runtime/lua/vim/_meta/api_keysets.lua | 3 +++ runtime/lua/vim/highlight.lua | 9 ++----- 3 files changed, 24 insertions(+), 39 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index bb27ee4269..d91b2d08bf 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -99,6 +99,25 @@ function vim.api.nvim__inspect_cell(grid, row, col) end --- function vim.api.nvim__invalidate_glyph_cache() end +--- @private +--- EXPERIMENTAL: this API will change in the future. +--- +--- Get the properties for namespace +--- +--- @param ns_id integer Namespace +--- @return vim.api.keyset.ns_opts +function vim.api.nvim__ns_get(ns_id) end + +--- @private +--- EXPERIMENTAL: this API will change in the future. +--- +--- Set some properties for namespace +--- +--- @param ns_id integer Namespace +--- @param opts vim.api.keyset.ns_opts Optional parameters to set: +--- • wins: a list of windows to be scoped in +function vim.api.nvim__ns_set(ns_id, opts) end + --- @private --- EXPERIMENTAL: this API may change in the future. --- @@ -144,36 +163,6 @@ function vim.api.nvim__stats() end --- @return any function vim.api.nvim__unpack(str) end ---- @private ---- EXPERIMENTAL: this API will change in the future. ---- ---- Scopes a namespace to the a window, so extmarks in the namespace will be ---- active only in the given window. ---- ---- @param window integer Window handle, or 0 for current window ---- @param ns_id integer Namespace ---- @return boolean -function vim.api.nvim__win_add_ns(window, ns_id) end - ---- @private ---- EXPERIMENTAL: this API will change in the future. ---- ---- Unscopes a namespace (un-binds it from the given scope). ---- ---- @param window integer Window handle, or 0 for current window ---- @param ns_id integer the namespace to remove ---- @return boolean -function vim.api.nvim__win_del_ns(window, ns_id) end - ---- @private ---- EXPERIMENTAL: this API will change in the future. ---- ---- Gets the namespace scopes for a given window. ---- ---- @param window integer Window handle, or 0 for current window ---- @return integer[] -function vim.api.nvim__win_get_ns(window) end - --- Adds a highlight to buffer. --- --- Useful for plugins that dynamically generate highlights to a buffer (like @@ -686,8 +675,6 @@ function vim.api.nvim_buf_line_count(buffer) end --- • url: A URL to associate with this extmark. In the TUI, the --- OSC 8 control sequence is used to generate a clickable --- hyperlink to this URL. ---- • scoped: boolean (EXPERIMENTAL) enables "scoping" for the ---- extmark. See `nvim__win_add_ns()` --- @return integer function vim.api.nvim_buf_set_extmark(buffer, ns_id, line, col, opts) end diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua index f7cd92a3b2..2fe5c32faf 100644 --- a/runtime/lua/vim/_meta/api_keysets.lua +++ b/runtime/lua/vim/_meta/api_keysets.lua @@ -197,6 +197,9 @@ error('Cannot require a meta file') --- @field desc? string --- @field replace_keycodes? boolean +--- @class vim.api.keyset.ns_opts +--- @field wins? any[] + --- @class vim.api.keyset.open_term --- @field on_input? function --- @field force_crlf? boolean diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index e972ffaa8c..233bc50237 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -31,8 +31,6 @@ M.priorities = { --- Indicates priority of highlight --- (default: `vim.highlight.priorities.user`) --- @field priority? integer ---- ---- @field package _scoped? boolean --- Apply highlight group to range of text. --- @@ -47,7 +45,6 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local regtype = opts.regtype or 'v' local inclusive = opts.inclusive or false local priority = opts.priority or M.priorities.user - local scoped = opts._scoped or false local v_maxcol = vim.v.maxcol @@ -114,7 +111,6 @@ function M.range(bufnr, ns, higroup, start, finish, opts) end_col = end_col, priority = priority, strict = false, - scoped = scoped, }) end end @@ -178,19 +174,18 @@ function M.on_yank(opts) yank_cancel() end - vim.api.nvim__win_add_ns(winid, yank_ns) + vim.api.nvim__ns_set(yank_ns, { wins = { winid } }) M.range(bufnr, yank_ns, higroup, "'[", "']", { regtype = event.regtype, inclusive = event.inclusive, priority = opts.priority or M.priorities.user, - _scoped = true, }) yank_cancel = function() yank_timer = nil yank_cancel = nil pcall(vim.api.nvim_buf_clear_namespace, bufnr, yank_ns, 0, -1) - pcall(vim.api.nvim__win_del_ns, winid, yank_ns) + pcall(vim.api.nvim__ns_set, { wins = {} }) end yank_timer = vim.defer_fn(yank_cancel, timeout) -- cgit From da6f68ee6966ebf434eee840b22a4f45e61d77dd Mon Sep 17 00:00:00 2001 From: Lennard Hofmann Date: Fri, 7 Jun 2024 21:43:17 +0200 Subject: fix(man): filter OSC 8 hyperlink markup #29171 Problem: `man cmake` shows "8;;https://cmake.orghttps://cmake.org8;;" Solution: Remove noise so that it shows as "https://cmake.org". See also: https://en.wikipedia.org/wiki/ANSI_escape_code#OSC --- runtime/lua/man.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index 02e841030f..348e502f34 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -35,7 +35,7 @@ local function highlight_line(line, linenr) ---@type string[] local chars = {} local prev_char = '' - local overstrike, escape = false, false + local overstrike, escape, osc8 = false, false, false ---@type table local hls = {} -- Store highlight groups as { attr, start, final } @@ -139,6 +139,12 @@ local function highlight_line(line, linenr) prev_char = '' byte = byte + #char chars[#chars + 1] = char + elseif osc8 then + -- eat characters until String Terminator or bell + if (prev_char == '\027' and char == '\\') or char == '\a' then + osc8 = false + end + prev_char = char elseif escape then -- Use prev_char to store the escape sequence prev_char = prev_char .. char @@ -157,8 +163,11 @@ local function highlight_line(line, linenr) add_attr_hl(match + 0) -- coerce to number end escape = false - elseif not prev_char:match('^%[[\032-\063]*$') then - -- Stop looking if this isn't a partial CSI sequence + elseif prev_char == ']8;' then + osc8 = true + escape = false + elseif not prev_char:match('^[][][\032-\063]*$') then + -- Stop looking if this isn't a partial CSI or OSC sequence escape = false end elseif char == '\027' then -- cgit From 9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 19:04:28 +0200 Subject: feat(lua): add `vim._with` It's a function to perform operations in their own sealed context, similar to pythons `with`. This helps ease operations where you need to perform an operation in a specific context, and then restore the context. Marked as private for now as it's not ready for public use. The current plan is to start using this internally so we can discover and fix any problems. Once this is ready to be exposed it will be renamed to `vim.with`. Usage: ```lua local ret = vim._with({context = val}, function() return "hello" end) ``` , where `context` is any combination of: - `buf` - `emsg_silent` - `hide` - `horizontal` - `keepalt` - `keepjumps` - `keepmarks` - `keeppatterns` - `lockmarks` - `noautocmd` - `options` - `sandbox` - `silent` - `unsilent` - `win` (except for `win` and `buf` which can't be used at the same time). This list will most likely be expanded in the future. Work on https://github.com/neovim/neovim/issues/19832. Co-authored-by: Lewis Russell --- runtime/lua/vim/_comment.lua | 11 ++----- runtime/lua/vim/shared.lua | 78 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 8 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_comment.lua b/runtime/lua/vim/_comment.lua index 044cd69716..efe289b3e1 100644 --- a/runtime/lua/vim/_comment.lua +++ b/runtime/lua/vim/_comment.lua @@ -194,14 +194,9 @@ local function toggle_lines(line_start, line_end, ref_position) -- - Debatable for highlighting in text area (like LSP semantic tokens). -- Mostly because it causes flicker as highlighting is preserved during -- comment toggling. - package.loaded['vim._comment']._lines = vim.tbl_map(f, lines) - local lua_cmd = string.format( - 'vim.api.nvim_buf_set_lines(0, %d, %d, false, package.loaded["vim._comment"]._lines)', - line_start - 1, - line_end - ) - vim.cmd.lua({ lua_cmd, mods = { lockmarks = true } }) - package.loaded['vim._comment']._lines = nil + vim._with({ lockmarks = true }, function() + vim.api.nvim_buf_set_lines(0, line_start - 1, line_end, false, vim.tbl_map(f, lines)) + end) end --- Operator which toggles user-supplied range of lines diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 9d54a80144..7fd29d5f7b 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -1139,4 +1139,82 @@ function vim._defer_require(root, mod) }) end +--- @nodoc +--- @class vim.context.mods +--- @field buf? integer +--- @field emsg_silent? boolean +--- @field hide? boolean +--- @field horizontal? boolean +--- @field keepalt? boolean +--- @field keepjumps? boolean +--- @field keepmarks? boolean +--- @field keeppatterns? boolean +--- @field lockmarks? boolean +--- @field noautocmd? boolean +--- @field options? table +--- @field sandbox? boolean +--- @field silent? boolean +--- @field unsilent? boolean +--- @field win? integer + +--- Executes function `f` with the given context specification. +--- +--- @param context vim.context.mods +function vim._with(context, f) + vim.validate('context', context, 'table') + vim.validate('f', f, 'function') + + vim.validate('context.buf', context.buf, 'number', true) + vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true) + vim.validate('context.hide', context.hide, 'boolean', true) + vim.validate('context.horizontal', context.horizontal, 'boolean', true) + vim.validate('context.keepalt', context.keepalt, 'boolean', true) + vim.validate('context.keepjumps', context.keepjumps, 'boolean', true) + vim.validate('context.keepmarks', context.keepmarks, 'boolean', true) + vim.validate('context.keeppatterns', context.keeppatterns, 'boolean', true) + vim.validate('context.lockmarks', context.lockmarks, 'boolean', true) + vim.validate('context.noautocmd', context.noautocmd, 'boolean', true) + vim.validate('context.options', context.options, 'table', true) + vim.validate('context.sandbox', context.sandbox, 'boolean', true) + vim.validate('context.silent', context.silent, 'boolean', true) + vim.validate('context.unsilent', context.unsilent, 'boolean', true) + vim.validate('context.win', context.win, 'number', true) + + -- Check buffer exists + if context.buf then + if not vim.api.nvim_buf_is_valid(context.buf) then + error('Invalid buffer id: ' .. context.buf) + end + end + + -- Check window exists + if context.win then + if not vim.api.nvim_win_is_valid(context.win) then + error('Invalid window id: ' .. context.win) + end + end + + -- Store original options + local previous_options ---@type table + if context.options then + previous_options = {} + for k, v in pairs(context.options) do + previous_options[k] = + vim.api.nvim_get_option_value(k, { win = context.win, buf = context.buf }) + vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf }) + end + end + + local retval = { vim._with_c(context, f) } + + -- Restore original options + if previous_options then + for k, v in pairs(previous_options) do + vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf }) + end + end + + return unpack(retval) +end + return vim -- cgit From 6592873f773b4c358ea950bfcfa8cbc3fc3bc8cc Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 8 Jun 2024 10:49:15 +0200 Subject: feat(help): use treesitter for table of contents Problem: Creating the table of contents for `gO` is complicated. Solution: Use treesitter instead. --- runtime/lua/vim/vimhelp.lua | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/vimhelp.lua b/runtime/lua/vim/vimhelp.lua index 4af6866d48..33324602c9 100644 --- a/runtime/lua/vim/vimhelp.lua +++ b/runtime/lua/vim/vimhelp.lua @@ -30,4 +30,42 @@ function M.highlight_groups(patterns) vim.fn.setpos('.', save_cursor) end +--- Show a table of contents for the help buffer in a loclist +function M.show_toc() + local bufnr = vim.api.nvim_get_current_buf() + local parser = vim.treesitter.get_parser(bufnr, 'vimdoc') + local query = vim.treesitter.query.parse( + parser:lang(), + [[ + (h1 (heading) @h1) + (h2 (heading) @h2) + (h3 (heading) @h3) + (column_heading (heading) @h4) + ]] + ) + local root = parser:parse()[1]:root() + local headings = {} + for id, node, _, _ in query:iter_captures(root, bufnr) do + local text = vim.treesitter.get_node_text(node, bufnr) + local capture = query.captures[id] + local row, col = node:start() + -- only column_headings at col 1 are headings, otherwise it's code examples + local is_code = (capture == 'h4' and col > 0) + -- ignore tabular material + local is_table = (capture == 'h4' and (text:find('\t') or text:find(' '))) + -- ignore tag-only headings + local is_tag = node:child_count() == 1 and node:child(0):type() == 'tag' + if not (is_code or is_table or is_tag) then + table.insert(headings, { + bufnr = bufnr, + lnum = row + 1, + text = (capture == 'h3' or capture == 'h4') and '  ' .. text or text, + }) + end + end + vim.fn.setloclist(0, headings, ' ') + vim.fn.setloclist(0, {}, 'a', { title = 'Help TOC' }) + vim.cmd.lopen() +end + return M -- cgit From 20f22f75ee629ae2db4cd99e730fa0af26553177 Mon Sep 17 00:00:00 2001 From: Tom Praschan <13141438+tom-anders@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:14:55 +0200 Subject: feat(lsp): include end_col, end_lnum in vim.lsp.buf.locations_to_items #29164 --- runtime/lua/vim/lsp/util.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 3d61af8b15..088d57b6d6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1722,7 +1722,9 @@ end) ---@inlinedoc ---@field filename string ---@field lnum integer 1-indexed line number +---@field end_lnum integer 1-indexed end line number ---@field col integer 1-indexed column +---@field end_col integer 1-indexed end column ---@field text string ---@field user_data lsp.Location|lsp.LocationLink @@ -1749,7 +1751,7 @@ function M.locations_to_items(locations, offset_encoding) end local items = {} - ---@type table + ---@type table local grouped = setmetatable({}, { __index = function(t, k) local v = {} @@ -1761,7 +1763,7 @@ function M.locations_to_items(locations, offset_encoding) -- locations may be Location or LocationLink local uri = d.uri or d.targetUri local range = d.range or d.targetSelectionRange - table.insert(grouped[uri], { start = range.start, location = d }) + table.insert(grouped[uri], { start = range.start, ['end'] = range['end'], location = d }) end ---@type string[] @@ -1776,6 +1778,9 @@ function M.locations_to_items(locations, offset_encoding) local line_numbers = {} for _, temp in ipairs(rows) do table.insert(line_numbers, temp.start.line) + if temp.start.line ~= temp['end'].line then + table.insert(line_numbers, temp['end'].line) + end end -- get all the lines for this uri @@ -1783,13 +1788,18 @@ function M.locations_to_items(locations, offset_encoding) for _, temp in ipairs(rows) do local pos = temp.start + local end_pos = temp['end'] local row = pos.line + local end_row = end_pos.line local line = lines[row] or '' local col = M._str_byteindex_enc(line, pos.character, offset_encoding) + local end_col = M._str_byteindex_enc(lines[end_row] or '', end_pos.character, offset_encoding) table.insert(items, { filename = filename, lnum = row + 1, + end_lnum = end_row + 1, col = col + 1, + end_col = end_col + 1, text = line, user_data = temp.location, }) -- cgit From 4bd86120d41e3b01433004bf761beccb7f3a0167 Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Mon, 10 Jun 2024 06:23:03 -0500 Subject: fix(glob): handle overlapping `{}` condition elements #29236 This change fixes an issue where glob patterns like `{a,ab}` would not match `ab` because the first option `a` matches, then the end of the string is expected but `b` is found, and LPeg does not backtrack to try the next option `ab` which would match. The fix here is to also append the rest of the pattern to the generated LPeg pattern for each option. This changes a glob `{a,ab}` from being parsed as ("a" or "ab") "end of string" to ("a" "end of string" or "ab" "end of string") Here, matching against `ab` would try the first option, fail to match, then proceed to the next option, and match. The sacrifice this change makes is dropping support for nested `{}` conditions, which VSCode doesn't seem to support or test AFAICT. Fixes #28931 Co-authored-by: Sergey Slipchenko --- runtime/lua/vim/glob.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/glob.lua b/runtime/lua/vim/glob.lua index ad4a915a94..6de2bc3e94 100644 --- a/runtime/lua/vim/glob.lua +++ b/runtime/lua/vim/glob.lua @@ -29,8 +29,10 @@ function M.to_lpeg(pattern) return patt end - local function add(acc, a) - return acc + a + local function condlist(conds, after) + return vim.iter(conds):fold(P(false), function(acc, cond) + return acc + cond * after + end) end local function mul(acc, m) @@ -63,15 +65,14 @@ function M.to_lpeg(pattern) * C(P('!') ^ -1) * Ct(Ct(C(P(1)) * P('-') * C(P(1) - P(']'))) ^ 1 * P(']')) / class, - CondList = P('{') * Cf(V('Cond') * (P(',') * V('Cond')) ^ 0, add) * P('}'), + CondList = P('{') * Ct(V('Cond') * (P(',') * V('Cond')) ^ 0) * P('}') * V('Pattern') / condlist, -- TODO: '*' inside a {} condition is interpreted literally but should probably have the same -- wildcard semantics it usually has. -- Fixing this is non-trivial because '*' should match non-greedily up to "the rest of the -- pattern" which in all other cases is the entire succeeding part of the pattern, but at the end of a {} -- condition means "everything after the {}" where several other options separated by ',' may -- exist in between that should not be matched by '*'. - Cond = Cf((V('Ques') + V('Class') + V('CondList') + (V('Literal') - S(',}'))) ^ 1, mul) - + Cc(P(0)), + Cond = Cf((V('Ques') + V('Class') + V('Literal') - S(',}')) ^ 1, mul) + Cc(P(0)), Literal = P(1) / P, End = P(-1) * Cc(P(-1)), }) -- cgit From 37bf4c572a8fa20dc4a8433524ecc8c8d68fe53c Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Mon, 10 Jun 2024 12:53:08 -0400 Subject: fix(lsp): do not reset buf version when detaching client (#29242) --- runtime/lua/vim/lsp.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index eb50a0b880..623ccdd5cd 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -520,7 +520,6 @@ local function buf_detach_client(bufnr, client) end client.attached_buffers[bufnr] = nil - util.buf_versions[bufnr] = nil local namespace = lsp.diagnostic.get_namespace(client.id) vim.diagnostic.reset(namespace, bufnr) @@ -605,6 +604,7 @@ local function buf_attach(bufnr) buf_detach_client(bufnr, client) end attached_buffers[bufnr] = nil + util.buf_versions[bufnr] = nil end, -- TODO if we know all of the potential clients ahead of time, then we -- cgit From 5e49ef0af3cb8dba658e5d0dc6a807f8edebf590 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 11 Jun 2024 12:05:18 +0100 Subject: refactor(lua): improve type annotations --- runtime/lua/vim/_meta/builtin.lua | 1 + runtime/lua/vim/_meta/builtin_types.lua | 5 + runtime/lua/vim/_meta/vimfn.lua | 4 +- runtime/lua/vim/lsp/_dynamic.lua | 4 - runtime/lua/vim/lsp/client.lua | 11 +- runtime/lua/vim/lsp/handlers.lua | 1 + runtime/lua/vim/lsp/log.lua | 2 +- runtime/lua/vim/lsp/protocol.lua | 342 +--------------------------- runtime/lua/vim/lsp/rpc.lua | 4 +- runtime/lua/vim/lsp/semantic_tokens.lua | 1 - runtime/lua/vim/lsp/util.lua | 21 +- runtime/lua/vim/treesitter/_fold.lua | 1 - runtime/lua/vim/treesitter/_meta.lua | 2 + runtime/lua/vim/treesitter/highlighter.lua | 6 +- runtime/lua/vim/treesitter/languagetree.lua | 10 +- 15 files changed, 51 insertions(+), 364 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua index 75737bd040..3aca3cdfa5 100644 --- a/runtime/lua/vim/_meta/builtin.lua +++ b/runtime/lua/vim/_meta/builtin.lua @@ -121,6 +121,7 @@ function vim.stricmp(a, b) end --- @param str string --- @param index integer --- @param use_utf16? boolean +--- @return integer function vim.str_byteindex(str, index, use_utf16) end --- Gets a list of the starting byte positions of each UTF-8 codepoint in the given string. diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua index 53dd8d95e9..9afb8c84f4 100644 --- a/runtime/lua/vim/_meta/builtin_types.lua +++ b/runtime/lua/vim/_meta/builtin_types.lua @@ -34,6 +34,11 @@ --- @field filename? string --- @field lnum integer +--- @class vim.fn.getmarklist.ret.item +--- @field mark string +--- @field pos [integer, integer, integer, integer] +--- @field file string + --- @class vim.fn.getmousepos.ret --- @field screenrow integer --- @field screencol integer diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index a1600e1cb5..e38c475d09 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3249,8 +3249,8 @@ function vim.fn.getloclist(nr, what) end --- Refer to |getpos()| for getting information about a specific --- mark. --- ---- @param buf? any ---- @return any +--- @param buf? integer? +--- @return vim.fn.getmarklist.ret.item[] function vim.fn.getmarklist(buf) end --- Returns a |List| with all matches previously defined for the diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 819b03a63a..27113c0e74 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -24,7 +24,6 @@ function M:supports_registration(method) end --- @param registrations lsp.Registration[] ---- @package function M:register(registrations) -- remove duplicates self:unregister(registrations) @@ -38,7 +37,6 @@ function M:register(registrations) end --- @param unregisterations lsp.Unregistration[] ---- @package function M:unregister(unregisterations) for _, unreg in ipairs(unregisterations) do local method = unreg.method @@ -58,7 +56,6 @@ end --- @param method string --- @param opts? {bufnr: integer?} --- @return lsp.Registration? (table|nil) the registration if found ---- @package function M:get(method, opts) opts = opts or {} opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf() @@ -78,7 +75,6 @@ end --- @param method string --- @param opts? {bufnr: integer?} ---- @package function M:supports(method, opts) return self:get(method, opts) ~= nil end diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 327cd19125..d3ff918792 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -436,7 +436,7 @@ local function ensure_list(x) return { x } end ---- @package +--- @nodoc --- @param config vim.lsp.ClientConfig --- @return vim.lsp.Client? function Client.create(config) @@ -535,7 +535,7 @@ function Client:_run_callbacks(cbs, error_id, ...) end end ---- @package +--- @nodoc function Client:initialize() local config = self.config @@ -656,7 +656,7 @@ end --- @param method string LSP method name. --- @param params? table LSP request params. --- @param handler? lsp.Handler Response |lsp-handler| for this method. ---- @param bufnr? integer Buffer handle (0 for current). +--- @param bufnr integer Buffer handle (0 for current). --- @return boolean status, integer? request_id {status} is a bool indicating --- whether the request was successful. If it is `false`, then it will --- always be `false` (the client has shutdown). If it was @@ -861,7 +861,6 @@ function Client:_is_stopped() return self.rpc.is_closing() end ---- @package --- Execute a lsp command, either via client command function (if available) --- or via workspace/executeCommand (if supported by the server) --- @@ -906,7 +905,6 @@ function Client:_exec_cmd(command, context, handler, on_unsupported) self.request(ms.workspace_executeCommand, params, handler, context.bufnr) end ---- @package --- Default handler for the 'textDocument/didOpen' LSP notification. --- --- @param bufnr integer Number of the buffer, or 0 for current @@ -942,7 +940,6 @@ function Client:_text_document_did_open_handler(bufnr) end) end ---- @package --- Runs the on_attach function from the client's config if it was defined. --- @param bufnr integer Buffer number function Client:_on_attach(bufnr) @@ -1065,7 +1062,6 @@ function Client:_on_exit(code, signal) ) end ---- @package --- Add a directory to the workspace folders. --- @param dir string? function Client:_add_workspace_folder(dir) @@ -1088,7 +1084,6 @@ function Client:_add_workspace_folder(dir) vim.list_extend(self.workspace_folders, wf) end ---- @package --- Remove a directory to the workspace folders. --- @param dir string? function Client:_remove_workspace_folder(dir) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 38c43893eb..44548fec92 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -646,6 +646,7 @@ M[ms.window_showMessage] = function(_, result, ctx, _) if message_type == protocol.MessageType.Error then err_message('LSP[', client_name, '] ', message) else + --- @type string local message_type_name = protocol.MessageType[message_type] api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message)) end diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 9f2bd71158..0438ca84af 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -9,7 +9,7 @@ local log_levels = vim.log.levels --- Can be used to lookup the number from the name or the name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" --- Level numbers begin with "TRACE" at 0 ---- @type table +--- @type table | table --- @nodoc log.levels = vim.deepcopy(log_levels) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 8ac4cc794b..eb18043843 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -12,9 +12,6 @@ end local sysname = vim.uv.os_uname().sysname --- Protocol for the Microsoft Language Server Protocol (mslsp) -local protocol = {} - local constants = { --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { @@ -46,6 +43,8 @@ local constants = { Info = 3, -- A log message. Log = 4, + -- A debug message. + Debug = 5, }, -- The file event type. @@ -308,326 +307,18 @@ local constants = { }, } -for k1, v1 in pairs(constants) do - local tbl = vim.deepcopy(v1, true) - for _, k2 in ipairs(vim.tbl_keys(tbl)) do - local v2 = tbl[k2] - tbl[v2] = k2 +-- Protocol for the Microsoft Language Server Protocol (mslsp) +local protocol = {} + +--- @diagnostic disable:no-unknown +for k1, v1 in pairs(vim.deepcopy(constants, true)) do + for _, k2 in ipairs(vim.tbl_keys(v1)) do + local v2 = v1[k2] + v1[v2] = k2 end - protocol[k1] = tbl + protocol[k1] = v1 end - ---[=[ ---Text document specific client capabilities. -export interface TextDocumentClientCapabilities { - synchronization?: { - --Whether text document synchronization supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports sending will save notifications. - willSave?: boolean; - --The client supports sending a will save request and - --waits for a response providing text edits which will - --be applied to the document before it is saved. - willSaveWaitUntil?: boolean; - --The client supports did save notifications. - didSave?: boolean; - } - --Capabilities specific to the `textDocument/completion` - completion?: { - --Whether completion supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports the following `CompletionItem` specific - --capabilities. - completionItem?: { - --The client supports snippets as insert text. - -- - --A snippet can define tab stops and placeholders with `$1`, `$2` - --and `${3:foo}`. `$0` defines the final tab stop, it defaults to - --the end of the snippet. Placeholders with equal identifiers are linked, - --that is typing in one will update others too. - snippetSupport?: boolean; - --The client supports commit characters on a completion item. - commitCharactersSupport?: boolean - --The client supports the following content formats for the documentation - --property. The order describes the preferred format of the client. - documentationFormat?: MarkupKind[]; - --The client supports the deprecated property on a completion item. - deprecatedSupport?: boolean; - --The client supports the preselect property on a completion item. - preselectSupport?: boolean; - } - completionItemKind?: { - --The completion item kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - -- - --If this property is not present the client only supports - --the completion items kinds from `Text` to `Reference` as defined in - --the initial version of the protocol. - valueSet?: CompletionItemKind[]; - }, - --The client supports to send additional context information for a - --`textDocument/completion` request. - contextSupport?: boolean; - }; - --Capabilities specific to the `textDocument/hover` - hover?: { - --Whether hover supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports the follow content formats for the content - --property. The order describes the preferred format of the client. - contentFormat?: MarkupKind[]; - }; - --Capabilities specific to the `textDocument/signatureHelp` - signatureHelp?: { - --Whether signature help supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports the following `SignatureInformation` - --specific properties. - signatureInformation?: { - --The client supports the follow content formats for the documentation - --property. The order describes the preferred format of the client. - documentationFormat?: MarkupKind[]; - --Client capabilities specific to parameter information. - parameterInformation?: { - --The client supports processing label offsets instead of a - --simple label string. - -- - --Since 3.14.0 - labelOffsetSupport?: boolean; - } - }; - }; - --Capabilities specific to the `textDocument/references` - references?: { - --Whether references supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentHighlight` - documentHighlight?: { - --Whether document highlight supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentSymbol` - documentSymbol?: { - --Whether document symbol supports dynamic registration. - dynamicRegistration?: boolean; - --Specific capabilities for the `SymbolKind`. - symbolKind?: { - --The symbol kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - -- - --If this property is not present the client only supports - --the symbol kinds from `File` to `Array` as defined in - --the initial version of the protocol. - valueSet?: SymbolKind[]; - } - --The client supports hierarchical document symbols. - hierarchicalDocumentSymbolSupport?: boolean; - }; - --Capabilities specific to the `textDocument/formatting` - formatting?: { - --Whether formatting supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/rangeFormatting` - rangeFormatting?: { - --Whether range formatting supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/onTypeFormatting` - onTypeFormatting?: { - --Whether on type formatting supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/declaration` - declaration?: { - --Whether declaration supports dynamic registration. If this is set to `true` - --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of declaration links. - -- - --Since 3.14.0 - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/definition`. - -- - --Since 3.14.0 - definition?: { - --Whether definition supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of definition links. - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/typeDefinition` - -- - --Since 3.6.0 - typeDefinition?: { - --Whether typeDefinition supports dynamic registration. If this is set to `true` - --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of definition links. - -- - --Since 3.14.0 - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/implementation`. - -- - --Since 3.6.0 - implementation?: { - --Whether implementation supports dynamic registration. If this is set to `true` - --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of definition links. - -- - --Since 3.14.0 - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/codeAction` - codeAction?: { - --Whether code action supports dynamic registration. - dynamicRegistration?: boolean; - --The client support code action literals as a valid - --response of the `textDocument/codeAction` request. - -- - --Since 3.8.0 - codeActionLiteralSupport?: { - --The code action kind is support with the following value - --set. - codeActionKind: { - --The code action kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - valueSet: CodeActionKind[]; - }; - }; - }; - --Capabilities specific to the `textDocument/codeLens` - codeLens?: { - --Whether code lens supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentLink` - documentLink?: { - --Whether document link supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentColor` and the - --`textDocument/colorPresentation` request. - -- - --Since 3.6.0 - colorProvider?: { - --Whether colorProvider supports dynamic registration. If this is set to `true` - --the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - } - --Capabilities specific to the `textDocument/rename` - rename?: { - --Whether rename supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports testing for validity of rename operations - --before execution. - prepareSupport?: boolean; - }; - --Capabilities specific to `textDocument/publishDiagnostics`. - publishDiagnostics?: { - --Whether the clients accepts diagnostics with related information. - relatedInformation?: boolean; - --Client supports the tag property to provide meta data about a diagnostic. - --Clients supporting tags have to handle unknown tags gracefully. - --Since 3.15.0 - tagSupport?: { - --The tags supported by this client - valueSet: DiagnosticTag[]; - }; - }; - --Capabilities specific to `textDocument/foldingRange` requests. - -- - --Since 3.10.0 - foldingRange?: { - --Whether implementation supports dynamic registration for folding range providers. If this is set to `true` - --the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The maximum number of folding ranges that the client prefers to receive per document. The value serves as a - --hint, servers are free to follow the limit. - rangeLimit?: number; - --If set, the client signals that it only supports folding complete lines. If set, client will - --ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. - lineFoldingOnly?: boolean; - }; -} ---]=] - ---[=[ ---Workspace specific client capabilities. -export interface WorkspaceClientCapabilities { - --The client supports applying batch edits to the workspace by supporting - --the request 'workspace/applyEdit' - applyEdit?: boolean; - --Capabilities specific to `WorkspaceEdit`s - workspaceEdit?: { - --The client supports versioned document changes in `WorkspaceEdit`s - documentChanges?: boolean; - --The resource operations the client supports. Clients should at least - --support 'create', 'rename' and 'delete' files and folders. - resourceOperations?: ResourceOperationKind[]; - --The failure handling strategy of a client if applying the workspace edit - --fails. - failureHandling?: FailureHandlingKind; - }; - --Capabilities specific to the `workspace/didChangeConfiguration` notification. - didChangeConfiguration?: { - --Did change configuration notification supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `workspace/didChangeWatchedFiles` notification. - didChangeWatchedFiles?: { - --Did change watched files notification supports dynamic registration. Please note - --that the current protocol doesn't support static configuration for file changes - --from the server side. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `workspace/symbol` request. - symbol?: { - --Symbol request supports dynamic registration. - dynamicRegistration?: boolean; - --Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. - symbolKind?: { - --The symbol kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - -- - --If this property is not present the client only supports - --the symbol kinds from `File` to `Array` as defined in - --the initial version of the protocol. - valueSet?: SymbolKind[]; - } - }; - --Capabilities specific to the `workspace/executeCommand` request. - executeCommand?: { - --Execute command supports dynamic registration. - dynamicRegistration?: boolean; - }; - --The client has support for workspace folders. - -- - --Since 3.6.0 - workspaceFolders?: boolean; - --The client supports `workspace/configuration` requests. - -- - --Since 3.6.0 - configuration?: boolean; -} ---]=] +--- @diagnostic enable:no-unknown --- Gets a new ClientCapabilities object describing the LSP client --- capabilities. @@ -1250,14 +941,5 @@ protocol.Methods = { --- The `workspace/workspaceFolders` is sent from the server to the client to fetch the open workspace folders. workspace_workspaceFolders = 'workspace/workspaceFolders', } -local function freeze(t) - return setmetatable({}, { - __index = t, - __newindex = function() - error('cannot modify immutable table') - end, - }) -end -protocol.Methods = freeze(protocol.Methods) return protocol diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 3c63a12da2..5e2b041a0a 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -140,7 +140,7 @@ local client_errors = { SERVER_RESULT_CALLBACK_ERROR = 7, } ---- @type table +--- @type table | table --- @nodoc M.client_errors = vim.deepcopy(client_errors) for k, v in pairs(client_errors) do @@ -502,7 +502,7 @@ function Client:handle_body(body) if decoded.error then decoded.error = setmetatable(decoded.error, { __tostring = M.format_rpc_error, - }) --- @type table + }) end self:try_call( M.client_errors.SERVER_RESULT_CALLBACK_ERROR, diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index 279956658c..f92c0eb2e6 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -773,7 +773,6 @@ function M.highlight_token(token, bufnr, client_id, hl_group, opts) }) end ---- @package --- |lsp-handler| for the method `workspace/semanticTokens/refresh` --- --- Refresh requests are sent by the server to indicate a project-wide change diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 088d57b6d6..ae6de591b3 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -238,6 +238,7 @@ end ---@param rows integer[] zero-indexed line numbers ---@return table|string a table mapping rows to lines local function get_lines(bufnr, rows) + --- @type integer[] rows = type(rows) == 'table' and rows or { rows } -- This is needed for bufload and bufloaded @@ -246,7 +247,7 @@ local function get_lines(bufnr, rows) end local function buf_lines() - local lines = {} + local lines = {} --- @type table for _, row in ipairs(rows) do lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1] end @@ -274,11 +275,11 @@ local function get_lines(bufnr, rows) if not fd then return '' end - local stat = uv.fs_fstat(fd) - local data = uv.fs_read(fd, stat.size, 0) + local stat = assert(uv.fs_fstat(fd)) + local data = assert(uv.fs_read(fd, stat.size, 0)) uv.fs_close(fd) - local lines = {} -- rows we need to retrieve + local lines = {} --- @type table rows we need to retrieve local need = 0 -- keep track of how many unique rows we need for _, row in pairs(rows) do if not lines[row] then @@ -307,7 +308,7 @@ local function get_lines(bufnr, rows) lines[i] = '' end end - return lines + return lines --[[@as table]] end --- Gets the zero-indexed line from the given buffer. @@ -322,7 +323,8 @@ local function get_line(bufnr, row) end --- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position ----@param offset_encoding string|nil utf-8|utf-16|utf-32 +---@param position lsp.Position +---@param offset_encoding? string utf-8|utf-16|utf-32 ---@return integer local function get_line_byte_from_position(bufnr, position, offset_encoding) -- LSP's line and characters are 0-indexed @@ -366,6 +368,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Fix reversed range and indexing each text_edits local index = 0 + --- @param text_edit lsp.TextEdit text_edits = vim.tbl_map(function(text_edit) index = index + 1 text_edit._index = index @@ -383,6 +386,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) end, text_edits) -- Sort text_edits + ---@param a lsp.TextEdit | { _index: integer } + ---@param b lsp.TextEdit | { _index: integer } + ---@return boolean table.sort(text_edits, function(a, b) if a.range.start.line ~= b.range.start.line then return a.range.start.line > b.range.start.line @@ -393,10 +399,11 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) if a._index ~= b._index then return a._index < b._index end + return false end) -- save and restore local marks since they get deleted by nvim_buf_set_lines - local marks = {} + local marks = {} --- @type table for _, m in pairs(vim.fn.getmarklist(bufnr)) do if m.mark:match("^'[a-z]$") then marks[m.mark:sub(2, 2)] = { m.pos[2], m.pos[3] - 1 } -- api-indexed diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua index eecf1ad6b1..04a3c62cf1 100644 --- a/runtime/lua/vim/treesitter/_fold.lua +++ b/runtime/lua/vim/treesitter/_fold.lua @@ -383,7 +383,6 @@ local function on_bytes(bufnr, foldinfo, start_row, start_col, old_row, old_col, end end ----@package ---@param lnum integer|nil ---@return string function M.foldexpr(lnum) diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua index 177699a207..2aedf5754e 100644 --- a/runtime/lua/vim/treesitter/_meta.lua +++ b/runtime/lua/vim/treesitter/_meta.lua @@ -33,6 +33,7 @@ error('Cannot require a meta file') ---@field iter_children fun(self: TSNode): fun(): TSNode, string ---@field field fun(self: TSNode, name: string): TSNode[] ---@field byte_length fun(self: TSNode): integer +---@field __has_ancestor fun(self: TSNode, node_types: string[]): boolean local TSNode = {} ---@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string) @@ -62,6 +63,7 @@ local TSNode = {} ---@field patterns table --- @param lang string +--- @return table vim._ts_inspect_language = function(lang) end ---@return integer diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d2f986b874..003f7e0169 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -47,7 +47,7 @@ function TSHighlighterQuery:get_hl_from_capture(capture) return self.hl_cache[capture] end ----@package +---@nodoc function TSHighlighterQuery:query() return self._query end @@ -75,7 +75,7 @@ local TSHighlighter = { TSHighlighter.__index = TSHighlighter ----@package +---@nodoc --- --- Creates a highlighter for `tree`. --- @@ -232,7 +232,7 @@ function TSHighlighter:on_changedtree(changes) end --- Gets the query used for @param lang ----@package +---@nodoc ---@param lang string Language used by the highlighter. ---@return vim.treesitter.highlighter.Query function TSHighlighter:get_query(lang) diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index b0812123b9..3523ea95e0 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -98,9 +98,9 @@ local LanguageTree = {} LanguageTree.__index = LanguageTree ---- @package +--- @nodoc --- ---- |LanguageTree| contains a tree of parsers: the root treesitter parser for {lang} and any +--- LanguageTree contains a tree of parsers: the root treesitter parser for {lang} and any --- "injected" language parsers, which themselves may inject other languages, recursively. --- ---@param source (integer|string) Buffer or text string to parse @@ -951,7 +951,7 @@ function LanguageTree:_edit( end end ----@package +---@nodoc ---@param bufnr integer ---@param changed_tick integer ---@param start_row integer @@ -1023,12 +1023,12 @@ function LanguageTree:_on_bytes( ) end ----@package +---@nodoc function LanguageTree:_on_reload() self:invalidate(true) end ----@package +---@nodoc function LanguageTree:_on_detach(...) self:invalidate(true) self:_do_callback('detach', ...) -- cgit From e947f226bebef1310af39ce3d93d7bb87e85d757 Mon Sep 17 00:00:00 2001 From: Will Hopkins Date: Sat, 1 Jun 2024 00:18:59 -0700 Subject: fix(types): use vararg return type annotation build(types): allow vararg returns in function types --- runtime/lua/vim/iter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index 1093759efe..6bddf0bc5e 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -276,7 +276,7 @@ end --- -- { 6, 12 } --- ``` --- ----@param f fun(...):any Mapping function. Takes all values returned from +---@param f fun(...):...:any Mapping function. Takes all values returned from --- the previous stage in the pipeline as arguments --- and returns one or more new values, which are used --- in the next pipeline stage. Nil return values -- cgit From 44410d063ad23544f87d1c8a553de336ae7939d8 Mon Sep 17 00:00:00 2001 From: notomo Date: Tue, 11 Jun 2024 21:11:40 +0900 Subject: fix(types): add some vim.fn type annotations Problem: Some vim.fn have no type annotations. Solution: Add type annotations. --- runtime/lua/vim/_meta/vimfn.lua | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index e38c475d09..87e2852efd 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -2766,8 +2766,9 @@ function vim.fn.getchangelist(buf) end --- endfunction --- < --- +--- @param expr? 0|1 --- @return integer -function vim.fn.getchar() end +function vim.fn.getchar(expr) end --- The result is a Number which is the state of the modifiers for --- the last obtained character with getchar() or in another way. @@ -2837,8 +2838,9 @@ function vim.fn.getcharsearch() end --- Otherwise this works like |getchar()|, except that a number --- result is converted to a string. --- +--- @param expr? 0|1 --- @return string -function vim.fn.getcharstr() end +function vim.fn.getcharstr(expr) end --- Return the type of the current command-line completion. --- Only works when the command line is being edited, thus @@ -5297,8 +5299,9 @@ function vim.fn.mapcheck(name, mode, abbr) end --- ounmap xyzzy --- echo printf("Operator-pending mode bit: 0x%x", op_bit) --- ---- @return any -function vim.fn.maplist() end +--- @param abbr? 0|1 +--- @return table[] +function vim.fn.maplist(abbr) end --- Like |map()| but instead of replacing items in {expr1} a new --- List or Dictionary is created and returned. {expr1} remains @@ -7634,8 +7637,15 @@ function vim.fn.searchdecl(name, global, thisblock) end --- \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"') --- < --- ---- @return any -function vim.fn.searchpair() end +--- @param start any +--- @param middle any +--- @param end_ any +--- @param flags? string +--- @param skip? any +--- @param stopline? any +--- @param timeout? integer +--- @return integer +function vim.fn.searchpair(start, middle, end_, flags, skip, stopline, timeout) end --- Same as |searchpair()|, but returns a |List| with the line and --- column position of the match. The first element of the |List| @@ -7647,8 +7657,15 @@ function vim.fn.searchpair() end --- < --- See |match-parens| for a bigger and more useful example. --- ---- @return any -function vim.fn.searchpairpos() end +--- @param start any +--- @param middle any +--- @param end_ any +--- @param flags? string +--- @param skip? any +--- @param stopline? any +--- @param timeout? integer +--- @return [integer, integer] +function vim.fn.searchpairpos(start, middle, end_, flags, skip, stopline, timeout) end --- Same as |search()|, but returns a |List| with the line and --- column position of the match. The first element of the |List| -- cgit From 72155121006bca884e154e935640054f2e090367 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 12 Jun 2024 11:44:38 +0800 Subject: vim-patch:210b39c: runtime(doc): clarify documentation for "v" position at line() (#29296) Problem: the previous documentation falsely states that "v" always refers to the start of a visual area. In fact, the reference of "v" and "." complement each other. If the cursor is at the start of a (characterwise) visual area, then "v" refers to the end of the area. Solution: be more verbose and explicit about the connection between "." and "v" and also refer to |v_o| which many vim users will be familiar with for visual areas. https://github.com/vim/vim/commit/210b39c2d686d875e2464ca1f42131453dc6bd41 Co-authored-by: Peter Aronoff --- runtime/lua/vim/_meta/vimfn.lua | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 87e2852efd..ad057d902b 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -4971,10 +4971,21 @@ function vim.fn.libcallnr(libname, funcname, argument) end --- display isn't updated, e.g. in silent Ex mode) --- w$ last line visible in current window (this is one --- less than "w0" if no lines are visible) ---- v In Visual mode: the start of the Visual area (the ---- cursor is the end). When not in Visual mode ---- returns the cursor position. Differs from |'<| in ---- that it's updated right away. +--- v When not in Visual mode, returns the cursor +--- position. In Visual mode, returns the other end +--- of the Visual area. A good way to think about +--- this is that in Visual mode "v" and "." complement +--- each other. While "." refers to the cursor +--- position, "v" refers to where |v_o| would move the +--- cursor. As a result, you can use "v" and "." +--- together to work on all of a selection in +--- characterwise visual mode. If the cursor is at +--- the end of a characterwise visual area, "v" refers +--- to the start of the same visual area. And if the +--- cursor is at the start of a characterwise visual +--- area, "v" refers to the end of the same visual +--- area. "v" differs from |'<| and |'>| in that it's +--- updated right away. --- Note that a mark in another file can be used. The line number --- then applies to another buffer. --- To get the column number use |col()|. To get both use -- cgit From 8bf79bd13c4d37a96109c8a6a924acb59d8e8ae5 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 12 Jun 2024 15:35:54 +0100 Subject: fix(vim.wo): never allow non-zero bufnr --- runtime/lua/vim/_options.lua | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua index 4a360c18e4..a61fa61256 100644 --- a/runtime/lua/vim/_options.lua +++ b/runtime/lua/vim/_options.lua @@ -174,6 +174,11 @@ local function new_buf_opt_accessor(bufnr) end local function new_win_opt_accessor(winid, bufnr) + -- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value + if bufnr ~= nil and bufnr ~= 0 then + error('only bufnr=0 is supported') + end + return setmetatable({}, { __index = function(_, k) if bufnr == nil and type(k) == 'number' then @@ -184,11 +189,6 @@ local function new_win_opt_accessor(winid, bufnr) end end - if bufnr ~= nil and bufnr ~= 0 then - error('only bufnr=0 is supported') - end - - -- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value return api.nvim_get_option_value(k, { scope = bufnr and 'local' or nil, win = winid or 0, @@ -196,7 +196,6 @@ local function new_win_opt_accessor(winid, bufnr) end, __newindex = function(_, k, v) - -- TODO(lewis6991): allow passing both buf and win to nvim_set_option_value return api.nvim_set_option_value(k, v, { scope = bufnr and 'local' or nil, win = winid or 0, -- cgit From d38912b59f97a4da0a2d0a24af226e6dd27e9b2c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jun 2024 11:10:34 -0500 Subject: refactor(terminal): move :terminal defaults to _defaults.lua --- runtime/lua/vim/_defaults.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 01dcd4bf74..f417bda3fb 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -282,6 +282,26 @@ do end, }) + vim.api.nvim_create_autocmd('TermOpen', { + group = nvim_terminal_augroup, + desc = 'Default settings for :terminal buffers', + callback = function() + vim.bo.modifiable = false + vim.bo.undolevels = -1 + vim.bo.scrollback = vim.o.scrollback < 0 and 10000 or math.max(1, vim.o.scrollback) + vim.bo.textwidth = 0 + vim.wo.wrap = false + vim.wo.list = false + + -- This is gross. Proper list options support when? + local winhl = vim.o.winhighlight + if winhl ~= '' then + winhl = winhl .. ',' + end + vim.wo.winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC' + end, + }) + vim.api.nvim_create_autocmd('CmdwinEnter', { pattern = '[:>]', desc = 'Limit syntax sync to maxlines=1 in the command window', -- cgit From fab3d4721ffb5109c2c30633605af30d37d7d229 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 13 Jun 2024 04:31:59 +0800 Subject: vim-patch:02f3eba: runtime(doc): deduplicate getpos(), line(), col(), virtcol() Move the main description to getpos() and link to that from the other functions. closes: vim/vim#14970 https://github.com/vim/vim/commit/02f3ebacfbfa1f892347d7532278f24620e68300 --- runtime/lua/vim/_meta/vimfn.lua | 113 +++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 59 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index ad057d902b..e9794b444c 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -911,33 +911,31 @@ function vim.fn.cindent(lnum) end function vim.fn.clearmatches(win) end --- The result is a Number, which is the byte index of the column ---- position given with {expr}. The accepted positions are: ---- . the cursor position ---- $ the end of the cursor line (the result is the ---- number of bytes in the cursor line plus one) ---- 'x position of mark x (if the mark is not set, 0 is ---- returned) ---- v In Visual mode: the start of the Visual area (the ---- cursor is the end). When not in Visual mode ---- returns the cursor position. Differs from |'<| in ---- that it's updated right away. +--- position given with {expr}. +--- For accepted positions see |getpos()|. --- Additionally {expr} can be [lnum, col]: a |List| with the line --- and column number. Most useful when the column is "$", to get --- the last column of a specific line. When "lnum" or "col" is --- out of range then col() returns zero. +--- --- With the optional {winid} argument the values are obtained for --- that window instead of the current window. +--- --- To get the line number use |line()|. To get both use --- |getpos()|. +--- --- For the screen column position use |virtcol()|. For the --- character position use |charcol()|. +--- --- Note that only marks in the current file can be used. +--- --- Examples: >vim --- echo col(".") " column of cursor --- echo col("$") " length of cursor line plus one --- echo col("'t") " column of mark t --- echo col("'" .. markname) " column of mark markname ---- | in that it's +--- updated right away. +--- Note that a mark in another file can be used. The line number +--- then applies to another buffer. +--- --- The result is a |List| with four numbers: --- [bufnum, lnum, col, off] --- "bufnum" is zero, unless a mark like '0 or 'A is used, then it @@ -3342,19 +3365,24 @@ function vim.fn.getpid() end --- it is the offset in screen columns from the start of the --- character. E.g., a position within a or after the last --- character. ---- Note that for '< and '> Visual mode matters: when it is "V" ---- (visual line mode) the column of '< is zero and the column of ---- '> is a large number equal to |v:maxcol|. +--- +--- For getting the cursor position see |getcurpos()|. --- The column number in the returned List is the byte position --- within the line. To get the character position in the line, --- use |getcharpos()|. +--- +--- Note that for '< and '> Visual mode matters: when it is "V" +--- (visual line mode) the column of '< is zero and the column of +--- '> is a large number equal to |v:maxcol|. --- A very large column number equal to |v:maxcol| can be returned, --- in which case it means "after the end of the line". --- If {expr} is invalid, returns a list with all zeros. +--- --- This can be used to save and restore the position of a mark: >vim --- let save_a_mark = getpos("'a") --- " ... --- call setpos("'a", save_a_mark) +--- --- | in that it's ---- updated right away. ---- Note that a mark in another file can be used. The line number ---- then applies to another buffer. +--- See |getpos()| for accepted positions. +--- --- To get the column number use |col()|. To get both use --- |getpos()|. +--- --- With the optional {winid} argument the values are obtained for --- that window instead of the current window. +--- --- Returns 0 for invalid values of {expr} and {winid}. +--- --- Examples: >vim --- echo line(".") " line number of the cursor --- echo line(".", winid) " idem, in window "winid" @@ -10410,7 +10415,7 @@ function vim.fn.values(dict) end --- set to 8, it returns 8. |conceal| is ignored. --- For the byte position use |col()|. --- ---- For the use of {expr} see |col()|. +--- For the use of {expr} see |getpos()| and |col()|. --- --- When 'virtualedit' is used {expr} can be [lnum, col, off], --- where "off" is the offset in screen columns from the start of @@ -10420,18 +10425,6 @@ function vim.fn.values(dict) end --- beyond the end of the line can be returned. Also see --- |'virtualedit'| --- ---- The accepted positions are: ---- . the cursor position ---- $ the end of the cursor line (the result is the ---- number of displayed characters in the cursor line ---- plus one) ---- 'x position of mark x (if the mark is not set, 0 is ---- returned) ---- v In Visual mode: the start of the Visual area (the ---- cursor is the end). When not in Visual mode ---- returns the cursor position. Differs from |'<| in ---- that it's updated right away. ---- --- If {list} is present and non-zero then virtcol() returns a --- List with the first and last screen position occupied by the --- character. @@ -10450,7 +10443,9 @@ function vim.fn.values(dict) end --- " With text " there", with 't at 'h': --- --- echo virtcol("'t") " returns 6 ---- vim --- echo max(map(range(1, line('$')), "virtcol([v:val, '$'])")) -- cgit From 6ba152168787e2cf7d197d8f2d682daaca0c94cf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Jun 2024 04:45:12 +0800 Subject: vim-patch:d353d27: runtime(doc): restore description of "$" in col() and virtcol() (vim/vim#14981) These are different from line() and getpos(). https://github.com/vim/vim/commit/d353d2782032b91498601afefee4256592f48074 --- runtime/lua/vim/_meta/vimfn.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index e9794b444c..f868aec423 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -913,6 +913,8 @@ function vim.fn.clearmatches(win) end --- The result is a Number, which is the byte index of the column --- position given with {expr}. --- For accepted positions see |getpos()|. +--- When {expr} is "$", it means the end of the cursor line, so +--- the result is the number of bytes in the cursor line plus one. --- Additionally {expr} can be [lnum, col]: a |List| with the line --- and column number. Most useful when the column is "$", to get --- the last column of a specific line. When "lnum" or "col" is @@ -3332,7 +3334,7 @@ function vim.fn.getpid() end --- . The cursor position. --- $ The last line in the current buffer. --- 'x Position of mark x (if the mark is not set, 0 is ---- returned). +--- returned for all values). --- w0 First line visible in current window (one if the --- display isn't updated, e.g. in silent Ex mode). --- w$ Last line visible in current window (this is one @@ -3382,8 +3384,8 @@ function vim.fn.getpid() end --- let save_a_mark = getpos("'a") --- " ... --- call setpos("'a", save_a_mark) ---- ---- Date: Fri, 14 Jun 2024 06:20:42 +0800 Subject: fix(terminal): set local values of window options (#29326) --- runtime/lua/vim/_defaults.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index f417bda3fb..8e4562c8ba 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -290,15 +290,15 @@ do vim.bo.undolevels = -1 vim.bo.scrollback = vim.o.scrollback < 0 and 10000 or math.max(1, vim.o.scrollback) vim.bo.textwidth = 0 - vim.wo.wrap = false - vim.wo.list = false + vim.wo[0][0].wrap = false + vim.wo[0][0].list = false -- This is gross. Proper list options support when? local winhl = vim.o.winhighlight if winhl ~= '' then winhl = winhl .. ',' end - vim.wo.winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC' + vim.wo[0][0].winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC' end, }) -- cgit From 81b372fecd749d350fbd86be1f65146b2df97b70 Mon Sep 17 00:00:00 2001 From: Tama McGlinn Date: Fri, 14 Jun 2024 11:02:36 +0200 Subject: fix(lsp): check for nil response from server (#29196) this only changes the error message, so that it is clear that the error is with the LSP server, rather than being a crash inside nvim runtime scripts. We are already doing a lot of validation, it's just that nil was being overlooked here. This fixes issue #27395 --- runtime/lua/vim/lsp/rpc.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 5e2b041a0a..7acb67b25e 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -407,7 +407,9 @@ function Client:handle_body(body) end log.debug('rpc.receive', decoded) - if type(decoded.method) == 'string' and decoded.id then + if type(decoded) ~= 'table' then + self:on_error(M.client_errors.INVALID_SERVER_MESSAGE, decoded) + elseif type(decoded.method) == 'string' and decoded.id then local err --- @type lsp.ResponseError|nil -- Schedule here so that the users functions don't trigger an error and -- we can still use the result. -- cgit From 0a9c81d70964f905112857900fbaa6aae590a96d Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 14 Jun 2024 05:03:58 -0400 Subject: refactor(lsp): use metatable for buf_versions (#29304) This reduces the number of nil checks around buf_versions usage Test changes were lifted from 5c33815 Co-authored-by: Mathias Fussenegger --- runtime/lua/vim/lsp/client.lua | 10 ++++------ runtime/lua/vim/lsp/semantic_tokens.lua | 2 +- runtime/lua/vim/lsp/util.lua | 8 ++++++-- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index d3ff918792..8cdfdd4b90 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -916,18 +916,16 @@ function Client:_text_document_did_open_handler(bufnr) if not api.nvim_buf_is_loaded(bufnr) then return end - local filetype = vim.bo[bufnr].filetype - local params = { + local filetype = vim.bo[bufnr].filetype + self.notify(ms.textDocument_didOpen, { textDocument = { - version = 0, + version = lsp.util.buf_versions[bufnr], uri = vim.uri_from_bufnr(bufnr), languageId = self.get_language_id(bufnr, filetype), text = lsp._buf_get_full_text(bufnr), }, - } - self.notify(ms.textDocument_didOpen, params) - lsp.util.buf_versions[bufnr] = params.textDocument.version + }) -- Next chance we get, we should re-do the diagnostics vim.schedule(function() diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index f92c0eb2e6..2ae86851d1 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -412,7 +412,7 @@ end function STHighlighter:on_win(topline, botline) for client_id, state in pairs(self.client_state) do local current_result = state.current_result - if current_result.version and current_result.version == util.buf_versions[self.bufnr] then + if current_result.version == util.buf_versions[self.bufnr] then if not current_result.namespace_cleared then api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) current_result.namespace_cleared = true diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ae6de591b3..a5cf13ed0f 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -516,7 +516,6 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) and ( text_document.version and text_document.version > 0 - and M.buf_versions[bufnr] and M.buf_versions[bufnr] > text_document.version ) then @@ -2222,6 +2221,11 @@ end M._get_line_byte_from_position = get_line_byte_from_position ---@nodoc -M.buf_versions = {} ---@type table +---@type table +M.buf_versions = setmetatable({}, { + __index = function(t, bufnr) + return rawget(t, bufnr) or 0 + end, +}) return M -- cgit From aa47af7e69bb32c4486510dce27f45d9028e0a6c Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 14 Jun 2024 19:32:34 +0200 Subject: fix(lsp): tune completion word extraction for decorated labels (#29331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: For snippets lsp.completion prefers the label if it is shorter than the insertText or textEdit to support postfix completion cases but clangd adds decoration characters to labels. E.g.: `•INT16_C(c)` Solution: Use parse_snippet on insertText/textEdit before checking if it is shorter than the label. Fixes https://github.com/neovim/neovim/issues/29301 --- runtime/lua/vim/lsp/completion.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 4b7deabf41..2e6d82b367 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -145,8 +145,8 @@ local function get_completion_word(item) -- label: insert -- -- Typing `i` would remove the candidate because newText starts with `t`. - local text = item.insertText or item.textEdit.newText - return #text < #item.label and text or item.label + local text = parse_snippet(item.insertText or item.textEdit.newText) + return #text < #item.label and vim.fn.matchstr(text, '\\k*') or item.label elseif item.insertText and item.insertText ~= '' then return parse_snippet(item.insertText) else -- cgit From f557a985ef47057398899a7270beb26e8f71771c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 15 Jun 2024 06:04:13 +0800 Subject: vim-patch:d6d4e13: runtime(doc): rewrite mkdir() doc and simplify {flags} meaning related: vim/vim#14991 https://github.com/vim/vim/commit/d6d4e1333659c0d2acee3133819498d014df47de Co-authored-by: Christian Brabandt --- runtime/lua/vim/_meta/vimfn.lua | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index f868aec423..3ef96a5f47 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -6007,17 +6007,14 @@ function vim.fn.min(expr) end --- When {flags} is present it must be a string. An empty string --- has no effect. --- ---- If {flags} contains "p" then intermediate directories are ---- created as necessary. ---- ---- If {flags} contains "D" then {name} is deleted at the end of ---- the current function, as with: >vim ---- defer delete({name}, 'd') ---- < ---- If {flags} contains "R" then {name} is deleted recursively at ---- the end of the current function, as with: >vim ---- defer delete({name}, 'rf') ---- vim -- cgit From b969e3e0b994db8bf5a5aba498f36ae4ab2555c1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 15 Jun 2024 06:08:45 +0800 Subject: vim-patch:c509c00: runtime(doc): fix wrong helptag for :defer https://github.com/vim/vim/commit/c509c009bbc07eff678a9239a5813398e180f019 Co-authored-by: Christian Brabandt --- runtime/lua/vim/_meta/vimfn.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 3ef96a5f47..900e0224a0 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -6010,9 +6010,9 @@ function vim.fn.min(expr) end --- {flags} can contain these character flags: --- "p" intermediate directories will be created as necessary --- "D" {name} will be deleted at the end of the current ---- function, but not recursively |defer| +--- function, but not recursively |:defer| --- "R" {name} will be deleted recursively at the end of the ---- current function |defer| +--- current function |:defer| --- --- Note that when {name} has more than one part and "p" is used --- some directories may already exist. Only the first one that -- cgit From 6e28589e00a32045d5a62654151299802e40fdb0 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 15 Jun 2024 01:04:27 +0200 Subject: docs: misc (#29229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ilia Choly Co-authored-by: Jose Pedro Oliveira Co-authored-by: Maria José Solano Co-authored-by: zeertzjq --- runtime/lua/vim/_meta/api.lua | 6 +++--- runtime/lua/vim/_meta/lpeg.lua | 4 ++-- runtime/lua/vim/_meta/vimfn.lua | 38 +++++++++++++++++++------------------- runtime/lua/vim/lsp/inlay_hint.lua | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index d91b2d08bf..1b70cc275f 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1910,7 +1910,7 @@ function vim.api.nvim_set_current_win(window) end --- Note: this function should not be called often. Rather, the callbacks --- themselves can be used to throttle unneeded callbacks. the `on_start` --- callback can return `false` to disable the provider until the next redraw. ---- Similarly, return `false` in `on_win` will skip the `on_lines` calls for +--- Similarly, return `false` in `on_win` will skip the `on_line` calls for --- that window (but any extmarks set in `on_win` will still be used). A --- plugin managing multiple sources of decoration should ideally only set one --- provider, and merge the sources internally. You can use multiple `ns_id` @@ -1919,10 +1919,10 @@ function vim.api.nvim_set_current_win(window) end --- Note: doing anything other than setting extmarks is considered --- experimental. Doing things like changing options are not explicitly --- forbidden, but is likely to have unexpected consequences (such as 100% CPU ---- consumption). doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is +--- consumption). Doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is --- quite dubious for the moment. --- ---- Note: It is not allowed to remove or update extmarks in 'on_line' +--- Note: It is not allowed to remove or update extmarks in `on_line` --- callbacks. --- --- @param ns_id integer Namespace id from `nvim_create_namespace()` diff --git a/runtime/lua/vim/_meta/lpeg.lua b/runtime/lua/vim/_meta/lpeg.lua index 73b3375c82..39a894aaeb 100644 --- a/runtime/lua/vim/_meta/lpeg.lua +++ b/runtime/lua/vim/_meta/lpeg.lua @@ -2,7 +2,7 @@ error('Cannot require a meta file') -- These types were taken from https://github.com/LuaCATS/lpeg --- (based on revision e6789e28e5b91a4a277a2a03081d708c403a3e34) +-- (based on revision 82c6a8fc676bbc20722026afd952668f3919b11d) -- with types being renamed to include the vim namespace and with some descriptions made less verbose. --- @brief
help
@@ -32,7 +32,7 @@ vim.lpeg = {}
 --- @operator div(table): vim.lpeg.Capture
 --- @operator div(function): vim.lpeg.Capture
 --- @operator pow(number): vim.lpeg.Pattern
---- @operator mod(function): nil
+--- @operator mod(function): vim.lpeg.Capture
 local Pattern = {}
 
 --- @alias vim.lpeg.Capture vim.lpeg.Pattern
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 900e0224a0..11dcbc010b 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -3601,8 +3601,8 @@ function vim.fn.getreginfo(regname) end
 ---   difference if the buffer is displayed in a window with
 ---   different 'virtualedit' or 'list' values.
 ---
---- Examples: >
----   :xnoremap 
+--- Examples: >vim
+---   xnoremap 
 ---   \ echom getregion(
 ---   \ getpos('v'), getpos('.'), #{ type: mode() })
 --- <
@@ -5596,19 +5596,19 @@ function vim.fn.matcharg(nr) end
 ---
 --- Examples: >vim
 ---     " Assuming line 3 in buffer 5 contains "a"
----     :echo matchbufline(5, '\<\k\+\>', 3, 3)
----     [{'lnum': 3, 'byteidx': 0, 'text': 'a'}]
+---     echo matchbufline(5, '\<\k\+\>', 3, 3)
+--- <    `[{'lnum': 3, 'byteidx': 0, 'text': 'a'}]` >vim
 ---     " Assuming line 4 in buffer 10 contains "tik tok"
----     :echo matchbufline(10, '\<\k\+\>', 1, 4)
----     [{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}]
---- <
+---     echo matchbufline(10, '\<\k\+\>', 1, 4)
+--- <    `[{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}]`
+---
 --- If {submatch} is present and is v:true, then submatches like
 --- "\1", "\2", etc. are also returned.  Example: >vim
 ---     " Assuming line 2 in buffer 2 contains "acd"
----     :echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2
+---     echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2
 ---         \ {'submatches': v:true})
----     [{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]
---- vim
----     :echo matchstrlist(['tik tok'], '\<\k\+\>')
----     [{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}]
----     :echo matchstrlist(['a', 'b'], '\<\k\+\>')
----     [{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}]
---- <
+---     echo matchstrlist(['tik tok'], '\<\k\+\>')
+--- <    `[{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}]` >vim
+---     echo matchstrlist(['a', 'b'], '\<\k\+\>')
+--- <    `[{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}]`
+---
 --- If "submatches" is present and is v:true, then submatches like
 --- "\1", "\2", etc. are also returned.  Example: >vim
----     :echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)',
+---     echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)',
 ---         \ #{submatches: v:true})
----     [{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]
---- vim
 ---   nnoremap  GG ":echom " .. screencol() .. "\n"
 ---   nnoremap  GG :echom screencol()
----   noremap GG echom screencol()
+---   noremap GG echom screencol()
 --- <
 ---
 --- @return any
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index 2d784816cb..aa84294cc4 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -370,7 +370,7 @@ api.nvim_set_decoration_provider(namespace, {
 })
 
 --- Query whether inlay hint is enabled in the {filter}ed scope
---- @param filter vim.lsp.inlay_hint.enable.Filter
+--- @param filter? vim.lsp.inlay_hint.enable.Filter
 --- @return boolean
 --- @since 12
 function M.is_enabled(filter)
-- 
cgit 


From 61aabe0730b547b733faaf74ff181ec8c33f8b92 Mon Sep 17 00:00:00 2001
From: Jerry 
Date: Fri, 14 Jun 2024 19:21:16 -0700
Subject: fix(defaults): default @/Q broken when 'ignorecase' is set (#29343)

Problem:
When 'ignorecase' is set, the default keymap Q and Q would exit visual
mode.

This issue was raised in #28287 and a fix was applied in #28289.

However, `==` operator is subject to user `ignorecase` setting.

Solution:
Switching to `==#` operator would guarantee case sensitive comparison
between visual mode and linewise visual mode.

Co-authored-by: Kuanju Chen 
---
 runtime/lua/vim/_defaults.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 8e4562c8ba..630f2219c7 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -85,13 +85,13 @@ do
   vim.keymap.set(
     'x',
     'Q',
-    "mode() == 'V' ? ':normal! @=reg_recorded()' : 'Q'",
+    "mode() ==# 'V' ? ':normal! @=reg_recorded()' : 'Q'",
     { silent = true, expr = true, desc = ':help v_Q-default' }
   )
   vim.keymap.set(
     'x',
     '@',
-    "mode() == 'V' ? ':normal! @'.getcharstr().'' : '@'",
+    "mode() ==# 'V' ? ':normal! @'.getcharstr().'' : '@'",
     { silent = true, expr = true, desc = ':help v_@-default' }
   )
 
-- 
cgit 


From 4faad4a950c68689166f0d6ecf5694cb04a9b589 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sat, 15 Jun 2024 10:07:36 +0200
Subject: vim-patch:9.1.0486: filetype: Snakemake files are not recognized

Problem:  filetype: Snakemake files are not recognized
Solution: Detect '*.smk' and Snakefile files as snakemake filetype
          (Riley Bruins)

See:
https://snakemake.readthedocs.io/en/stable/snakefiles/deployment.html#distribution-and-reproducibility

closes: vim/vim#14992

https://github.com/vim/vim/commit/82a579e15ad78f4b99d2957300da3076ccc7d378

Co-authored-by: Riley Bruins 
Co-authored-by: zeertzjq 
---
 runtime/lua/vim/filetype.lua | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index cc2fbe0cec..2bb50d8c0b 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -985,6 +985,7 @@ local extension = {
   smt = 'smith',
   smithy = 'smithy',
   sml = 'sml',
+  smk = 'snakemake',
   spt = 'snobol4',
   sno = 'snobol4',
   sln = 'solution',
@@ -1620,6 +1621,7 @@ local filename = {
   ['/etc/slp.spi'] = 'slpspi',
   ['.slrnrc'] = 'slrnrc',
   ['sendmail.cf'] = 'sm',
+  Snakefile = 'snakemake',
   ['.sqlite_history'] = 'sql',
   ['squid.conf'] = 'squid',
   ['ssh_config'] = 'sshconfig',
-- 
cgit 


From 7e65f3757bdbe41bbf022b05b6869ad6e7febe0d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 16 Jun 2024 06:08:36 +0800
Subject: docs: document 'list' behavior when 'listchars' excludes "tab"
 (#29360)

---
 runtime/lua/vim/_meta/options.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 155c93726b..27534789b3 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -3830,6 +3830,9 @@ vim.go.lw = vim.go.lispwords
 --- between tabs and spaces and for trailing blanks. Further changed by
 --- the 'listchars' option.
 ---
+--- When 'listchars' does not contain "tab" field, tabs are shown as "^I"
+--- or "<09>", like how unprintable characters are displayed.
+---
 --- The cursor is displayed at the start of the space a Tab character
 --- occupies, not at the end as usual in Normal mode.  To get this cursor
 --- position while displaying Tabs with spaces, use:
-- 
cgit 


From 191a70f9dd347926bc74a9928fce388be0000248 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sun, 16 Jun 2024 11:27:20 +0200
Subject: vim-patch:9.1.0492: filetype: Vim-script files not detected by
 shebang line

Problem:  Vim-script files may not be recognised
Solution: Add shebang line detection (Doug Kearns)

closes: vim/vim#15012

https://github.com/vim/vim/commit/0d4d23dac0a5a77ccb0ebf1dcf646afe0c6886bf

Co-authored-by: Doug Kearns 
---
 runtime/lua/vim/filetype/detect.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index c56ece6289..fa90c83b81 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -1783,6 +1783,7 @@ local patterns_hashbang = {
   ['^janet\\>'] = { 'janet', { vim_regex = true } },
   ['^dart\\>'] = { 'dart', { vim_regex = true } },
   ['^execlineb\\>'] = { 'execline', { vim_regex = true } },
+  ['^vim\\>'] = { 'vim', { vim_regex = true } },
 }
 
 ---@private
-- 
cgit 


From ad70c9892d5b5ebcc106742386c99524f074bcea Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Sat, 15 Jun 2024 05:46:43 +0200
Subject: feat(column)!: rework 'statuscolumn' %r/l items

Problem:  A custom 'statuscolumn' needs to check a bunch of options and
          placed signs to replicate the default number column.
Solution: Rework %l item to include the necessary logic to mimic the
          default number column. Remove now redundant %r item.
---
 runtime/lua/vim/_meta/options.lua | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 155c93726b..befb56d3d5 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -6373,8 +6373,7 @@ vim.go.sol = vim.go.startofline
 --- Some of the items from the 'statusline' format are different for
 --- 'statuscolumn':
 ---
---- %l	line number of currently drawn line
---- %r	relative line number of currently drawn line
+--- %l	line number column for currently drawn line
 --- %s	sign column for currently drawn line
 --- %C	fold column for currently drawn line
 ---
@@ -6403,11 +6402,8 @@ vim.go.sol = vim.go.startofline
 --- Examples:
 ---
 --- ```vim
---- 	" Relative number with bar separator and click handlers:
---- 	set statuscolumn=%@SignCb@%s%=%T%@NumCb@%r│%T
----
---- 	" Right aligned relative cursor line number:
---- 	let &stc='%=%{v:relnum?v:relnum:v:lnum} '
+--- 	" Line number with bar separator and click handlers:
+--- 	set statuscolumn=%@SignCb@%s%=%T%@NumCb@%l│%T
 ---
 --- 	" Line numbers in hexadecimal for non wrapped part of lines:
 --- 	let &stc='%=%{v:virtnum>0?"":printf("%x",v:lnum)} '
-- 
cgit 


From a46991e1c6ff769d2381d87886ac4f7397ab25c3 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 18 Jun 2024 07:00:32 +0800
Subject: docs(news): fix inconsistencies (#29381)

---
 runtime/lua/vim/snippet.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua
index 8cd454b908..98a7a79ce0 100644
--- a/runtime/lua/vim/snippet.lua
+++ b/runtime/lua/vim/snippet.lua
@@ -609,7 +609,7 @@ end
 --- ```lua
 --- vim.keymap.set({ 'i', 's' }, '', function()
 ---    if vim.snippet.active({ direction = 1 }) then
----      return 'lua vim.snippet.jump(1)'
+---      return 'lua vim.snippet.jump(1)'
 ---    else
 ---      return ''
 ---    end
@@ -661,7 +661,7 @@ end
 --- ```lua
 --- vim.keymap.set({ 'i', 's' }, '', function()
 ---    if vim.snippet.active({ direction = 1 }) then
----      return 'lua vim.snippet.jump(1)'
+---      return 'lua vim.snippet.jump(1)'
 ---    else
 ---      return ''
 ---    end
-- 
cgit 


From 6012f79557b8807593c1c88b75e54f14a88d5173 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Tue, 18 Jun 2024 20:00:43 +0200
Subject: vim-patch:9718ed7: runtime(filetype): update htmldjango detection

- update tags to detect djangohtml based on
  https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#built-in-tag-reference

- increase the lines to inspect to 40 lines

  10 lines is too few and might result in high false negative.
  Increasing it to 40 lines should reduce the false negative.

closes: vim/vim#15037

https://github.com/vim/vim/commit/9718ed7ab989c0a0be88a0d749f24321eb0e6af1

Co-authored-by: Afiq Nazrie 
---
 runtime/lua/vim/filetype/detect.lua | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index fa90c83b81..997b53ba4b 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -676,10 +676,15 @@ end
 
 --- @type vim.filetype.mapfn
 function M.html(_, bufnr)
-  for _, line in ipairs(getlines(bufnr, 1, 10)) do
+  for _, line in ipairs(getlines(bufnr, 1, 40)) do
     if matchregex(line, [[\\|{#\s\+]]) then
+    elseif
+      matchregex(
+        line,
+        [[\c{%\s*\(autoescape\|block\|comment\|csrf_token\|cycle\|debug\|extends\|filter\|firstof\|for\|if\|ifchanged\|include\|load\|lorem\|now\|query_string\|regroup\|resetcycle\|spaceless\|templatetag\|url\|verbatim\|widthratio\|with\)\>\|{#\s\+]]
+      )
+    then
       return 'htmldjango'
     end
   end
-- 
cgit 


From e5e81262af88ec13b456d68ffb5a6ffafe497dab Mon Sep 17 00:00:00 2001
From: Riley Bruins 
Date: Wed, 19 Jun 2024 09:28:44 -0700
Subject: fix(diagnostics): don't apply extmarks to invalid lines #29321

Problem:
If there are errors in the last line of a buffer, something like `Gdk` or
`G2k3J` will produce an error (at least with `lua_ls`):

    Error executing vim.schedule lua callback:
    .../neovim/share/nvim/runtime/lua/vim/diagnostic.lua:1446: Invalid 'line': out of range

Solution:
Only set extmarks if the target buffer line still exists
---
 runtime/lua/vim/diagnostic.lua | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index c8e34258f5..3be22556ab 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -1359,6 +1359,10 @@ M.handlers.signs = {
     bufnr = get_bufnr(bufnr)
     opts = opts or {}
 
+    if not api.nvim_buf_is_loaded(bufnr) then
+      return
+    end
+
     if opts.signs and opts.signs.severity then
       diagnostics = filter_by_severity(opts.signs.severity, diagnostics)
     end
@@ -1441,8 +1445,10 @@ M.handlers.signs = {
     local numhl = opts.signs.numhl or {}
     local linehl = opts.signs.linehl or {}
 
+    local line_count = api.nvim_buf_line_count(bufnr)
+
     for _, diagnostic in ipairs(diagnostics) do
-      if api.nvim_buf_is_loaded(diagnostic.bufnr) then
+      if diagnostic.lnum <= line_count then
         api.nvim_buf_set_extmark(bufnr, ns.user_data.sign_ns, diagnostic.lnum, 0, {
           sign_text = text[diagnostic.severity] or text[M.severity[diagnostic.severity]] or 'U',
           sign_hl_group = sign_highlight_map[diagnostic.severity],
-- 
cgit 


From af0021f990bfd9681e8889ef217d26a89fadf5f0 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 20 Jun 2024 17:45:41 +0800
Subject: vim-patch:9.1.0505: filetype: Faust files are not recognized (#29426)

Problem:  filetype: Faust files are not recognized
Solution: Detect '*.lib' files as Faust filetype, add detection for
          '*.dsp' files (Faust or Make), remove '*.lib' from Cobol
          filetype (PowerUser64)

closes: vim/vim#14894

https://github.com/vim/vim/commit/aa61b8a9087e9cd999ef07e0d87b60f43d68f2c6

Co-authored-by: PowerUser64 
---
 runtime/lua/vim/filetype.lua        |  4 ++--
 runtime/lua/vim/filetype/detect.lua | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 2 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 2bb50d8c0b..7373c403b5 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -281,7 +281,6 @@ local extension = {
   cook = 'cook',
   cmake = 'cmake',
   cmod = 'cmod',
-  lib = 'cobol',
   cob = 'cobol',
   cbl = 'cobol',
   atg = 'coco',
@@ -366,6 +365,7 @@ local extension = {
   gv = 'dot',
   drac = 'dracula',
   drc = 'dracula',
+  dsp = detect.dsp,
   dtd = 'dtd',
   d = detect.dtrace,
   dts = 'dts',
@@ -417,6 +417,7 @@ local extension = {
   fal = 'falcon',
   fan = 'fan',
   fwt = 'fan',
+  lib = 'faust',
   fnl = 'fennel',
   m4gl = 'fgl',
   ['4gl'] = 'fgl',
@@ -666,7 +667,6 @@ local extension = {
   eml = 'mail',
   mk = 'make',
   mak = 'make',
-  dsp = 'make',
   page = 'mallard',
   map = 'map',
   mws = 'maple',
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 997b53ba4b..b52dba7388 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -471,6 +471,41 @@ function M.def(_, bufnr)
   return 'def'
 end
 
+--- @type vim.filetype.mapfn
+function M.dsp(path, bufnr)
+  if vim.g.filetype_dsp then
+    return vim.g.filetype_dsp
+  end
+
+  -- Test the filename
+  local file_name = fn.fnamemodify(path, ':t')
+  if file_name:find('^[mM]akefile.*$') then
+    return 'make'
+  end
+
+  -- Test the file contents
+  for _, line in ipairs(getlines(bufnr, 1, 200)) do
+    if
+      findany(line, {
+        -- Check for comment style
+        [[#.*]],
+        -- Check for common lines
+        [[^.*Microsoft Developer Studio Project File.*$]],
+        [[^!MESSAGE This is not a valid makefile\..+$]],
+        -- Check for keywords
+        [[^!(IF,ELSEIF,ENDIF).*$]],
+        -- Check for common assignments
+        [[^SOURCE=.*$]],
+      })
+    then
+      return 'make'
+    end
+  end
+
+  -- Otherwise, assume we have a Faust file
+  return 'faust'
+end
+
 --- @type vim.filetype.mapfn
 function M.e(_, bufnr)
   if vim.g.filetype_euphoria then
-- 
cgit 


From 0e3e1e6b6d8370f1fcc9887d5cb931b131450a1c Mon Sep 17 00:00:00 2001
From: Jaehwang Jung 
Date: Thu, 20 Jun 2024 22:37:09 +0900
Subject: fix(treesitter): don't open fold when o/O adds a line below #28709

Problem:
`o`-ing on a folded line opens the fold, because the new line gets the
fold level from the above line (level '='), which extends the fold to
the new line. `O` has a similar problem when run on the line below a
fold.

Solution:
Use -1 for the added line to get the lower level from the above/below
line.
---
 runtime/lua/vim/treesitter/_fold.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index 04a3c62cf1..b8f1ef1282 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -87,7 +87,7 @@ end
 ---@param srow integer
 ---@param erow integer 0-indexed, exclusive
 function FoldInfo:add_range(srow, erow)
-  list_insert(self.levels, srow + 1, erow, '=')
+  list_insert(self.levels, srow + 1, erow, -1)
   list_insert(self.levels0, srow + 1, erow, -1)
 end
 
-- 
cgit 


From d82efeccc7e89230ba6673da0fdf62c09fa38c17 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Fri, 21 Jun 2024 10:29:44 +0200
Subject: vim-patch:9.1.0506: filetype: .envrc & .prettierignore not recognized

Problem:  filetype: .envrc & .prettierignore not recognized
Solution: Detect '.envrc' as shell and '.prettierignore' as gitignore
          filetype (Tyler Miller)

Support ft detection for `.envrc` files used by direnv, and
`.prettierignore` files used by prettier.

closes: vim/vim#15053
resolves: neovim/neovim#29405

https://github.com/vim/vim/commit/49012cd8c2fb0452847e5d213b07aa8a978f4762

Co-authored-by: Tyler Miller 
---
 runtime/lua/vim/filetype.lua | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 7373c403b5..6dd920e506 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -469,6 +469,7 @@ local extension = {
   gmi = 'gemtext',
   gemini = 'gemtext',
   gift = 'gift',
+  prettierignore = 'gitignore',
   gleam = 'gleam',
   glsl = 'glsl',
   gn = 'gn',
@@ -953,6 +954,7 @@ local extension = {
   ebuild = detect.bash,
   eclass = detect.bash,
   env = detect.sh,
+  envrc = detect.sh,
   ksh = detect.ksh,
   sh = detect.sh,
   mdd = 'sh',
-- 
cgit 


From da4e8dc5b04a82c6dd483f6c5345a81d8b375bec Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Sun, 23 Jun 2024 13:50:21 +0200
Subject: fix(treesitter): do not modify highlight state for _on_spell_nav

Problem:  Treesitter highlighter clears the already populated highlight
          state when performing spell checking while drawing a
          smoothscrolled topline.
Solution: Save and restore the highlight state in the highlighter's
          _on_spell_nav callback.
---
 runtime/lua/vim/treesitter/highlighter.lua | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 003f7e0169..cd5c67d816 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -377,11 +377,15 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
     return
   end
 
+  -- Do not affect potentially populated highlight state. Here we just want a temporary
+  -- empty state so the C code can detect whether the region should be spell checked.
+  local highlight_states = self._highlight_states
   self:prepare_highlight_states(srow, erow)
 
   for row = srow, erow do
     on_line_impl(self, buf, row, true)
   end
+  self._highlight_states = highlight_states
 end
 
 ---@private
-- 
cgit 


From c57a85e0eda067ea28ca5853358947332aceecfd Mon Sep 17 00:00:00 2001
From: Riley Bruins 
Date: Fri, 14 Jun 2024 17:54:10 -0700
Subject: perf(treesitter): remove unnecessary foldexpr loop

Instead of looping over all captured nodes, just take the end range from
the last node in the list. This uses the fact that nodes returned by
iter_matches are ordered by their range (earlier to later).
---
 runtime/lua/vim/treesitter/_fold.lua | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index b8f1ef1282..194e09babc 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -139,16 +139,12 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
           local range = ts.get_range(nodes[1], bufnr, metadata[id])
           local start, _, stop, stop_col = Range.unpack4(range)
 
-          for i = 2, #nodes, 1 do
-            local node_range = ts.get_range(nodes[i], bufnr, metadata[id])
-            local node_start, _, node_stop, node_stop_col = Range.unpack4(node_range)
-            if node_start < start then
-              start = node_start
-            end
-            if node_stop > stop then
-              stop = node_stop
-              stop_col = node_stop_col
-            end
+          if #nodes > 1 then
+            -- assumes nodes are ordered by range
+            local end_range = ts.get_range(nodes[#nodes], bufnr, metadata[id])
+            local _, _, end_stop, end_stop_col = Range.unpack4(end_range)
+            stop = end_stop
+            stop_col = end_stop_col
           end
 
           if stop_col == 0 then
-- 
cgit 


From b0e59909075a582fbcf12b4c8a3ec1bff12c4eea Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 24 Jun 2024 22:12:15 +0800
Subject: refactor(filetype): change some patterns to extensions (#29472)

Ref #29468
---
 runtime/lua/vim/filetype.lua | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 6dd920e506..6d3fc48efc 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -203,6 +203,10 @@ local extension = {
     return 'aspvbs'
   end,
   asm = detect.asm,
+  s = detect.asm,
+  S = detect.asm,
+  a = detect.asm,
+  A = detect.asm,
   lst = detect.asm,
   mac = detect.asm,
   asn1 = 'asn',
@@ -706,6 +710,10 @@ local extension = {
   mmp = 'mmp',
   mms = detect.mms,
   DEF = 'modula2',
+  m3 = 'modula3',
+  i3 = 'modula3',
+  mg = 'modula3',
+  ig = 'modula3',
   lm3 = 'modula3',
   mojo = 'mojo',
   ['🔥'] = 'mojo', -- 🙄
@@ -1157,6 +1165,8 @@ local extension = {
   wbt = 'winbatch',
   wit = 'wit',
   wml = 'wml',
+  wsf = 'wsh',
+  wsc = 'wsh',
   wsml = 'wsml',
   ad = 'xdefaults',
   xhtml = 'xhtml',
@@ -1741,8 +1751,6 @@ local pattern = {
   ['.*asterisk/.*%.conf.*'] = starsetf('asterisk'),
   ['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'),
   ['.*/%.aptitude/config'] = 'aptconf',
-  ['.*%.[aA]'] = detect.asm,
-  ['.*%.[sS]'] = detect.asm,
   ['[mM]akefile%.am'] = 'automake',
   ['.*/bind/db%..*'] = starsetf('bindzone'),
   ['.*/named/db%..*'] = starsetf('bindzone'),
@@ -1798,8 +1806,6 @@ local pattern = {
   ['.*/etc/apt/sources%.list%.d/.*%.list'] = 'debsources',
   ['.*/etc/apt/sources%.list'] = 'debsources',
   ['.*/etc/apt/sources%.list%.d/.*%.sources'] = 'deb822sources',
-  ['.*%.directory'] = 'desktop',
-  ['.*%.desktop'] = 'desktop',
   ['dictd.*%.conf'] = 'dictdconf',
   ['.*/etc/DIR_COLORS'] = 'dircolors',
   ['.*/etc/dnsmasq%.conf'] = 'dnsmasq',
@@ -2017,7 +2023,6 @@ local pattern = {
       return 'modconf'
     end
   end),
-  ['.*%.[mi][3g]'] = 'modula3',
   ['Muttrc'] = 'muttrc',
   ['Muttngrc'] = 'muttrc',
   ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'),
@@ -2164,7 +2169,6 @@ local pattern = {
   ['.*%.[Ll][Oo][Gg]'] = detect.log,
   ['.*/etc/config/.*'] = starsetf(detect.uci),
   ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'),
-  ['.*%.ws[fc]'] = 'wsh',
   ['.*/Xresources/.*'] = starsetf('xdefaults'),
   ['.*/app%-defaults/.*'] = starsetf('xdefaults'),
   ['.*/etc/xinetd%.conf'] = 'xinetd',
-- 
cgit 


From 5581a95534e44b8714e715c925c9de2d95ae1c21 Mon Sep 17 00:00:00 2001
From: Tom Praschan <13141438+tom-anders@users.noreply.github.com>
Date: Mon, 24 Jun 2024 16:54:56 +0200
Subject: feat(lsp): vim.lsp.buf.format() supports
 textDocument/rangesFormatting #27323

While this relies on a proposed LSP 3.18 feature, it's fully backwards
compatible, so IMO there's no harm in adding this already.

Looks like some servers already support for this e.g.
- gopls: https://go-review.googlesource.com/c/tools/+/510235
- clangd: https://github.com/llvm/llvm-project/pull/80180

Fixes #27293
---
 runtime/lua/vim/lsp.lua          |  1 +
 runtime/lua/vim/lsp/buf.lua      | 28 ++++++++++++++++++++++------
 runtime/lua/vim/lsp/protocol.lua |  1 +
 3 files changed, 24 insertions(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 623ccdd5cd..7fe4dd8cf5 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -56,6 +56,7 @@ lsp._request_name_to_capability = {
   [ms.workspace_symbol] = { 'workspaceSymbolProvider' },
   [ms.textDocument_references] = { 'referencesProvider' },
   [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' },
+  [ms.textDocument_rangesFormatting] = { 'documentRangeFormattingProvider', 'rangesSupport' },
   [ms.textDocument_formatting] = { 'documentFormattingProvider' },
   [ms.textDocument_completion] = { 'completionProvider' },
   [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' },
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 299b68e134..f20730b8e6 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -205,9 +205,11 @@ end
 --- Range to format.
 --- Table must contain `start` and `end` keys with {row,col} tuples using
 --- (1,0) indexing.
+--- Can also be a list of tables that contain `start` and `end` keys as described above,
+--- in which case `textDocument/rangesFormatting` support is required.
 --- (Default: current selection in visual mode, `nil` in other modes,
 --- formatting the full buffer)
---- @field range? {start:integer[],end:integer[]}
+--- @field range? {start:[integer,integer],end:[integer, integer]}|{start:[integer,integer],end:[integer,integer]}[]
 
 --- Formats a buffer using the attached (and optionally filtered) language
 --- server clients.
@@ -218,10 +220,20 @@ function M.format(opts)
   local bufnr = opts.bufnr or api.nvim_get_current_buf()
   local mode = api.nvim_get_mode().mode
   local range = opts.range
+  -- Try to use visual selection if no range is given
   if not range and mode == 'v' or mode == 'V' then
     range = range_from_selection(bufnr, mode)
   end
-  local method = range and ms.textDocument_rangeFormatting or ms.textDocument_formatting
+
+  local passed_multiple_ranges = (range and #range ~= 0 and type(range[1]) == 'table')
+  local method ---@type string
+  if passed_multiple_ranges then
+    method = ms.textDocument_rangesFormatting
+  elseif range then
+    method = ms.textDocument_rangeFormatting
+  else
+    method = ms.textDocument_formatting
+  end
 
   local clients = vim.lsp.get_clients({
     id = opts.id,
@@ -241,10 +253,14 @@ function M.format(opts)
   --- @param params lsp.DocumentFormattingParams
   --- @return lsp.DocumentFormattingParams
   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
+    local to_lsp_range = function(r) ---@return lsp.DocumentRangeFormattingParams|lsp.DocumentRangesFormattingParams
+      return util.make_given_range_params(r.start, r['end'], bufnr, client.offset_encoding).range
+    end
+
+    if passed_multiple_ranges then
+      params.ranges = vim.tbl_map(to_lsp_range, range)
+    elseif range then
+      params.range = to_lsp_range(range)
     end
     return params
   end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index eb18043843..656921644d 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -425,6 +425,7 @@ function protocol.make_client_capabilities()
       },
       rangeFormatting = {
         dynamicRegistration = true,
+        rangesSupport = true,
       },
       completion = {
         dynamicRegistration = false,
-- 
cgit 


From f8795365deb88ab4e108858c563284b1082d06d4 Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Fri, 21 Jun 2024 16:23:02 +0300
Subject: test(lua): cover `vim._with()` with tests

Problem: `vim._with()` has many different use cases which are not
  covered with tests.

Solution: cover with tests. Some (many) test cases are intentionally
  marked as "pending" because they cover cases which don't work as
  expected at the moment (and fixing them requires specific knowledge of
  C codebase). Use them as a reference for future fixes.
  Also some of "can be nested" tests currently might pass only because
  the tested context doesn't work.
---
 runtime/lua/vim/shared.lua | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 7fd29d5f7b..79e614aaaa 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -1144,7 +1144,6 @@ end
 --- @field buf? integer
 --- @field emsg_silent? boolean
 --- @field hide? boolean
---- @field horizontal? boolean
 --- @field keepalt? boolean
 --- @field keepjumps? boolean
 --- @field keepmarks? boolean
@@ -1159,6 +1158,15 @@ end
 
 --- Executes function `f` with the given context specification.
 ---
+--- Notes:
+--- - Context `{ buf = buf }` has no guarantees about current window when
+---   inside context.
+--- - Context `{ buf = buf, win = win }` is yet not allowed, but this seems
+---   to be an implementation detail.
+--- - There should be no way to revert currently set `context.sandbox = true`
+---   (like with nested `vim._with()` calls). Otherwise it kind of breaks the
+---   whole purpose of sandbox execution.
+---
 --- @param context vim.context.mods
 function vim._with(context, f)
   vim.validate('context', context, 'table')
@@ -1167,7 +1175,6 @@ function vim._with(context, f)
   vim.validate('context.buf', context.buf, 'number', true)
   vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true)
   vim.validate('context.hide', context.hide, 'boolean', true)
-  vim.validate('context.horizontal', context.horizontal, 'boolean', true)
   vim.validate('context.keepalt', context.keepalt, 'boolean', true)
   vim.validate('context.keepjumps', context.keepjumps, 'boolean', true)
   vim.validate('context.keepmarks', context.keepmarks, 'boolean', true)
@@ -1192,6 +1199,10 @@ function vim._with(context, f)
     if not vim.api.nvim_win_is_valid(context.win) then
       error('Invalid window id: ' .. context.win)
     end
+    -- TODO: Maybe allow it?
+    if context.buf and vim.api.nvim_win_get_buf(context.win) ~= context.buf then
+      error('Can not set both `buf` and `win` context.')
+    end
   end
 
   -- Store original options
@@ -1214,7 +1225,7 @@ function vim._with(context, f)
     end
   end
 
-  return unpack(retval)
+  return unpack(retval, 1, table.maxn(retval))
 end
 
 return vim
-- 
cgit 


From 07cc559cdf11acb3031b6b7ba53e65285a6f4b3f Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Fri, 21 Jun 2024 16:23:05 +0300
Subject: feat(lua): update `vim._with` to allow more granular option contexts

Problem: with a single `context.options` there is no way for user to
  force which scope (local, global, both) is being temporarily set and
  later restored.

Solution: replace single `options` context with `bo`, `go`, `wo`, and
  `o`. Naming and implementation follows how options can be set directly
  with `vim.*` (like `vim.bo`, etc.).
  Options are set for possible target `win` or `buf` context.
---
 runtime/lua/vim/shared.lua | 99 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 82 insertions(+), 17 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 79e614aaaa..0c20248d8e 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -1141,8 +1141,10 @@ end
 
 --- @nodoc
 --- @class vim.context.mods
+--- @field bo? table
 --- @field buf? integer
 --- @field emsg_silent? boolean
+--- @field go? table
 --- @field hide? boolean
 --- @field keepalt? boolean
 --- @field keepjumps? boolean
@@ -1150,11 +1152,47 @@ end
 --- @field keeppatterns? boolean
 --- @field lockmarks? boolean
 --- @field noautocmd? boolean
---- @field options? table
+--- @field o? table
 --- @field sandbox? boolean
 --- @field silent? boolean
 --- @field unsilent? boolean
 --- @field win? integer
+--- @field wo? table
+
+--- @nodoc
+--- @class vim.context.state
+--- @field bo? table
+--- @field go? table
+--- @field wo? table
+
+local scope_map = { buf = 'bo', global = 'go', win = 'wo' }
+local scope_order = { 'o', 'wo', 'bo', 'go' }
+local state_restore_order = { 'bo', 'wo', 'go' }
+
+--- Gets data about current state, enough to properly restore specified options/env/etc.
+--- @param context vim.context.mods
+--- @return vim.context.state
+local get_context_state = function(context)
+  local res = { bo = {}, go = {}, wo = {} }
+
+  -- Use specific order from possibly most to least intrusive
+  for _, scope in ipairs(scope_order) do
+    for name, _ in pairs(context[scope] or {}) do
+      local sc = scope == 'o' and scope_map[vim.api.nvim_get_option_info2(name, {}).scope] or scope
+
+      -- Do not override already set state and fall back to `vim.NIL` for
+      -- state `nil` values (which still needs restoring later)
+      res[sc][name] = res[sc][name] or vim[sc][name] or vim.NIL
+
+      -- Always track global option value to properly restore later.
+      -- This matters for at least `o` and `wo` (which might set either/both
+      -- local and global option values).
+      res.go[name] = res.go[name] or vim.go[name]
+    end
+  end
+
+  return res
+end
 
 --- Executes function `f` with the given context specification.
 ---
@@ -1166,14 +1204,24 @@ end
 --- - There should be no way to revert currently set `context.sandbox = true`
 ---   (like with nested `vim._with()` calls). Otherwise it kind of breaks the
 ---   whole purpose of sandbox execution.
+--- - Saving and restoring option contexts (`bo`, `go`, `o`, `wo`) trigger
+---   `OptionSet` events. This is an implementation issue because not doing it
+---   seems to mean using either 'eventignore' option or extra nesting with
+---   `{ noautocmd = true }` (which itself is a wrapper for 'eventignore').
+---   As `{ go = { eventignore = '...' } }` is a valid context which should be
+---   properly set and restored, this is not a good approach.
+---   Not triggering `OptionSet` seems to be a good idea, though. So probably
+---   only moving context save and restore to lower level might resolve this.
 ---
 --- @param context vim.context.mods
 function vim._with(context, f)
   vim.validate('context', context, 'table')
   vim.validate('f', f, 'function')
 
+  vim.validate('context.bo', context.bo, 'table', true)
   vim.validate('context.buf', context.buf, 'number', true)
   vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true)
+  vim.validate('context.go', context.go, 'table', true)
   vim.validate('context.hide', context.hide, 'boolean', true)
   vim.validate('context.keepalt', context.keepalt, 'boolean', true)
   vim.validate('context.keepjumps', context.keepjumps, 'boolean', true)
@@ -1181,11 +1229,12 @@ function vim._with(context, f)
   vim.validate('context.keeppatterns', context.keeppatterns, 'boolean', true)
   vim.validate('context.lockmarks', context.lockmarks, 'boolean', true)
   vim.validate('context.noautocmd', context.noautocmd, 'boolean', true)
-  vim.validate('context.options', context.options, 'table', true)
+  vim.validate('context.o', context.o, 'table', true)
   vim.validate('context.sandbox', context.sandbox, 'boolean', true)
   vim.validate('context.silent', context.silent, 'boolean', true)
   vim.validate('context.unsilent', context.unsilent, 'boolean', true)
   vim.validate('context.win', context.win, 'number', true)
+  vim.validate('context.wo', context.wo, 'table', true)
 
   -- Check buffer exists
   if context.buf then
@@ -1205,27 +1254,43 @@ function vim._with(context, f)
     end
   end
 
-  -- Store original options
-  local previous_options ---@type table
-  if context.options then
-    previous_options = {}
-    for k, v in pairs(context.options) do
-      previous_options[k] =
-        vim.api.nvim_get_option_value(k, { win = context.win, buf = context.buf })
-      vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf })
+  -- Decorate so that save-set-restore options is done in correct window-buffer
+  local callback = function()
+    -- Cache current values to be changed by context
+    -- Abort early in case of bad context value
+    local ok, state = pcall(get_context_state, context)
+    if not ok then
+      error(state, 0)
     end
-  end
 
-  local retval = { vim._with_c(context, f) }
+    -- Apply some parts of the context in specific order
+    -- NOTE: triggers `OptionSet` event
+    for _, scope in ipairs(scope_order) do
+      for name, context_value in pairs(context[scope] or {}) do
+        vim[scope][name] = context_value
+      end
+    end
+
+    -- Execute
+    local res = { pcall(f) }
+
+    -- Restore relevant cached values in specific order, global scope last
+    -- NOTE: triggers `OptionSet` event
+    for _, scope in ipairs(state_restore_order) do
+      for name, cached_value in pairs(state[scope]) do
+        vim[scope][name] = cached_value
+      end
+    end
 
-  -- Restore original options
-  if previous_options then
-    for k, v in pairs(previous_options) do
-      vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf })
+    -- Return
+    if not res[1] then
+      error(res[2], 0)
     end
+    table.remove(res, 1)
+    return unpack(res, 1, table.maxn(res))
   end
 
-  return unpack(retval, 1, table.maxn(retval))
+  return vim._with_c(context, callback)
 end
 
 return vim
-- 
cgit 


From cd53db2157f0cd27877451a6b00d66e9bed74e73 Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Sun, 23 Jun 2024 17:13:06 +0300
Subject: feat(lua): add `context.env` (environment variables) to `vim._with()`

---
 runtime/lua/vim/shared.lua | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 0c20248d8e..6de1ce9d0c 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -1144,6 +1144,7 @@ end
 --- @field bo? table
 --- @field buf? integer
 --- @field emsg_silent? boolean
+--- @field env? table
 --- @field go? table
 --- @field hide? boolean
 --- @field keepalt? boolean
@@ -1162,18 +1163,19 @@ end
 --- @nodoc
 --- @class vim.context.state
 --- @field bo? table
+--- @field env? table
 --- @field go? table
 --- @field wo? table
 
 local scope_map = { buf = 'bo', global = 'go', win = 'wo' }
-local scope_order = { 'o', 'wo', 'bo', 'go' }
-local state_restore_order = { 'bo', 'wo', 'go' }
+local scope_order = { 'o', 'wo', 'bo', 'go', 'env' }
+local state_restore_order = { 'bo', 'wo', 'go', 'env' }
 
 --- Gets data about current state, enough to properly restore specified options/env/etc.
 --- @param context vim.context.mods
 --- @return vim.context.state
 local get_context_state = function(context)
-  local res = { bo = {}, go = {}, wo = {} }
+  local res = { bo = {}, env = {}, go = {}, wo = {} }
 
   -- Use specific order from possibly most to least intrusive
   for _, scope in ipairs(scope_order) do
@@ -1187,7 +1189,9 @@ local get_context_state = function(context)
       -- Always track global option value to properly restore later.
       -- This matters for at least `o` and `wo` (which might set either/both
       -- local and global option values).
-      res.go[name] = res.go[name] or vim.go[name]
+      if sc ~= 'env' then
+        res.go[name] = res.go[name] or vim.go[name]
+      end
     end
   end
 
@@ -1221,6 +1225,7 @@ function vim._with(context, f)
   vim.validate('context.bo', context.bo, 'table', true)
   vim.validate('context.buf', context.buf, 'number', true)
   vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true)
+  vim.validate('context.env', context.env, 'table', true)
   vim.validate('context.go', context.go, 'table', true)
   vim.validate('context.hide', context.hide, 'boolean', true)
   vim.validate('context.keepalt', context.keepalt, 'boolean', true)
-- 
cgit 


From fc9b70826ec88ca2e6c0624c522b872e87aa7ac1 Mon Sep 17 00:00:00 2001
From: Matt Fellenz 
Date: Wed, 26 Jun 2024 08:03:46 -0700
Subject: fix(lsp): avoid vim.keymap.del error when stopping a client (#29478)

---
 runtime/lua/vim/lsp.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 7fe4dd8cf5..39222cb8bc 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -380,7 +380,7 @@ local function reset_defaults(bufnr)
   end
   api.nvim_buf_call(bufnr, function()
     local keymap = vim.fn.maparg('K', 'n', false, true)
-    if keymap and keymap.callback == vim.lsp.buf.hover then
+    if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
       vim.keymap.del('n', 'K', { buffer = bufnr })
     end
   end)
-- 
cgit 


From bda63d5b97dfb333de6f4bd757dbb978906062a2 Mon Sep 17 00:00:00 2001
From: bfredl 
Date: Tue, 25 Jun 2024 15:33:47 +0200
Subject: refactor(typval)!: remove distinction of binary and nonbinary strings

This is a breaking change which will make refactor of typval and shada
code a lot easier. In particular, code that would use or check for
v:msgpack_types.binary in the wild would be broken. This appears to be
rarely used in existing plugins.

Also some cases where v:msgpack_type.string would be used to represent a
binary string of "string" type, we use a BLOB instead, which is
vimscripts native type for binary blobs, and already was used for BIN
formats when necessary.

msgpackdump(msgpackparse(data)) no longer preserves the distinction
of BIN and STR strings. This is very common behavior for
language-specific msgpack bindings. Nvim uses msgpack as a tool to
serialize its data. Nvim is not a tool to bit-perfectly manipulate
arbitrary msgpack data out in the wild.

The changed tests should indicate how behavior changes in various edge
cases.
---
 runtime/lua/vim/_meta/vimfn.lua | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 11dcbc010b..9d4cc825ec 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -6177,12 +6177,7 @@ function vim.fn.msgpackdump(list, type) end
 ---      C parser does not support such values.
 --- float  |Float|. This value cannot possibly appear in
 ---   |msgpackparse()| output.
---- string  |readfile()|-style list of strings. This value will
----   appear in |msgpackparse()| output if string contains
----   zero byte or if string is a mapping key and mapping is
----   being represented as special dictionary for other
----   reasons.
---- binary  |String|, or |Blob| if binary string contains zero
+--- string  |String|, or |Blob| if binary string contains zero
 ---   byte. This value cannot appear in |msgpackparse()|
 ---   output since blobs were introduced.
 --- array  |List|. This value cannot appear in |msgpackparse()|
-- 
cgit 


From 724d1110b1e4699a34f489e9cdb2d25098746499 Mon Sep 17 00:00:00 2001
From: Mathias Fußenegger 
Date: Thu, 27 Jun 2024 12:20:00 +0200
Subject: fix(lsp): pre-filter matches on label if filterText is missing
 (#29491)

Although the built-in pum completion mechanism will filter anyway on the
next input it is odd if the initial popup shows entries which don't
match the current prefix.

Using fuzzy match on the label/prefix is compatible with
`completeopt+=fuzzy` and also doesn't seem to break postfix snippet
cases

Closes https://github.com/neovim/neovim/issues/29287
---
 runtime/lua/vim/lsp/completion.lua | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index 2e6d82b367..b935c48d3c 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -235,14 +235,20 @@ function M._lsp_to_complete_items(result, prefix, client_id)
     return {}
   end
 
-  local matches = prefix == '' and function()
-    return true
-  end or function(item)
-    if item.filterText then
-      return next(vim.fn.matchfuzzy({ item.filterText }, prefix))
+  ---@type fun(item: lsp.CompletionItem):boolean
+  local matches
+  if prefix == '' then
+    matches = function(_)
+      return true
+    end
+  else
+    ---@param item lsp.CompletionItem
+    matches = function(item)
+      local text = item.filterText or item.label
+      return next(vim.fn.matchfuzzy({ text }, prefix)) ~= nil
     end
-    return true
   end
+
   local candidates = {}
   for _, item in ipairs(items) do
     if matches(item) then
-- 
cgit 


From aa6b9c677d83d76d448c3bb0973bf8d14bfdf922 Mon Sep 17 00:00:00 2001
From: dundargoc 
Date: Sat, 8 Jun 2024 21:40:18 +0200
Subject: refactor: use `vim._with` where possible

This mostly means replacing `nvim_buf_call` and `nvim_win_call` with
`vim._with`.
---
 runtime/lua/tohtml.lua                     | 6 +++---
 runtime/lua/vim/_inspector.lua             | 2 +-
 runtime/lua/vim/diagnostic.lua             | 2 +-
 runtime/lua/vim/filetype/detect.lua        | 2 +-
 runtime/lua/vim/highlight.lua              | 2 +-
 runtime/lua/vim/lsp.lua                    | 4 ++--
 runtime/lua/vim/lsp/util.lua               | 6 +++---
 runtime/lua/vim/shared.lua                 | 2 ++
 runtime/lua/vim/snippet.lua                | 2 +-
 runtime/lua/vim/treesitter/highlighter.lua | 2 +-
 runtime/lua/vim/ui.lua                     | 7 +++----
 11 files changed, 19 insertions(+), 18 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua
index a67e1c69e2..37ad60b436 100644
--- a/runtime/lua/tohtml.lua
+++ b/runtime/lua/tohtml.lua
@@ -646,7 +646,7 @@ end
 --- @param state vim.tohtml.state
 local function styletable_conceal(state)
   local bufnr = state.bufnr
-  vim.api.nvim_buf_call(bufnr, function()
+  vim._with({ buf = bufnr }, function()
     for row = 1, state.buflen do
       --- @type table
       local conceals = {}
@@ -764,7 +764,7 @@ local function styletable_statuscolumn(state)
     if foldcolumn:match('^auto') then
       local max = tonumber(foldcolumn:match('^%w-:(%d)')) or 1
       local maxfold = 0
-      vim.api.nvim_buf_call(state.bufnr, function()
+      vim._with({ buf = state.bufnr }, function()
         for row = 1, vim.api.nvim_buf_line_count(state.bufnr) do
           local foldlevel = vim.fn.foldlevel(row)
           if foldlevel > maxfold then
@@ -1291,7 +1291,7 @@ local styletable_funcs = {
 
 --- @param state vim.tohtml.state
 local function state_generate_style(state)
-  vim.api.nvim_win_call(state.winid, function()
+  vim._with({ win = state.winid }, function()
     for _, fn in ipairs(styletable_funcs) do
       --- @type string?
       local cond
diff --git a/runtime/lua/vim/_inspector.lua b/runtime/lua/vim/_inspector.lua
index f5d1640c82..21dacbe41d 100644
--- a/runtime/lua/vim/_inspector.lua
+++ b/runtime/lua/vim/_inspector.lua
@@ -84,7 +84,7 @@ function vim.inspect_pos(bufnr, row, col, filter)
 
   -- syntax
   if filter.syntax and vim.api.nvim_buf_is_valid(bufnr) then
-    vim.api.nvim_buf_call(bufnr, function()
+    vim._with({ buf = bufnr }, function()
       for _, i1 in ipairs(vim.fn.synstack(row + 1, col + 1)) do
         results.syntax[#results.syntax + 1] =
           resolve_hl({ hl_group = vim.fn.synIDattr(i1, 'name') })
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 3be22556ab..43954358a3 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -964,7 +964,7 @@ local function goto_diagnostic(diagnostic, opts)
 
   local winid = opts.winid or api.nvim_get_current_win()
 
-  api.nvim_win_call(winid, function()
+  vim._with({ win = winid }, function()
     -- Save position in the window's jumplist
     vim.cmd("normal! m'")
     api.nvim_win_set_cursor(winid, { diagnostic.lnum + 1, diagnostic.col })
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index b52dba7388..e1891e299e 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -450,7 +450,7 @@ local function modula2(bufnr)
 
   return 'modula2',
     function(b)
-      vim.api.nvim_buf_call(b, function()
+      vim._with({ buf = b }, function()
         fn['modula2#SetDialect'](dialect, extension)
       end)
     end
diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua
index 233bc50237..a8d88db372 100644
--- a/runtime/lua/vim/highlight.lua
+++ b/runtime/lua/vim/highlight.lua
@@ -71,7 +71,7 @@ function M.range(bufnr, ns, higroup, start, finish, opts)
     return
   end
 
-  vim.api.nvim_buf_call(bufnr, function()
+  vim._with({ buf = bufnr }, function()
     if pos1[3] ~= v_maxcol then
       local max_col1 = vim.fn.col({ pos1[2], '$' })
       pos1[3] = math.min(pos1[3], max_col1)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 39222cb8bc..382ec58156 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -352,7 +352,7 @@ function lsp._set_defaults(client, bufnr)
   then
     vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr()'
   end
-  api.nvim_buf_call(bufnr, function()
+  vim._with({ buf = bufnr }, function()
     if
       client.supports_method(ms.textDocument_hover)
       and is_empty_or_default(bufnr, 'keywordprg')
@@ -378,7 +378,7 @@ local function reset_defaults(bufnr)
   if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
     vim.bo[bufnr].formatexpr = nil
   end
-  api.nvim_buf_call(bufnr, function()
+  vim._with({ buf = bufnr }, function()
     local keymap = vim.fn.maparg('K', 'n', false, true)
     if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
       vim.keymap.del('n', 'K', { buffer = bufnr })
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index a5cf13ed0f..b0fd25af3a 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -640,7 +640,7 @@ function M.rename(old_fname, new_fname, opts)
     -- Rename with :saveas. This does two things:
     -- * Unset BF_WRITE_MASK, so that users don't get E13 when they do :write.
     -- * Send didClose and didOpen via textDocument/didSave handler.
-    api.nvim_buf_call(b, function()
+    vim._with({ buf = b }, function()
       vim.cmd('keepalt saveas! ' .. vim.fn.fnameescape(rename.to))
     end)
     -- Delete the new buffer with the old name created by :saveas. nvim_buf_delete and
@@ -1014,7 +1014,7 @@ function M.show_document(location, offset_encoding, opts)
     local row = range.start.line
     local col = get_line_byte_from_position(bufnr, range.start, offset_encoding)
     api.nvim_win_set_cursor(win, { row + 1, col })
-    api.nvim_win_call(win, function()
+    vim._with({ win = win }, function()
       -- Open folds under the cursor
       vim.cmd('normal! zv')
     end)
@@ -1334,7 +1334,7 @@ function M.stylize_markdown(bufnr, contents, opts)
   end
 
   -- needs to run in the buffer for the regions to work
-  api.nvim_buf_call(bufnr, function()
+  vim._with({ buf = bufnr }, function()
     -- we need to apply lsp_markdown regions speperately, since otherwise
     -- markdown regions can "bleed" through the other syntax regions
     -- and mess up the formatting
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 6de1ce9d0c..621de2b1c2 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -1218,6 +1218,8 @@ end
 ---   only moving context save and restore to lower level might resolve this.
 ---
 --- @param context vim.context.mods
+--- @param f function
+--- @return any
 function vim._with(context, f)
   vim.validate('context', context, 'table')
   vim.validate('f', f, 'function')
diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua
index 98a7a79ce0..a880bf0197 100644
--- a/runtime/lua/vim/snippet.lua
+++ b/runtime/lua/vim/snippet.lua
@@ -257,7 +257,7 @@ end
 function Session:restore_keymaps()
   local function restore(keymap, lhs, mode)
     if keymap then
-      vim.api.nvim_buf_call(self.bufnr, function()
+      vim._with({ buf = self.bufnr }, function()
         vim.fn.mapset(keymap)
       end)
     else
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index cd5c67d816..052b839609 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -143,7 +143,7 @@ function TSHighlighter.new(tree, opts)
     vim.cmd.runtime({ 'syntax/synload.vim', bang = true })
   end
 
-  api.nvim_buf_call(self.bufnr, function()
+  vim._with({ buf = self.bufnr }, function()
     vim.opt_local.spelloptions:append('noplainbuffer')
   end)
 
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
index f168da4955..ec5c5c5ba0 100644
--- a/runtime/lua/vim/ui.lua
+++ b/runtime/lua/vim/ui.lua
@@ -180,10 +180,9 @@ function M._get_url()
     end
   end
 
-  local old_isfname = vim.o.isfname
-  vim.cmd [[set isfname+=@-@]]
-  local url = vim.fn.expand('')
-  vim.o.isfname = old_isfname
+  local url = vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function()
+    return vim.fn.expand('')
+  end)
 
   return url
 end
-- 
cgit 


From e7020306a19a5211c834966ec067fff3b981bdb9 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 30 Jun 2024 06:40:31 +0800
Subject: feat(jumplist): allow opting out of removing unloaded buffers
 (#29347)

Problem:  Cannot opt out of removing unloaded buffers from the jumplist.
Solution: Only enable that with "unload" flag in 'jumpoptions'.
---
 runtime/lua/vim/_meta/options.lua | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 902df8f7d6..fb04da14a5 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -3551,8 +3551,11 @@ vim.go.js = vim.go.joinspaces
 --- 		|alternate-file` or using `mark-motions` try to
 --- 		restore the `mark-view` in which the action occurred.
 ---
+---   unload        Remove unloaded buffers from the jumplist.
+--- 		EXPERIMENTAL: this flag may change in the future.
+---
 --- @type string
-vim.o.jumpoptions = ""
+vim.o.jumpoptions = "unload"
 vim.o.jop = vim.o.jumpoptions
 vim.go.jumpoptions = vim.o.jumpoptions
 vim.go.jop = vim.go.jumpoptions
-- 
cgit 


From aec7f1979ada1b34cfb3d8fd33769232d0323ea8 Mon Sep 17 00:00:00 2001
From: Sebastian Lyng Johansen 
Date: Tue, 2 Jul 2024 18:27:51 +0200
Subject: fix(lsp): fallback to `label` for completion items if all others are
 missing (#29522)

---
 runtime/lua/vim/lsp/completion.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index b935c48d3c..1078e3eb7e 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -176,7 +176,7 @@ local function apply_defaults(item, defaults)
   if defaults.editRange then
     local textEdit = item.textEdit or {}
     item.textEdit = textEdit
-    textEdit.newText = textEdit.newText or item.textEditText or item.insertText
+    textEdit.newText = textEdit.newText or item.textEditText or item.insertText or item.label
     if defaults.editRange.start then
       textEdit.range = textEdit.range or defaults.editRange
     elseif defaults.editRange.insert then
-- 
cgit 


From d413038b4fd71b7a335b6653aa64d2cb6daeac7b Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 3 Jul 2024 07:40:42 +0800
Subject: fix(treesitter): ensure syntaxset augroup exists (#29542)

Problem:
Error when calling vim.treesitter.start() and vim.treesitter.stop() in
init.lua.

Solution:
Ensure syntaxset augroup exists after loading synload.vim.
---
 runtime/lua/vim/treesitter/highlighter.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 052b839609..a94c408f4e 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -139,8 +139,11 @@ function TSHighlighter.new(tree, opts)
   -- but use synload.vim rather than syntax.vim to not enable
   -- syntax FileType autocmds. Later on we should integrate with the
   -- `:syntax` and `set syntax=...` machinery properly.
+  -- Still need to ensure that syntaxset augroup exists, so that calling :destroy()
+  -- immediately afterwards will not error.
   if vim.g.syntax_on ~= 1 then
     vim.cmd.runtime({ 'syntax/synload.vim', bang = true })
+    vim.api.nvim_create_augroup('syntaxset', { clear = false })
   end
 
   vim._with({ buf = self.bufnr }, function()
-- 
cgit 


From 7f33c1967b78ca8fda11fb0ad4c7f57d563e6ede Mon Sep 17 00:00:00 2001
From: Tyler Miller 
Date: Wed, 3 Jul 2024 15:36:00 -0700
Subject: fix(lua): use rawget() to get __call in vim.is_callable() (#29536)

Lua 5.1 uses a "raw get" to retrieve `__call` from a metatable to
determine if a table is callable. Mirror this behavior in
`vim.is_callable()`.
---
 runtime/lua/vim/shared.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 621de2b1c2..99530bf72e 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -997,7 +997,7 @@ function vim.is_callable(f)
   if m == nil then
     return false
   end
-  return type(m.__call) == 'function'
+  return type(rawget(m, '__call')) == 'function'
 end
 
 --- Creates a table whose missing keys are provided by {createfn} (like Python's "defaultdict").
-- 
cgit 


From 4b3be56a03695fa14ed28d6ded4cb338cbb99249 Mon Sep 17 00:00:00 2001
From: Peter Aronoff 
Date: Thu, 4 Jul 2024 13:15:35 -0400
Subject: fix(diagnostic): make docs agree with code (#29561)

Problem: the code and docs for vim.diagnostic.JumpOpts.float send mixed
signals about what the default should be. When the option is first set,
in the global_diagnostic_options table, the comment clearly says that
the default is false. Later in the code, in goto_diagnostic, there's
a line that sets the default to true if no default is present. Finally,
the docs say that the default is true.

Solution: Change the docs to reflect the new default of false and fix
the goto_diagnostic function.
---
 runtime/lua/vim/diagnostic.lua | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 43954358a3..a4280506ab 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -972,9 +972,8 @@ local function goto_diagnostic(diagnostic, opts)
     vim.cmd('normal! zv')
   end)
 
-  local float = if_nil(opts.float, true)
-  if float then
-    local float_opts = type(float) == 'table' and float or {}
+  if opts.float then
+    local float_opts = type(opts.float) == 'table' and opts.float or {}
     vim.schedule(function()
       M.open_float(vim.tbl_extend('keep', float_opts, {
         bufnr = api.nvim_win_get_buf(winid),
@@ -1271,7 +1270,7 @@ end
 --- If a table, pass the table as the {opts} parameter to |vim.diagnostic.open_float()|.
 --- Unless overridden, the float will show diagnostics at the new cursor
 --- position (as if "cursor" were passed to the "scope" option).
---- (default: `true`)
+--- (default: `false`)
 --- @field float? boolean|vim.diagnostic.Opts.Float
 ---
 --- Window ID
-- 
cgit 


From 9217e0d671b790d39192181cb894cfec012f06a6 Mon Sep 17 00:00:00 2001
From: Riley Bruins 
Date: Thu, 4 Jul 2024 10:09:19 -0700
Subject: fix(treesitter): display fields for anonymous nodes in :InspectTree

---
 runtime/lua/vim/treesitter/dev.lua | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua
index 56608bbf14..bd0ef5a011 100644
--- a/runtime/lua/vim/treesitter/dev.lua
+++ b/runtime/lua/vim/treesitter/dev.lua
@@ -220,14 +220,13 @@ function TSTreeView:draw(bufnr)
 
     local text ---@type string
     if item.node:named() then
-      if item.field then
-        text = string.format('%s: (%s', item.field, item.node:type())
-      else
-        text = string.format('(%s', item.node:type())
-      end
+      text = string.format('(%s', item.node:type())
     else
       text = string.format('%q', item.node:type()):gsub('\n', 'n')
     end
+    if item.field then
+      text = string.format('%s: %s', item.field, text)
+    end
 
     local next = self:get(i + 1)
     if not next or next.depth <= item.depth then
-- 
cgit 


From 0abaccb2a795c40cd7f55b9a19fe6ecb765479e2 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Fri, 5 Jul 2024 21:39:51 +0200
Subject: vim-patch:9.1.0532: filetype: Cedar files not recognized

Problem:  filetype: Cedar files not recognized
Solution: Detect '*.cedar' files as cedar filetype
          (Riley Bruins)

References: https://github.com/cedar-policy

closes: vim/vim#15148

https://github.com/vim/vim/commit/15addb24dd3b2645f5c04d2742ab5eb53444a3a0

Co-authored-by: Riley Bruins 
---
 runtime/lua/vim/filetype.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 6d3fc48efc..d2cf87bea5 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -261,6 +261,7 @@ local extension = {
   cdc = 'cdc',
   cdl = 'cdl',
   toc = detect_line1('\\contentsline', 'tex', 'cdrtoc'),
+  cedar = 'cedar',
   cfc = 'cf',
   cfm = 'cf',
   cfi = 'cf',
-- 
cgit 


From b109b1abce8c86f80aea06948b32e35a70daa0b0 Mon Sep 17 00:00:00 2001
From: Zoltán Nyikos 
Date: Sat, 6 Jul 2024 11:40:08 +0200
Subject: fix(glob): avoid `subcapture nesting too deep` error (#29520)

Use Cmt to evaluate Cond and Elem during match to avoid building the
nested capture structure later.
---
 runtime/lua/vim/glob.lua | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/glob.lua b/runtime/lua/vim/glob.lua
index 6de2bc3e94..22073b15c8 100644
--- a/runtime/lua/vim/glob.lua
+++ b/runtime/lua/vim/glob.lua
@@ -1,6 +1,6 @@
 local lpeg = vim.lpeg
 local P, S, V, R, B = lpeg.P, lpeg.S, lpeg.V, lpeg.R, lpeg.B
-local C, Cc, Ct, Cf = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cf
+local C, Cc, Ct, Cf, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cf, lpeg.Cmt
 
 local M = {}
 
@@ -47,13 +47,22 @@ function M.to_lpeg(pattern)
     return (-after * P(1)) ^ 0 * after
   end
 
+  -- luacheck: push ignore s
+  local function cut(s, idx, match)
+    return idx, match
+  end
+  -- luacheck: pop
+
   local p = P({
     'Pattern',
     Pattern = V('Elem') ^ -1 * V('End'),
-    Elem = Cf(
-      (V('DStar') + V('Star') + V('Ques') + V('Class') + V('CondList') + V('Literal'))
-        * (V('Elem') + V('End')),
-      mul
+    Elem = Cmt(
+      Cf(
+        (V('DStar') + V('Star') + V('Ques') + V('Class') + V('CondList') + V('Literal'))
+          * (V('Elem') + V('End')),
+        mul
+      ),
+      cut
     ),
     DStar = (B(pathsep) + -B(P(1)))
       * P('**')
@@ -72,7 +81,7 @@ function M.to_lpeg(pattern)
     -- pattern" which in all other cases is the entire succeeding part of the pattern, but at the end of a {}
     -- condition means "everything after the {}" where several other options separated by ',' may
     -- exist in between that should not be matched by '*'.
-    Cond = Cf((V('Ques') + V('Class') + V('Literal') - S(',}')) ^ 1, mul) + Cc(P(0)),
+    Cond = Cmt(Cf((V('Ques') + V('Class') + V('Literal') - S(',}')) ^ 1, mul), cut) + Cc(P(0)),
     Literal = P(1) / P,
     End = P(-1) * Cc(P(-1)),
   })
-- 
cgit 


From 55e4301036bb938474fc9768c41e28df867d9286 Mon Sep 17 00:00:00 2001
From: Andreas Schneider 
Date: Sat, 6 Jul 2024 11:44:19 +0200
Subject: feat(lsp): drop fswatch, use inotifywait (#29374)

This patch replaces fswatch with inotifywait from inotify-toools:

https://github.com/inotify-tools/inotify-tools

fswatch takes ~1min to set up recursively for the Samba source code
directory. inotifywait needs less than a second to do the same thing.

https://github.com/emcrisostomo/fswatch/issues/321

Also it fswatch seems to be unmaintained in the meantime.

Signed-off-by: Andreas Schneider 
---
 runtime/lua/vim/_watch.lua          | 61 +++++++++++++++++--------------------
 runtime/lua/vim/lsp/_watchfiles.lua |  4 +--
 runtime/lua/vim/lsp/health.lua      |  6 ++--
 3 files changed, 33 insertions(+), 38 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua
index 02b3f536c2..40f18ce5b0 100644
--- a/runtime/lua/vim/_watch.lua
+++ b/runtime/lua/vim/_watch.lua
@@ -227,11 +227,12 @@ end
 --- @param data string
 --- @param opts vim._watch.Opts?
 --- @param callback vim._watch.Callback
-local function fswatch_output_handler(data, opts, callback)
+local function on_inotifywait_output(data, opts, callback)
   local d = vim.split(data, '%s+')
 
   -- only consider the last reported event
-  local fullpath, event = d[1], d[#d]
+  local path, event, file = d[1], d[2], d[#d]
+  local fullpath = vim.fs.joinpath(path, file)
 
   if skip(fullpath, opts) then
     return
@@ -240,20 +241,16 @@ local function fswatch_output_handler(data, opts, callback)
   --- @type integer
   local change_type
 
-  if event == 'Created' then
+  if event == 'CREATE' then
     change_type = M.FileChangeType.Created
-  elseif event == 'Removed' then
+  elseif event == 'DELETE' then
     change_type = M.FileChangeType.Deleted
-  elseif event == 'Updated' then
+  elseif event == 'MODIFY' then
     change_type = M.FileChangeType.Changed
-  elseif event == 'Renamed' then
-    local _, staterr, staterrname = uv.fs_stat(fullpath)
-    if staterrname == 'ENOENT' then
-      change_type = M.FileChangeType.Deleted
-    else
-      assert(not staterr, staterr)
-      change_type = M.FileChangeType.Created
-    end
+  elseif event == 'MOVED_FROM' then
+    change_type = M.FileChangeType.Deleted
+  elseif event == 'MOVED_TO' then
+    change_type = M.FileChangeType.Created
   end
 
   if change_type then
@@ -265,24 +262,22 @@ end
 --- @param opts vim._watch.Opts?
 --- @param callback vim._watch.Callback Callback for new events
 --- @return fun() cancel Stops the watcher
-function M.fswatch(path, opts, callback)
-  -- debounce isn't the same as latency but close enough
-  local latency = 0.5 -- seconds
-  if opts and opts.debounce then
-    latency = opts.debounce / 1000
-  end
-
+function M.inotify(path, opts, callback)
   local obj = vim.system({
-    'fswatch',
-    '--event=Created',
-    '--event=Removed',
-    '--event=Updated',
-    '--event=Renamed',
-    '--event-flags',
+    'inotifywait',
+    '--quiet', -- suppress startup messages
+    '--no-dereference', -- don't follow symlinks
+    '--monitor', -- keep listening for events forever
     '--recursive',
-    '--latency=' .. tostring(latency),
-    '--exclude',
-    '/.git/',
+    '--event',
+    'create',
+    '--event',
+    'delete',
+    '--event',
+    'modify',
+    '--event',
+    'move',
+    '@.git', -- ignore git directory
     path,
   }, {
     stderr = function(err, data)
@@ -292,11 +287,11 @@ function M.fswatch(path, opts, callback)
 
       if data and #vim.trim(data) > 0 then
         vim.schedule(function()
-          if vim.fn.has('linux') == 1 and vim.startswith(data, 'Event queue overflow') then
-            data = 'inotify(7) limit reached, see :h fswatch-limitations for more info.'
+          if vim.fn.has('linux') == 1 and vim.startswith(data, 'Failed to watch') then
+            data = 'inotify(7) limit reached, see :h inotify-limitations for more info.'
           end
 
-          vim.notify('fswatch: ' .. data, vim.log.levels.ERROR)
+          vim.notify('inotify: ' .. data, vim.log.levels.ERROR)
         end)
       end
     end,
@@ -306,7 +301,7 @@ function M.fswatch(path, opts, callback)
       end
 
       for line in vim.gsplit(data or '', '\n', { plain = true, trimempty = true }) do
-        fswatch_output_handler(line, opts, callback)
+        on_inotifywait_output(line, opts, callback)
       end
     end,
     -- --latency is locale dependent but tostring() isn't and will always have '.' as decimal point.
diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua
index 49328fbe9b..98e9818bcd 100644
--- a/runtime/lua/vim/lsp/_watchfiles.lua
+++ b/runtime/lua/vim/lsp/_watchfiles.lua
@@ -9,8 +9,8 @@ local M = {}
 
 if vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1 then
   M._watchfunc = watch.watch
-elseif vim.fn.executable('fswatch') == 1 then
-  M._watchfunc = watch.fswatch
+elseif vim.fn.executable('inotifywait') == 1 then
+  M._watchfunc = watch.inotify
 else
   M._watchfunc = watch.watchdirs
 end
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index ffe595ab37..18066a84db 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -90,8 +90,8 @@ local function check_watcher()
     watchfunc_name = 'libuv-watch'
   elseif watchfunc == vim._watch.watchdirs then
     watchfunc_name = 'libuv-watchdirs'
-  elseif watchfunc == vim._watch.fswatch then
-    watchfunc_name = 'fswatch'
+  elseif watchfunc == vim._watch.inotifywait then
+    watchfunc_name = 'inotifywait'
   else
     local nm = debug.getinfo(watchfunc, 'S').source
     watchfunc_name = string.format('Custom (%s)', nm)
@@ -99,7 +99,7 @@ local function check_watcher()
 
   report_info('File watch backend: ' .. watchfunc_name)
   if watchfunc_name == 'libuv-watchdirs' then
-    report_warn('libuv-watchdirs has known performance issues. Consider installing fswatch.')
+    report_warn('libuv-watchdirs has known performance issues. Consider installing inotify-tools.')
   end
 end
 
-- 
cgit 


From 5da9b49b19240bb00f338249fef84a2bf1212b49 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 7 Jul 2024 06:32:54 +0800
Subject: vim-patch:9.1.0537: signed number detection for CTRL-X/A can be
 improved (#29590)

Problem:  signed number detection for CTRL-X/A can be improved
          (Chris Patuzzo)
Solution: Add the new "blank" value for the 'nrformat' setting. This
          will make Vim assume a signed number only if there is a blank
          in front of the sign.
          (distobs)

fixes: vim/vim#15033
closes: vim/vim#15110

https://github.com/vim/vim/commit/25ac6d67d92e0adda53b8d44b81c15031643ca1e

Co-authored-by: distobs 
---
 runtime/lua/vim/_meta/options.lua | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index fb04da14a5..40c12d94fd 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -4549,6 +4549,20 @@ vim.go.mouset = vim.go.mousetime
 --- 	    (without "unsigned" it would become "9-2019").
 --- 	    Using CTRL-X on "0" or CTRL-A on "18446744073709551615"
 --- 	    (2^64 - 1) has no effect, overflow is prevented.
+--- blank	If included, treat numbers as signed or unsigned based on
+--- 	preceding whitespace. If a number with a leading dash has its
+--- 	dash immediately preceded by a non-whitespace character (i.e.,
+--- 	not a tab or a " "), the negative sign won't be considered as
+--- 	part of the number.  For example:
+--- 	    Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15"
+--- 	    (without "blank" it would become "Carbon-13").
+--- 	    Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9"
+--- 	    (because -8 is preceded by whitespace. If "unsigned" was
+--- 	    set, it would result in "Carbon -7").
+--- 	If this format is included, overflow is prevented as if
+--- 	"unsigned" were set. If both this format and "unsigned" are
+--- 	included, "unsigned" will take precedence.
+---
 --- Numbers which simply begin with a digit in the range 1-9 are always
 --- considered decimal.  This also happens for numbers that are not
 --- recognized as octal or hex.
-- 
cgit 


From 472b5b9b20756146db39cf32c6fb678e1d8104c0 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sat, 6 Jul 2024 18:00:09 +0200
Subject: vim-patch:9.1.0536: filetype: zone files are not recognized

Problem:  filetype: zone files are not recognized
          (rpdprd)
Solution: Detect '*.zone' files as bindzone filetype

fixes: vim/vim#14222

https://github.com/vim/vim/commit/f095539b3900d76f5eeaaa0897c6abf970829b31

Co-authored-by: Christian Brabandt 
---
 runtime/lua/vim/filetype.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index d2cf87bea5..eae5817aee 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -236,6 +236,7 @@ local extension = {
   db = detect.bindzone,
   bicep = 'bicep',
   bicepparam = 'bicep',
+  zone = 'bindzone',
   bb = 'bitbake',
   bbappend = 'bitbake',
   bbclass = 'bitbake',
-- 
cgit 


From 6a886a2511bbfd24a4d6ecc3f3a75f08a6df9de9 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 7 Jul 2024 07:21:14 +0800
Subject: vim-patch:9.1.0538: not possible to assign priority when defining a
 sign (#29592)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem:  not possible to assign priority when defining a sign
          (Mathias Fußenegger)
Solution: Add the priority argument for the :sign-define ex command and
          the sign_define() function (LemonBoy)

Use the specified value instead of the default one (SIGN_DEF_PRIO) when
no priority is explicitly specified in sign_place or :sign place.

fixes: vim/vim#8334
closes: vim/vim#15124

https://github.com/vim/vim/commit/b975ddfdf96644b8df808415dee36f99abd48753

Co-authored-by: LemonBoy 
---
 runtime/lua/vim/_meta/vimfn.lua | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 9d4cc825ec..e51041839b 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -8477,6 +8477,7 @@ function vim.fn.sign_define(list) end
 ---    linehl  highlight group used for the whole line the
 ---     sign is placed in; not present if not set.
 ---    name    name of the sign
+---    priority  default priority value of the sign
 ---    numhl  highlight group used for the line number where
 ---     the sign is placed; not present if not set.
 ---    text    text that is displayed when there is no icon
@@ -8668,7 +8669,8 @@ function vim.fn.sign_place(id, group, name, buf, dict) end
 ---     priority  Priority of the sign. When multiple signs are
 ---     placed on a line, the sign with the highest
 ---     priority is used. If not specified, the
----     default value of 10 is used. See
+---     default value of 10 is used, unless specified
+---     otherwise by the sign definition. See
 ---     |sign-priority| for more information.
 ---
 --- If {id} refers to an existing sign, then the existing sign is
-- 
cgit 


From 5b778a64ec2e82a7d8d28c3c36698cd42a41c539 Mon Sep 17 00:00:00 2001
From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com>
Date: Sun, 7 Jul 2024 11:37:39 +0300
Subject: fix(health): fix fetching url with python in provider health (#29594)

---
 runtime/lua/vim/provider/health.lua | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua
index 860f839f23..9ff4d15257 100644
--- a/runtime/lua/vim/provider/health.lua
+++ b/runtime/lua/vim/provider/health.lua
@@ -409,12 +409,15 @@ local function download(url)
       return out
     end
   elseif vim.fn.executable('python') == 1 then
-    local script = "try:\n\
-          from urllib.request import urlopen\n\
-          except ImportError:\n\
-          from urllib2 import urlopen\n\
-          response = urlopen('" .. url .. "')\n\
-          print(response.read().decode('utf8'))\n"
+    local script = ([[
+try:
+    from urllib.request import urlopen
+except ImportError:
+    from urllib2 import urlopen
+
+response = urlopen('%s')
+print(response.read().decode('utf8'))
+]]):format(url)
     local out, rc = system({ 'python', '-c', script })
     if out == '' and rc ~= 0 then
       return 'python urllib.request error: ' .. rc
-- 
cgit 


From 435ce9921374055ed2103212bb102e2506c1e2e3 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 8 Jul 2024 06:19:12 +0800
Subject: vim-patch:9.1.0540: Unused assignment in sign_define_cmd()

Problem:  Unused assignment in sign_define_cmd()
Solution: Remove the assignment.  Also document the "priority" flag of
          sign_define(). (zeertzjq)

closes: vim/vim#15169

https://github.com/vim/vim/commit/fc3f5dba52099d82ccc8bfe309d58a6fac01373d
---
 runtime/lua/vim/_meta/vimfn.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index e51041839b..34a3addb57 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -8427,6 +8427,7 @@ function vim.fn.sign_define(name, dict) end
 ---    icon    full path to the bitmap file for the sign.
 ---    linehl  highlight group used for the whole line the
 ---     sign is placed in.
+---    priority  default priority value of the sign
 ---    numhl  highlight group used for the line number where
 ---     the sign is placed.
 ---    text    text that is displayed when there is no icon
-- 
cgit 


From bf92d423a9ac4bd3d30685c23a0d9a0dd772b7a7 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Mon, 8 Jul 2024 10:39:03 +0200
Subject: vim-patch:9.1.0544: filetype: ldapconf files are not recognized

Problem:  filetype: ldapconf files are not recognized
Solution: Detect '.ldaprc', 'ldap.conf' and 'ldaprc' files as ldapconf
          filetype, include a simple ldapconf ftplugin file
          (Riley Bruins)

[Specification](https://www.openldap.org/software//man.cgi?query=ldap.conf&sektion=5&apropos=0&manpath=OpenLDAP+2.4-Release)

closes: vim/vim#15176

https://github.com/vim/vim/commit/62f31e949918167cb7f50cdf1737f7c28460b62b

Co-authored-by: Riley Bruins 
---
 runtime/lua/vim/filetype.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index eae5817aee..179a6312de 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1481,6 +1481,9 @@ local filename = {
   Kconfig = 'kconfig',
   ['Kconfig.debug'] = 'kconfig',
   ['Config.in'] = 'kconfig',
+  ['ldaprc'] = 'ldapconf',
+  ['.ldaprc'] = 'ldapconf',
+  ['ldap.conf'] = 'ldapconf',
   ['lftp.conf'] = 'lftp',
   ['.lftprc'] = 'lftp',
   ['/.libao'] = 'libao',
-- 
cgit 


From 8474f529780ba20f9179ad1b60167ee9e53f8374 Mon Sep 17 00:00:00 2001
From: Jaehwang Jung 
Date: Sat, 6 Jul 2024 15:34:05 +0900
Subject: fix(treesitter.foldexpr): robustness against ctrl-c

Problem:
Exiting the insert mode with ctrl-c does not trigger InsertLeave
autocmd. This may lead to nil error in treesitter foldexpr.

Solution:
Check nil. Folds still can be stale after exiting the insert mode with
ctrl-c, but it will be eventually updated correctly.

An alternative solution would be to ensure that exiting the insert mode
always triggers do_foldupdate. This can be done either by "fixing"
ctrl-c or with on_key callback that checks ctrl-c (nvim-cmp does this).
---
 runtime/lua/vim/treesitter/_fold.lua | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index 194e09babc..27590eff5d 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -264,6 +264,15 @@ end
 
 ---@package
 function FoldInfo:do_foldupdate(bufnr)
+  -- InsertLeave is not executed when  is used for exiting the insert mode, leaving
+  -- do_foldupdate untouched. If another execution of foldupdate consumes foldupdate_range, the
+  -- InsertLeave do_foldupdate gets nil foldupdate_range. In that case, skip the update. This is
+  -- correct because the update that consumed the range must have incorporated the range that
+  -- InsertLeave meant to update.
+  if not self.foldupdate_range then
+    return
+  end
+
   local srow, erow = self.foldupdate_range[1], self.foldupdate_range[2]
   self.foldupdate_range = nil
   for _, win in ipairs(vim.fn.win_findbuf(bufnr)) do
-- 
cgit 


From 8aab46da5e5bd8737d0d90ec10faa09cee5448c7 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Mon, 8 Jul 2024 10:46:16 +0200
Subject: vim-patch:94c1c66: runtime(tf): include tf ftplugin file

Adds ftplugin support for tf (TinyFugue). Comment support taken from
[here](https://github.com/kruton/tinyfugue/blob/1e8ac0bb014036c07bb3c679b0292ef20a6a0bb5/src/command.c#L568)

closes: vim/vim#15168

https://github.com/vim/vim/commit/94c1c6638a652cbe21b4d25ae5f26078e2e633d7

Co-authored-by: Riley Bruins 
---
 runtime/lua/vim/filetype/detect.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index e1891e299e..85c8d4c9dc 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -1597,7 +1597,7 @@ function M.tex(path, bufnr)
   end
 end
 
--- Determine if a *.tf file is TF mud client or terraform
+-- Determine if a *.tf file is TF (TinyFugue) mud client or terraform
 --- @type vim.filetype.mapfn
 function M.tf(_, bufnr)
   for _, line in ipairs(getlines(bufnr)) do
-- 
cgit 


From dc04ef2a20bf3457269e0c2aeb7dbfbb56c47012 Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Mon, 8 Jul 2024 19:20:32 +0300
Subject: perf(filetype): skip contents check in `match()` if there is no
 contents (#29596)

Problem: `vim.filetype.match()` tries to match on contents even if there
  is no contents (empty buffer or `{''}` explicit contents).
  This results in extra avoidable execution duration for cases.
  It matters, for example, when trying to match filetype based solely
  on file name (which still needs `contents` or `buf` to properly match
  earlier in the code path).

Solution: skip matching based solely on contents if it is `{''}`. This
  works because:
    - Matching solely on content is done after any user-configured
      `vim.filetype.add()` hooks.
    - All default matching on content might depend on supplied path
      *only* if there is non-empty content (like in
      `require('vim.filetype.detect').match_from_hashbang()`).
---
 runtime/lua/vim/filetype.lua | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 179a6312de..18fa1ed658 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -2598,20 +2598,24 @@ function M.match(args)
         contents = M._getlines(bufnr)
       end
     end
-    -- If name is nil, catch any errors from the contents filetype detection function.
-    -- If the function tries to use the filename that is nil then it will fail,
-    -- but this enables checks which do not need a filename to still work.
-    local ok
-    ok, ft, on_detect = pcall(
-      require('vim.filetype.detect').match_contents,
-      contents,
-      name,
-      function(ext)
-        return dispatch(extension[ext], name, bufnr)
+
+    -- Match based solely on content only if there is any content (for performance)
+    if not (#contents == 1 and contents[1] == '') then
+      -- If name is nil, catch any errors from the contents filetype detection function.
+      -- If the function tries to use the filename that is nil then it will fail,
+      -- but this enables checks which do not need a filename to still work.
+      local ok
+      ok, ft, on_detect = pcall(
+        require('vim.filetype.detect').match_contents,
+        contents,
+        name,
+        function(ext)
+          return dispatch(extension[ext], name, bufnr)
+        end
+      )
+      if ok then
+        return ft, on_detect
       end
-    )
-    if ok then
-      return ft, on_detect
     end
   end
 end
-- 
cgit 


From 487f44a6c14f83a4f80a4d03a4a8c16ad690927a Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 9 Jul 2024 19:17:50 +0800
Subject: fix(lua): change some vim.fn.expand() to vim.fs.normalize() (#29583)

Unlike vim.fn.expand(), vim.fs.normalize() doesn't expand wildcards.
---
 runtime/lua/vim/health/health.lua | 6 +++---
 runtime/lua/vim/ui.lua            | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/health/health.lua b/runtime/lua/vim/health/health.lua
index 235dacb82a..35b3ec17c4 100644
--- a/runtime/lua/vim/health/health.lua
+++ b/runtime/lua/vim/health/health.lua
@@ -50,11 +50,11 @@ local function check_config()
 
   local init_lua = vim.fn.stdpath('config') .. '/init.lua'
   local init_vim = vim.fn.stdpath('config') .. '/init.vim'
-  local vimrc = vim.env.MYVIMRC and vim.fn.expand(vim.env.MYVIMRC) or init_lua
+  local vimrc = vim.env.MYVIMRC and vim.fs.normalize(vim.env.MYVIMRC) or init_lua
 
   if vim.fn.filereadable(vimrc) == 0 and vim.fn.filereadable(init_vim) == 0 then
     ok = false
-    local has_vim = vim.fn.filereadable(vim.fn.expand('~/.vimrc')) == 1
+    local has_vim = vim.fn.filereadable(vim.fs.normalize('~/.vimrc')) == 1
     health.warn(
       ('%s user config file: %s'):format(
         -1 == vim.fn.getfsize(vimrc) and 'Missing' or 'Unreadable',
@@ -114,7 +114,7 @@ local function check_config()
   )
   shadafile = (
     vim.o.shadafile == ''
-      and (shadafile == '' and vim.fn.stdpath('state') .. '/shada/main.shada' or vim.fn.expand(
+      and (shadafile == '' and vim.fn.stdpath('state') .. '/shada/main.shada' or vim.fs.normalize(
         shadafile
       ))
     or (vim.o.shadafile == 'NONE' and '' or vim.o.shadafile)
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
index ec5c5c5ba0..79638a044a 100644
--- a/runtime/lua/vim/ui.lua
+++ b/runtime/lua/vim/ui.lua
@@ -136,7 +136,7 @@ function M.open(path)
   })
   local is_uri = path:match('%w+:')
   if not is_uri then
-    path = vim.fn.expand(path)
+    path = vim.fs.normalize(path)
   end
 
   local cmd --- @type string[]
-- 
cgit 


From d918ebe3b8a5ee2a7ad735e2edd474cc1224ea28 Mon Sep 17 00:00:00 2001
From: Max Coplan 
Date: Tue, 9 Jul 2024 12:08:12 -0700
Subject: fix(diagnostic): fix backwards compatibility for goto_next and
 goto_prev (#29593)

---
 runtime/lua/vim/diagnostic.lua | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index a4280506ab..db540c0dc1 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -1194,6 +1194,8 @@ end
 ---@deprecated
 function M.goto_prev(opts)
   vim.deprecate('vim.diagnostic.goto_prev()', 'vim.diagnostic.jump()', '0.13')
+  opts = opts or {}
+  opts.float = if_nil(opts.float, true)
   goto_diagnostic(M.get_prev(opts), opts)
 end
 
@@ -1339,6 +1341,8 @@ end
 ---@deprecated
 function M.goto_next(opts)
   vim.deprecate('vim.diagnostic.goto_next()', 'vim.diagnostic.jump()', '0.13')
+  opts = opts or {}
+  opts.float = if_nil(opts.float, true)
   goto_diagnostic(M.get_next(opts), opts)
 end
 
-- 
cgit 


From 545aafbeb80eb52c182ce139800489b392a12d0d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 10 Jul 2024 08:07:16 +0800
Subject: vim-patch:9.1.0547: No way to get the arity of a Vim function
 (#29638)

Problem:  No way to get the arity of a Vim function
          (Austin Ziegler)
Solution: Enhance get() Vim script function to return the function
          argument info using get(func, "arity") (LemonBoy)

fixes: vim/vim#15097
closes: vim/vim#15109

https://github.com/vim/vim/commit/48b7d05a4f88c4326bd5d7a73a523f2d953b3e51

Co-authored-by: LemonBoy 
---
 runtime/lua/vim/_meta/vimfn.lua | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 34a3addb57..d9bd683bbb 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -2523,12 +2523,25 @@ function vim.fn.get(blob, idx, default) end
 --- @return any
 function vim.fn.get(dict, key, default) end
 
---- Get item {what} from Funcref {func}.  Possible values for
+--- Get item {what} from |Funcref| {func}.  Possible values for
 --- {what} are:
----   "name"  The function name
----   "func"  The function
----   "dict"  The dictionary
----   "args"  The list with arguments
+---   "name"    The function name
+---   "func"    The function
+---   "dict"    The dictionary
+---   "args"    The list with arguments
+---   "arity"   A dictionary with information about the number of
+---       arguments accepted by the function (minus the
+---       {arglist}) with the following fields:
+---     required    the number of positional arguments
+---     optional    the number of optional arguments,
+---           in addition to the required ones
+---     varargs     |TRUE| if the function accepts a
+---           variable number of arguments |...|
+---
+---     Note: There is no error, if the {arglist} of
+---     the Funcref contains more arguments than the
+---     Funcref expects, it's not validated.
+---
 --- Returns zero on error.
 ---
 --- @param func function
-- 
cgit 


From 136c11ca22881ac64c074070c7fda501e89b6bea Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Tue, 9 Jul 2024 19:15:22 +0200
Subject: vim-patch:9.1.0550: filetype: antlr4 files are not recognized

Problem:  filetype: antlr4 files are not recognized
Solution: Detect '*.g4' as antlr4 filetype, include a simple antlr4
          syntax and filetype plugin (Yinzuo Jiang)

closes: vim/vim#15191

https://github.com/vim/vim/commit/4a7a4a3675b6ad90a525524ba4684925df212325

Co-authored-by: Yinzuo Jiang 
---
 runtime/lua/vim/filetype.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 18fa1ed658..83892ac290 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -190,6 +190,7 @@ local extension = {
   aidl = 'aidl',
   aml = 'aml',
   run = 'ampl',
+  g4 = 'antlr4',
   scpt = 'applescript',
   ino = 'arduino',
   pde = 'arduino',
-- 
cgit 


From 7fa089f463dac83f256a8336ddb0adc9eae483a2 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Tue, 9 Jul 2024 19:58:02 +0200
Subject: vim-patch:9.1.0551: filetype: htmlangular files are not properly
 detected

Problem:  filetype: htmlangular files are not properly detected
Solution: Use the new htmlangular filetype for angular files, because
          since angular v17, those are no longer valid HTML files.
          (Dennis van den Berg)

Since Angular 17, the new Control Flow Syntax is not valid HTML. This PR
adds a new filetype detection for the HTML templates of Angular.

It first checks the filename. The Angular convention is to use
*.component.html for the template. However, this is not mandatory.

If the filename does not match, it will check the contents of the file
if it contains:

  - One of the Control-Flow blocks: @if, @for, @switch, @defer
  - A structural directive: *ngIf, *ngFor, *ngSwitch, *ngTemplateOutlet
  - Builtin Angular elements: ng-template or ng-content
  - String interpolation: {{ something }}

This enables the Angular LSP to attach only to htmlangular filetypes, as
well as language parsers, such as tree-sitter.

closes: vim/vim#15190

https://github.com/vim/vim/commit/1ad194c0dfd82ca1e7a1b6f2fca89a487794158d

Co-authored-by: Dennis van den Berg 
---
 runtime/lua/vim/filetype/detect.lua | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 85c8d4c9dc..8a217a4ac2 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -710,9 +710,22 @@ function M.haredoc(path, _)
 end
 
 --- @type vim.filetype.mapfn
-function M.html(_, bufnr)
+function M.html(path, bufnr)
+  -- Test if the filename follows the Angular component template convention
+  local filename = fn.fnamemodify(path, ':t')
+  if filename:find('%.component%.html$') then
+    return 'htmlangular'
+  end
+
   for _, line in ipairs(getlines(bufnr, 1, 40)) do
-    if matchregex(line, [[\
Date: Tue, 9 Jul 2024 20:05:04 +0200
Subject: vim-patch:9.1.0553: filetype: *.mcmeta files are not recognized

Problem:  filetype: *.mcmeta files are not recognized
Solution: Detect '*.mcmeta' files as json filetype
          (Tomodachi94)

"pack.mcmeta" was added to the JSON tests because that is the most common
filename with that extension.

There are currently 34,000 instances of this file extension on GitHub:
https://github.com/search?q=path%3A*.mcmeta&type=code&p=2

.zip files with this extension have downloads in the millions on sites
like CurseForge:
https://www.curseforge.com/minecraft/search?page=1&pageSize=20&sortBy=relevancy&class=texture-packs

Further reading about the file extension:
https://minecraft.wiki/w/Tutorials/Creating_a_resource_pack#Creating_a_.MCMETA_file

closes: vim/vim#15189

https://github.com/vim/vim/commit/d33a518025765c4a3530ad6cfb6cab83a30c8f55

Co-authored-by: Tomodachi94 
---
 runtime/lua/vim/filetype.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 83892ac290..c866dc1de7 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -591,6 +591,7 @@ local extension = {
   json = 'json',
   jsonp = 'json',
   geojson = 'json',
+  mcmeta = 'json',
   webmanifest = 'json',
   ipynb = 'json',
   ['jupyterlab-settings'] = 'json',
-- 
cgit 


From afbe7736a4966f22146d857f246eac01cd080773 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Wed, 10 Jul 2024 19:47:28 +0200
Subject: vim-patch:9.1.0555: filetype: angular ft detection is still
 problematic

Problem:  filetype: angular ft detection is still problematic
          (after 9.1.0551)
Solution: detect htmlangular filetype only by inspecting the content,
          do not try to determine it from a generic name like
          '*.component.html'

For the reasons mentioned here:

https://github.com/vim/vim/pull/13594#issuecomment-1834465890

related: vim/vim#15190
related: vim/vim#13594
related: vim/vim#13604

https://github.com/vim/vim/commit/c03f631b7b01e672787b222a55898f8dcac8d859

Co-authored-by: Christian Brabandt 
---
 runtime/lua/vim/filetype/detect.lua | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 8a217a4ac2..95e55ebb21 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -710,12 +710,13 @@ function M.haredoc(path, _)
 end
 
 --- @type vim.filetype.mapfn
-function M.html(path, bufnr)
-  -- Test if the filename follows the Angular component template convention
-  local filename = fn.fnamemodify(path, ':t')
-  if filename:find('%.component%.html$') then
-    return 'htmlangular'
-  end
+function M.html(_, bufnr)
+  -- Disabled for the reasons mentioned here:
+  -- https://github.com/vim/vim/pull/13594#issuecomment-1834465890
+  -- local filename = fn.fnamemodify(path, ':t')
+  -- if filename:find('%.component%.html$') then
+  --   return 'htmlangular'
+  -- end
 
   for _, line in ipairs(getlines(bufnr, 1, 40)) do
     if
-- 
cgit 


From 83f42aa450582594f0be044c9f0710809ef0f93d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 12 Jul 2024 07:11:54 +0800
Subject: vim-patch:9.1.0568: Cannot expand paths from 'cdpath' setting

Problem:  Cannot expand paths from 'cdpath' setting
          (Daniel Hahler)
Solution: Implement 'cdpath' completion, add the new 'dir_in_path'
          completion type (LemonBoy)

fixes vim/vim#374
closes: vim/vim#15205

https://github.com/vim/vim/commit/a20bf69a3b32024cb7809be87af33bf9dc490a19

Co-authored-by: LemonBoy 
---
 runtime/lua/vim/_meta/vimfn.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index d9bd683bbb..b18ca1ecf8 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -2942,6 +2942,7 @@ function vim.fn.getcmdwintype() end
 --- customlist,{func} custom completion, defined via {func}
 --- diff_buffer  |:diffget| and |:diffput| completion
 --- dir    directory names
+--- dir_in_path  directory names in |'cdpath'|
 --- environment  environment variable names
 --- event    autocommand events
 --- expression  Vim expression
-- 
cgit 


From c7e8fc6302dc1bb6277319be05350bc5308f3841 Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Tue, 9 Jul 2024 15:00:33 +0300
Subject: refactor(filetype): unify matching patterns with pos/neg priority

Problem: due to single list of sorted patterns, their matching inside
  `vim.filetype.match()` was done very similarly but with extra checks
  to stop processing negative priority patterns before extensions.

Solution: create separated sorted lists for patterns with non-negative
  and negative priorities. This allows to process them in a single
  extracted function making the main codeflow a bit nicer and more
  easily expandable.
---
 runtime/lua/vim/filetype.lua | 80 ++++++++++++++++++++++++--------------------
 1 file changed, 43 insertions(+), 37 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index c866dc1de7..fc7e0b5094 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -2218,10 +2218,18 @@ local pattern = {
 -- luacheck: pop
 -- luacheck: pop
 
+local function compare_by_priority(a, b)
+  return a[next(a)][2].priority > b[next(b)][2].priority
+end
+
 --- @param t vim.filetype.mapping
 --- @return vim.filetype.mapping[]
+--- @return vim.filetype.mapping[]
 local function sort_by_priority(t)
-  local sorted = {} --- @type vim.filetype.mapping[]
+  -- Separate patterns with non-negative and negative priority because they
+  -- will be processed separately
+  local pos = {} --- @type vim.filetype.mapping[]
+  local neg = {} --- @type vim.filetype.mapping[]
   for k, v in pairs(t) do
     local ft = type(v) == 'table' and v[1] or v
     assert(
@@ -2233,15 +2241,16 @@ local function sort_by_priority(t)
     if not opts.priority then
       opts.priority = 0
     end
-    table.insert(sorted, { [k] = { ft, opts } })
+
+    table.insert(opts.priority >= 0 and pos or neg, { [k] = { ft, opts } })
   end
-  table.sort(sorted, function(a, b)
-    return a[next(a)][2].priority > b[next(b)][2].priority
-  end)
-  return sorted
+
+  table.sort(pos, compare_by_priority)
+  table.sort(neg, compare_by_priority)
+  return pos, neg
 end
 
-local pattern_sorted = sort_by_priority(pattern)
+local pattern_sorted_pos, pattern_sorted_neg = sort_by_priority(pattern)
 
 --- @param path string
 --- @param as_pattern? true
@@ -2365,7 +2374,9 @@ function M.add(filetypes)
   end
 
   if filetypes.pattern then
-    pattern_sorted = sort_by_priority(pattern)
+    -- TODO: full resorting might be expensive with a lot of separate `vim.filetype.add()` calls.
+    -- Consider inserting new patterns precisely into already sorted lists of built-in patterns.
+    pattern_sorted_pos, pattern_sorted_neg = sort_by_priority(pattern)
   end
 end
 
@@ -2451,6 +2462,24 @@ local function match_pattern(name, path, tail, pat)
   return (tail:match(fullpat))
 end
 
+--- @param name string
+--- @param path string
+--- @param tail string
+--- @param pattern_sorted vim.filetype.mapping[]
+--- @param bufnr integer?
+local function match_pattern_sorted(name, path, tail, pattern_sorted, bufnr)
+  for i = 1, #pattern_sorted do
+    local pat, ft_data = next(pattern_sorted[i])
+    local matches = match_pattern(name, path, tail, pat)
+    if matches then
+      local ft, on_detect = dispatch(ft_data[1], path, bufnr, matches)
+      if ft then
+        return ft, on_detect
+      end
+    end
+  end
+end
+
 --- @class vim.filetype.match.args
 --- @inlinedoc
 ---
@@ -2544,23 +2573,9 @@ function M.match(args)
     end
 
     -- Next, check the file path against available patterns with non-negative priority
-    local j = 1
-    for i, v in ipairs(pattern_sorted) do
-      local k = next(v)
-      local opts = v[k][2]
-      if opts.priority < 0 then
-        j = i
-        break
-      end
-
-      local filetype = v[k][1]
-      local matches = match_pattern(name, path, tail, k)
-      if matches then
-        ft, on_detect = dispatch(filetype, path, bufnr, matches)
-        if ft then
-          return ft, on_detect
-        end
-      end
+    ft, on_detect = match_pattern_sorted(name, path, tail, pattern_sorted_pos, bufnr)
+    if ft then
+      return ft, on_detect
     end
 
     -- Next, check file extension
@@ -2573,18 +2588,9 @@ function M.match(args)
     end
 
     -- Next, check patterns with negative priority
-    for i = j, #pattern_sorted do
-      local v = pattern_sorted[i]
-      local k = next(v)
-
-      local filetype = v[k][1]
-      local matches = match_pattern(name, path, tail, k)
-      if matches then
-        ft, on_detect = dispatch(filetype, path, bufnr, matches)
-        if ft then
-          return ft, on_detect
-        end
-      end
+    ft, on_detect = match_pattern_sorted(name, path, tail, pattern_sorted_neg, bufnr)
+    if ft then
+      return ft, on_detect
     end
   end
 
-- 
cgit 


From abf4b65a51b2e96191782adf68bd967f8073f018 Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Tue, 9 Jul 2024 15:30:24 +0300
Subject: perf(filetype): cache (more) pattern data during "add" time

---
 runtime/lua/vim/filetype.lua | 45 ++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index fc7e0b5094..236c67790f 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -2218,6 +2218,11 @@ local pattern = {
 -- luacheck: pop
 -- luacheck: pop
 
+--- Lookup table/cache for patterns
+--- @alias vim.filetype.pattern_cache { fullpat: string, has_env: boolean, has_slash: boolean }
+--- @type table
+local pattern_lookup = {}
+
 local function compare_by_priority(a, b)
   return a[next(a)][2].priority > b[next(b)][2].priority
 end
@@ -2230,19 +2235,24 @@ local function sort_by_priority(t)
   -- will be processed separately
   local pos = {} --- @type vim.filetype.mapping[]
   local neg = {} --- @type vim.filetype.mapping[]
-  for k, v in pairs(t) do
-    local ft = type(v) == 'table' and v[1] or v
+  for pat, maptbl in pairs(t) do
+    local ft = type(maptbl) == 'table' and maptbl[1] or maptbl
     assert(
       type(ft) == 'string' or type(ft) == 'function',
       'Expected string or function for filetype'
     )
 
-    local opts = (type(v) == 'table' and type(v[2]) == 'table') and v[2] or {}
-    if not opts.priority then
-      opts.priority = 0
-    end
+    -- Parse pattern for common data and cache it once
+    pattern_lookup[pat] = pattern_lookup[pat] or {
+      fullpat = '^' .. pat .. '$',
+      has_env = pat:find('%$%b{}') ~= nil,
+      has_slash = pat:find('/') ~= nil,
+    }
 
-    table.insert(opts.priority >= 0 and pos or neg, { [k] = { ft, opts } })
+    local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or {}
+    opts.priority = opts.priority or 0
+
+    table.insert(opts.priority >= 0 and pos or neg, { [pat] = { ft, opts } })
   end
 
   table.sort(pos, compare_by_priority)
@@ -2420,23 +2430,19 @@ local function dispatch(ft, path, bufnr, ...)
   return ft0, on_detect
 end
 
---- Lookup table/cache for patterns that contain an environment variable pattern, e.g. ${SOME_VAR}.
---- @type table
-local expand_env_lookup = {}
-
 --- @param name string
 --- @param path string
 --- @param tail string
 --- @param pat string
---- @return string|false?
+--- @return string|boolean?
 local function match_pattern(name, path, tail, pat)
-  if expand_env_lookup[pat] == nil then
-    expand_env_lookup[pat] = pat:find('%${') ~= nil
-  end
-  if expand_env_lookup[pat] then
+  local pat_cache = pattern_lookup[pat]
+  local fullpat, has_slash = pat_cache.fullpat, pat_cache.has_slash
+
+  if pat_cache.has_env then
     local return_early --- @type true?
     --- @type string
-    pat = pat:gsub('%${(%S-)}', function(env)
+    fullpat = fullpat:gsub('%${(%S-)}', function(env)
       -- If an environment variable is present in the pattern but not set, there is no match
       if not vim.env[env] then
         return_early = true
@@ -2447,12 +2453,11 @@ local function match_pattern(name, path, tail, pat)
     if return_early then
       return false
     end
+    has_slash = fullpat:find('/') ~= nil
   end
 
   -- If the pattern contains a / match against the full path, otherwise just the tail
-  local fullpat = '^' .. pat .. '$'
-
-  if pat:find('/') then
+  if has_slash then
     -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against
     -- both the short file name (as typed) and the full file name (after expanding to full path
     -- and resolving symlinks)
-- 
cgit 


From 9d14b76089dfafbc663b0cfa0b185c484d0f1ed3 Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Fri, 12 Jul 2024 15:41:19 +0300
Subject: refactor(filetype): extract expanding env. vars in separate function

---
 runtime/lua/vim/filetype.lua | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 236c67790f..5e34bac728 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -2430,6 +2430,19 @@ local function dispatch(ft, path, bufnr, ...)
   return ft0, on_detect
 end
 
+--- @param pat string
+--- @return boolean
+--- @return string
+local function expand_envvar_pattern(pat)
+  local some_env_missing = false
+  local expanded = pat:gsub('%${(%S-)}', function(env)
+    local val = vim.env[env] --- @type string?
+    some_env_missing = some_env_missing or val == nil
+    return vim.pesc(val or '')
+  end)
+  return some_env_missing, expanded
+end
+
 --- @param name string
 --- @param path string
 --- @param tail string
@@ -2440,20 +2453,12 @@ local function match_pattern(name, path, tail, pat)
   local fullpat, has_slash = pat_cache.fullpat, pat_cache.has_slash
 
   if pat_cache.has_env then
-    local return_early --- @type true?
-    --- @type string
-    fullpat = fullpat:gsub('%${(%S-)}', function(env)
-      -- If an environment variable is present in the pattern but not set, there is no match
-      if not vim.env[env] then
-        return_early = true
-        return nil
-      end
-      return vim.pesc(vim.env[env])
-    end)
-    if return_early then
+    local some_env_missing, expanded = expand_envvar_pattern(fullpat)
+    -- If any environment variable is present in the pattern but not set, there is no match
+    if some_env_missing then
       return false
     end
-    has_slash = fullpat:find('/') ~= nil
+    fullpat, has_slash = expanded, expanded:find('/') ~= nil
   end
 
   -- If the pattern contains a / match against the full path, otherwise just the tail
-- 
cgit 


From 708b5f86ba6513050da0af72e1b6e07386c0acdb Mon Sep 17 00:00:00 2001
From: Evgeni Chasnovski 
Date: Fri, 12 Jul 2024 15:53:57 +0300
Subject: refactor(filetype): use Lua patterns without implicit anchoring

---
 runtime/lua/vim/filetype.lua | 921 ++++++++++++++++++++++---------------------
 1 file changed, 461 insertions(+), 460 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 5e34bac728..f0e1af4f04 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1730,484 +1730,487 @@ local detect_apache = starsetf('apache')
 local detect_muttrc = starsetf('muttrc')
 local detect_neomuttrc = starsetf('neomuttrc')
 
+--- Vim regexes are converted into explicit Lua patterns (without implicit anchoring):
+--- '*/debian/changelog' -> '/debian/changelog$'
+--- '*/bind/db.*' -> '/bind/db%.'
 --- @type vim.filetype.mapping
 local pattern = {
   -- BEGIN PATTERN
-  ['.*/etc/a2ps/.*%.cfg'] = 'a2ps',
-  ['.*/etc/a2ps%.cfg'] = 'a2ps',
-  ['.*/usr/share/alsa/alsa%.conf'] = 'alsaconf',
-  ['.*/etc/asound%.conf'] = 'alsaconf',
-  ['.*/etc/apache2/sites%-.*/.*%.com'] = 'apache',
-  ['.*/etc/httpd/.*%.conf'] = 'apache',
-  ['.*/etc/apache2/.*%.conf.*'] = detect_apache,
-  ['.*/etc/apache2/conf%..*/.*'] = detect_apache,
-  ['.*/etc/apache2/mods%-.*/.*'] = detect_apache,
-  ['.*/etc/apache2/sites%-.*/.*'] = detect_apache,
-  ['access%.conf.*'] = detect_apache,
-  ['apache%.conf.*'] = detect_apache,
-  ['apache2%.conf.*'] = detect_apache,
-  ['httpd%.conf.*'] = detect_apache,
-  ['srm%.conf.*'] = detect_apache,
-  ['.*/etc/httpd/conf%..*/.*'] = detect_apache,
-  ['.*/etc/httpd/conf%.d/.*%.conf.*'] = detect_apache,
-  ['.*/etc/httpd/mods%-.*/.*'] = detect_apache,
-  ['.*/etc/httpd/sites%-.*/.*'] = detect_apache,
-  ['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'),
-  ['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'),
-  ['proftpd%.conf.*'] = starsetf('apachestyle'),
-  ['.*asterisk/.*%.conf.*'] = starsetf('asterisk'),
-  ['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'),
-  ['.*/%.aptitude/config'] = 'aptconf',
-  ['[mM]akefile%.am'] = 'automake',
-  ['.*/bind/db%..*'] = starsetf('bindzone'),
-  ['.*/named/db%..*'] = starsetf('bindzone'),
-  ['.*/build/conf/.*%.conf'] = 'bitbake',
-  ['.*/meta/conf/.*%.conf'] = 'bitbake',
-  ['.*/meta%-.*/conf/.*%.conf'] = 'bitbake',
-  ['.*%.blade%.php'] = 'blade',
-  ['bzr_log%..*'] = 'bzr',
-  ['.*enlightenment/.*%.cfg'] = 'c',
-  ['.*/%.cabal/config'] = 'cabalconfig',
-  ['.*/cabal/config'] = 'cabalconfig',
-  ['cabal%.project%..*'] = starsetf('cabalproject'),
-  ['.*/%.calendar/.*'] = starsetf('calendar'),
-  ['.*/share/calendar/.*/calendar%..*'] = starsetf('calendar'),
-  ['.*/share/calendar/calendar%..*'] = starsetf('calendar'),
-  ['sgml%.catalog.*'] = starsetf('catalog'),
-  ['.*/etc/defaults/cdrdao'] = 'cdrdaoconf',
-  ['.*/etc/cdrdao%.conf'] = 'cdrdaoconf',
-  ['.*/etc/default/cdrdao'] = 'cdrdaoconf',
-  ['.*hgrc'] = 'cfg',
-  ['.*%.[Cc][Ff][Gg]'] = {
+  ['/etc/a2ps/.*%.cfg$'] = 'a2ps',
+  ['/etc/a2ps%.cfg$'] = 'a2ps',
+  ['/usr/share/alsa/alsa%.conf$'] = 'alsaconf',
+  ['/etc/asound%.conf$'] = 'alsaconf',
+  ['/etc/apache2/sites%-.*/.*%.com$'] = 'apache',
+  ['/etc/httpd/.*%.conf$'] = 'apache',
+  ['/etc/apache2/.*%.conf'] = detect_apache,
+  ['/etc/apache2/conf%..*/'] = detect_apache,
+  ['/etc/apache2/mods%-.*/'] = detect_apache,
+  ['/etc/apache2/sites%-.*/'] = detect_apache,
+  ['^access%.conf'] = detect_apache,
+  ['^apache%.conf'] = detect_apache,
+  ['^apache2%.conf'] = detect_apache,
+  ['^httpd%.conf'] = detect_apache,
+  ['^srm%.conf'] = detect_apache,
+  ['/etc/httpd/conf%..*/'] = detect_apache,
+  ['/etc/httpd/conf%.d/.*%.conf'] = detect_apache,
+  ['/etc/httpd/mods%-.*/'] = detect_apache,
+  ['/etc/httpd/sites%-.*/'] = detect_apache,
+  ['/etc/proftpd/.*%.conf'] = starsetf('apachestyle'),
+  ['/etc/proftpd/conf%..*/'] = starsetf('apachestyle'),
+  ['^proftpd%.conf'] = starsetf('apachestyle'),
+  ['asterisk/.*%.conf'] = starsetf('asterisk'),
+  ['asterisk.*/.*voicemail%.conf'] = starsetf('asteriskvm'),
+  ['/%.aptitude/config$'] = 'aptconf',
+  ['^[mM]akefile%.am$'] = 'automake',
+  ['/bind/db%.'] = starsetf('bindzone'),
+  ['/named/db%.'] = starsetf('bindzone'),
+  ['/build/conf/.*%.conf$'] = 'bitbake',
+  ['/meta/conf/.*%.conf$'] = 'bitbake',
+  ['/meta%-.*/conf/.*%.conf$'] = 'bitbake',
+  ['%.blade%.php$'] = 'blade',
+  ['^bzr_log%.'] = 'bzr',
+  ['enlightenment/.*%.cfg$'] = 'c',
+  ['/%.cabal/config$'] = 'cabalconfig',
+  ['/cabal/config$'] = 'cabalconfig',
+  ['^cabal%.project%.'] = starsetf('cabalproject'),
+  ['/%.calendar/'] = starsetf('calendar'),
+  ['/share/calendar/.*/calendar%.'] = starsetf('calendar'),
+  ['/share/calendar/calendar%.'] = starsetf('calendar'),
+  ['^sgml%.catalog'] = starsetf('catalog'),
+  ['/etc/defaults/cdrdao$'] = 'cdrdaoconf',
+  ['/etc/cdrdao%.conf$'] = 'cdrdaoconf',
+  ['/etc/default/cdrdao$'] = 'cdrdaoconf',
+  ['hgrc$'] = 'cfg',
+  ['%.[Cc][Ff][Gg]$'] = {
     detect.cfg,
     -- Decrease priority to avoid conflicts with more specific patterns
     -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc.
     { priority = -1 },
   },
-  ['[cC]hange[lL]og.*'] = starsetf(detect.changelog),
-  ['.*%.%.ch'] = 'chill',
-  ['.*/etc/translate%-shell'] = 'clojure',
-  ['.*%.cmake%.in'] = 'cmake',
+  ['^[cC]hange[lL]og'] = starsetf(detect.changelog),
+  ['%.%.ch$'] = 'chill',
+  ['/etc/translate%-shell$'] = 'clojure',
+  ['%.cmake%.in$'] = 'cmake',
   -- */cmus/rc and */.cmus/rc
-  ['.*/%.?cmus/rc'] = 'cmusrc',
+  ['/%.?cmus/rc$'] = 'cmusrc',
   -- */cmus/*.theme and */.cmus/*.theme
-  ['.*/%.?cmus/.*%.theme'] = 'cmusrc',
-  ['.*/%.cmus/autosave'] = 'cmusrc',
-  ['.*/%.cmus/command%-history'] = 'cmusrc',
-  ['.*/etc/hostname%..*'] = starsetf('config'),
-  ['crontab%..*'] = starsetf('crontab'),
-  ['.*/etc/cron%.d/.*'] = starsetf('crontab'),
-  ['%.cshrc.*'] = detect.csh,
-  ['%.login.*'] = detect.csh,
-  ['cvs%d+'] = 'cvs',
-  ['.*%.[Dd][Aa][Tt]'] = detect.dat,
-  ['.*/debian/patches/.*'] = detect.dep3patch,
-  ['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'),
-  ['Containerfile%..*'] = starsetf('dockerfile'),
-  ['Dockerfile%..*'] = starsetf('dockerfile'),
-  ['.*/etc/yum%.repos%.d/.*'] = starsetf('dosini'),
-  ['drac%..*'] = starsetf('dracula'),
-  ['.*/debian/changelog'] = 'debchangelog',
-  ['.*/debian/control'] = 'debcontrol',
-  ['.*/debian/copyright'] = 'debcopyright',
-  ['.*/etc/apt/sources%.list%.d/.*%.list'] = 'debsources',
-  ['.*/etc/apt/sources%.list'] = 'debsources',
-  ['.*/etc/apt/sources%.list%.d/.*%.sources'] = 'deb822sources',
-  ['dictd.*%.conf'] = 'dictdconf',
-  ['.*/etc/DIR_COLORS'] = 'dircolors',
-  ['.*/etc/dnsmasq%.conf'] = 'dnsmasq',
-  ['php%.ini%-.*'] = 'dosini',
-  ['.*/%.aws/config'] = 'confini',
-  ['.*/%.aws/credentials'] = 'confini',
-  ['.*/etc/yum%.conf'] = 'dosini',
-  ['.*/lxqt/.*%.conf'] = 'dosini',
-  ['.*/screengrab/.*%.conf'] = 'dosini',
-  ['.*/bpython/config'] = 'dosini',
-  ['.*/mypy/config'] = 'dosini',
-  ['.*/flatpak/repo/config'] = 'dosini',
-  ['.*lvs'] = 'dracula',
-  ['.*lpe'] = 'dracula',
-  ['.*/dtrace/.*%.d'] = 'dtrace',
-  ['.*esmtprc'] = 'esmtprc',
-  ['.*Eterm/.*%.cfg'] = 'eterm',
-  ['.*s6.*/up'] = 'execline',
-  ['.*s6.*/down'] = 'execline',
-  ['.*s6.*/run'] = 'execline',
-  ['.*s6.*/finish'] = 'execline',
-  ['s6%-.*'] = 'execline',
-  ['[a-zA-Z0-9].*Dict'] = detect.foam,
-  ['[a-zA-Z0-9].*Dict%..*'] = detect.foam,
-  ['[a-zA-Z].*Properties'] = detect.foam,
-  ['[a-zA-Z].*Properties%..*'] = detect.foam,
-  ['.*Transport%..*'] = detect.foam,
-  ['.*/constant/g'] = detect.foam,
-  ['.*/0/.*'] = detect.foam,
-  ['.*/0%.orig/.*'] = detect.foam,
-  ['.*/%.fvwm/.*'] = starsetf('fvwm'),
-  ['.*fvwmrc.*'] = starsetf(detect.fvwm_v1),
-  ['.*fvwm95.*%.hook'] = starsetf(detect.fvwm_v1),
-  ['.*fvwm2rc.*'] = starsetf(detect.fvwm_v2),
-  ['.*/tmp/lltmp.*'] = starsetf('gedcom'),
-  ['.*/etc/gitconfig%.d/.*'] = starsetf('gitconfig'),
-  ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'),
-  ['tmac%..*'] = starsetf('nroff'),
-  ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'),
-  ['.*%.git/.*'] = {
+  ['/%.?cmus/.*%.theme$'] = 'cmusrc',
+  ['/%.cmus/autosave$'] = 'cmusrc',
+  ['/%.cmus/command%-history$'] = 'cmusrc',
+  ['/etc/hostname%.'] = starsetf('config'),
+  ['^crontab%.'] = starsetf('crontab'),
+  ['/etc/cron%.d/'] = starsetf('crontab'),
+  ['^%.cshrc'] = detect.csh,
+  ['^%.login'] = detect.csh,
+  ['^cvs%d+$'] = 'cvs',
+  ['%.[Dd][Aa][Tt]$'] = detect.dat,
+  ['/debian/patches/'] = detect.dep3patch,
+  ['/etc/dnsmasq%.d/'] = starsetf('dnsmasq'),
+  ['^Containerfile%.'] = starsetf('dockerfile'),
+  ['^Dockerfile%.'] = starsetf('dockerfile'),
+  ['/etc/yum%.repos%.d/'] = starsetf('dosini'),
+  ['^drac%.'] = starsetf('dracula'),
+  ['/debian/changelog$'] = 'debchangelog',
+  ['/debian/control$'] = 'debcontrol',
+  ['/debian/copyright$'] = 'debcopyright',
+  ['/etc/apt/sources%.list%.d/.*%.list$'] = 'debsources',
+  ['/etc/apt/sources%.list$'] = 'debsources',
+  ['/etc/apt/sources%.list%.d/.*%.sources$'] = 'deb822sources',
+  ['^dictd.*%.conf$'] = 'dictdconf',
+  ['/etc/DIR_COLORS$'] = 'dircolors',
+  ['/etc/dnsmasq%.conf$'] = 'dnsmasq',
+  ['^php%.ini%-'] = 'dosini',
+  ['/%.aws/config$'] = 'confini',
+  ['/%.aws/credentials$'] = 'confini',
+  ['/etc/yum%.conf$'] = 'dosini',
+  ['/lxqt/.*%.conf$'] = 'dosini',
+  ['/screengrab/.*%.conf$'] = 'dosini',
+  ['/bpython/config$'] = 'dosini',
+  ['/mypy/config$'] = 'dosini',
+  ['/flatpak/repo/config$'] = 'dosini',
+  ['lvs$'] = 'dracula',
+  ['lpe$'] = 'dracula',
+  ['/dtrace/.*%.d$'] = 'dtrace',
+  ['esmtprc$'] = 'esmtprc',
+  ['Eterm/.*%.cfg$'] = 'eterm',
+  ['s6.*/up$'] = 'execline',
+  ['s6.*/down$'] = 'execline',
+  ['s6.*/run$'] = 'execline',
+  ['s6.*/finish$'] = 'execline',
+  ['^s6%-'] = 'execline',
+  ['^[a-zA-Z0-9].*Dict$'] = detect.foam,
+  ['^[a-zA-Z0-9].*Dict%.'] = detect.foam,
+  ['^[a-zA-Z].*Properties$'] = detect.foam,
+  ['^[a-zA-Z].*Properties%.'] = detect.foam,
+  ['Transport%.'] = detect.foam,
+  ['/constant/g$'] = detect.foam,
+  ['/0/'] = detect.foam,
+  ['/0%.orig/'] = detect.foam,
+  ['/%.fvwm/'] = starsetf('fvwm'),
+  ['fvwmrc'] = starsetf(detect.fvwm_v1),
+  ['fvwm95.*%.hook$'] = starsetf(detect.fvwm_v1),
+  ['fvwm2rc'] = starsetf(detect.fvwm_v2),
+  ['/tmp/lltmp'] = starsetf('gedcom'),
+  ['/etc/gitconfig%.d/'] = starsetf('gitconfig'),
+  ['/gitolite%-admin/conf/'] = starsetf('gitolite'),
+  ['^tmac%.'] = starsetf('nroff'),
+  ['/%.gitconfig%.d/'] = starsetf('gitconfig'),
+  ['%.git/'] = {
     detect.git,
     -- Decrease priority to run after simple pattern checks
     { priority = -1 },
   },
-  ['.*%.git/modules/.*/config'] = 'gitconfig',
-  ['.*%.git/modules/config'] = 'gitconfig',
-  ['.*%.git/config'] = 'gitconfig',
-  ['.*/etc/gitconfig'] = 'gitconfig',
-  ['.*/%.config/git/config'] = 'gitconfig',
-  ['.*%.git/config%.worktree'] = 'gitconfig',
-  ['.*%.git/worktrees/.*/config%.worktree'] = 'gitconfig',
-  ['${XDG_CONFIG_HOME}/git/config'] = 'gitconfig',
-  ['.*%.git/info/attributes'] = 'gitattributes',
-  ['.*/etc/gitattributes'] = 'gitattributes',
-  ['.*/%.config/git/attributes'] = 'gitattributes',
-  ['${XDG_CONFIG_HOME}/git/attributes'] = 'gitattributes',
-  ['.*%.git/info/exclude'] = 'gitignore',
-  ['.*/%.config/git/ignore'] = 'gitignore',
-  ['${XDG_CONFIG_HOME}/git/ignore'] = 'gitignore',
-  ['%.gitsendemail%.msg%.......'] = 'gitsendemail',
-  ['gkrellmrc_.'] = 'gkrellmrc',
-  ['.*/usr/.*/gnupg/options%.skel'] = 'gpg',
-  ['.*/%.gnupg/options'] = 'gpg',
-  ['.*/%.gnupg/gpg%.conf'] = 'gpg',
-  ['${GNUPGHOME}/options'] = 'gpg',
-  ['${GNUPGHOME}/gpg%.conf'] = 'gpg',
-  ['.*/etc/group'] = 'group',
-  ['.*/etc/gshadow'] = 'group',
-  ['.*/etc/group%.edit'] = 'group',
-  ['.*/var/backups/gshadow%.bak'] = 'group',
-  ['.*/etc/group%-'] = 'group',
-  ['.*/etc/gshadow%-'] = 'group',
-  ['.*/var/backups/group%.bak'] = 'group',
-  ['.*/etc/gshadow%.edit'] = 'group',
-  ['.*/boot/grub/grub%.conf'] = 'grub',
-  ['.*/boot/grub/menu%.lst'] = 'grub',
-  ['.*/etc/grub%.conf'] = 'grub',
+  ['%.git/modules/.*/config$'] = 'gitconfig',
+  ['%.git/modules/config$'] = 'gitconfig',
+  ['%.git/config$'] = 'gitconfig',
+  ['/etc/gitconfig$'] = 'gitconfig',
+  ['/%.config/git/config$'] = 'gitconfig',
+  ['%.git/config%.worktree$'] = 'gitconfig',
+  ['%.git/worktrees/.*/config%.worktree$'] = 'gitconfig',
+  ['^${XDG_CONFIG_HOME}/git/config$'] = 'gitconfig',
+  ['%.git/info/attributes$'] = 'gitattributes',
+  ['/etc/gitattributes$'] = 'gitattributes',
+  ['/%.config/git/attributes$'] = 'gitattributes',
+  ['^${XDG_CONFIG_HOME}/git/attributes$'] = 'gitattributes',
+  ['%.git/info/exclude$'] = 'gitignore',
+  ['/%.config/git/ignore$'] = 'gitignore',
+  ['^${XDG_CONFIG_HOME}/git/ignore$'] = 'gitignore',
+  ['^%.gitsendemail%.msg%.......$'] = 'gitsendemail',
+  ['^gkrellmrc_.$'] = 'gkrellmrc',
+  ['/usr/.*/gnupg/options%.skel$'] = 'gpg',
+  ['/%.gnupg/options$'] = 'gpg',
+  ['/%.gnupg/gpg%.conf$'] = 'gpg',
+  ['^${GNUPGHOME}/options$'] = 'gpg',
+  ['^${GNUPGHOME}/gpg%.conf$'] = 'gpg',
+  ['/etc/group$'] = 'group',
+  ['/etc/gshadow$'] = 'group',
+  ['/etc/group%.edit$'] = 'group',
+  ['/var/backups/gshadow%.bak$'] = 'group',
+  ['/etc/group%-$'] = 'group',
+  ['/etc/gshadow%-$'] = 'group',
+  ['/var/backups/group%.bak$'] = 'group',
+  ['/etc/gshadow%.edit$'] = 'group',
+  ['/boot/grub/grub%.conf$'] = 'grub',
+  ['/boot/grub/menu%.lst$'] = 'grub',
+  ['/etc/grub%.conf$'] = 'grub',
   -- gtkrc* and .gtkrc*
-  ['%.?gtkrc.*'] = starsetf('gtkrc'),
-  ['${VIMRUNTIME}/doc/.*%.txt'] = 'help',
-  ['hg%-editor%-.*%.txt'] = 'hgcommit',
-  ['.*/etc/host%.conf'] = 'hostconf',
-  ['.*/etc/hosts%.deny'] = 'hostsaccess',
-  ['.*/etc/hosts%.allow'] = 'hostsaccess',
-  ['.*%.html%.m4'] = 'htmlm4',
-  ['.*/%.i3/config'] = 'i3config',
-  ['.*/i3/config'] = 'i3config',
-  ['.*/%.icewm/menu'] = 'icemenu',
-  ['.*/etc/initng/.*/.*%.i'] = 'initng',
-  ['JAM.*%..*'] = starsetf('jam'),
-  ['Prl.*%..*'] = starsetf('jam'),
-  ['.*%.properties_..'] = 'jproperties',
-  ['.*%.properties_.._..'] = 'jproperties',
-  ['org%.eclipse%..*%.prefs'] = 'jproperties',
-  ['.*%.properties_.._.._.*'] = starsetf('jproperties'),
-  ['[jt]sconfig.*%.json'] = 'jsonc',
-  ['[jJ]ustfile'] = 'just',
-  ['Kconfig%..*'] = starsetf('kconfig'),
-  ['Config%.in%..*'] = starsetf('kconfig'),
-  ['.*%.[Ss][Uu][Bb]'] = 'krl',
-  ['lilo%.conf.*'] = starsetf('lilo'),
-  ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'),
-  ['.*/ldscripts/.*'] = 'ld',
-  ['.*lftp/rc'] = 'lftp',
-  ['.*/%.libao'] = 'libao',
-  ['.*/etc/libao%.conf'] = 'libao',
-  ['.*/etc/.*limits%.conf'] = 'limits',
-  ['.*/etc/limits'] = 'limits',
-  ['.*/etc/.*limits%.d/.*%.conf'] = 'limits',
-  ['.*/supertux2/config'] = 'lisp',
-  ['.*/LiteStep/.*/.*%.rc'] = 'litestep',
-  ['.*/etc/login%.access'] = 'loginaccess',
-  ['.*/etc/login%.defs'] = 'logindefs',
-  ['%.letter%.%d+'] = 'mail',
-  ['%.article%.%d+'] = 'mail',
-  ['/tmp/SLRN[0-9A-Z.]+'] = 'mail',
-  ['ae%d+%.txt'] = 'mail',
-  ['pico%.%d+'] = 'mail',
-  ['mutt%-.*%-%w+'] = 'mail',
-  ['muttng%-.*%-%w+'] = 'mail',
-  ['neomutt%-.*%-%w+'] = 'mail',
-  ['mutt' .. string.rep('[%w_-]', 6)] = 'mail',
-  ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail',
-  ['snd%.%d+'] = 'mail',
-  ['reportbug%-.*'] = starsetf('mail'),
-  ['.*/etc/mail/aliases'] = 'mailaliases',
-  ['.*/etc/aliases'] = 'mailaliases',
-  ['.*[mM]akefile'] = 'make',
-  ['[mM]akefile.*'] = starsetf('make'),
-  ['.*/etc/man%.conf'] = 'manconf',
-  ['.*/log/auth'] = 'messages',
-  ['.*/log/cron'] = 'messages',
-  ['.*/log/daemon'] = 'messages',
-  ['.*/log/debug'] = 'messages',
-  ['.*/log/kern'] = 'messages',
-  ['.*/log/lpr'] = 'messages',
-  ['.*/log/mail'] = 'messages',
-  ['.*/log/messages'] = 'messages',
-  ['.*/log/news/news'] = 'messages',
-  ['.*/log/syslog'] = 'messages',
-  ['.*/log/user'] = 'messages',
-  ['.*/log/auth%.log'] = 'messages',
-  ['.*/log/cron%.log'] = 'messages',
-  ['.*/log/daemon%.log'] = 'messages',
-  ['.*/log/debug%.log'] = 'messages',
-  ['.*/log/kern%.log'] = 'messages',
-  ['.*/log/lpr%.log'] = 'messages',
-  ['.*/log/mail%.log'] = 'messages',
-  ['.*/log/messages%.log'] = 'messages',
-  ['.*/log/news/news%.log'] = 'messages',
-  ['.*/log/syslog%.log'] = 'messages',
-  ['.*/log/user%.log'] = 'messages',
-  ['.*/log/auth%.err'] = 'messages',
-  ['.*/log/cron%.err'] = 'messages',
-  ['.*/log/daemon%.err'] = 'messages',
-  ['.*/log/debug%.err'] = 'messages',
-  ['.*/log/kern%.err'] = 'messages',
-  ['.*/log/lpr%.err'] = 'messages',
-  ['.*/log/mail%.err'] = 'messages',
-  ['.*/log/messages%.err'] = 'messages',
-  ['.*/log/news/news%.err'] = 'messages',
-  ['.*/log/syslog%.err'] = 'messages',
-  ['.*/log/user%.err'] = 'messages',
-  ['.*/log/auth%.info'] = 'messages',
-  ['.*/log/cron%.info'] = 'messages',
-  ['.*/log/daemon%.info'] = 'messages',
-  ['.*/log/debug%.info'] = 'messages',
-  ['.*/log/kern%.info'] = 'messages',
-  ['.*/log/lpr%.info'] = 'messages',
-  ['.*/log/mail%.info'] = 'messages',
-  ['.*/log/messages%.info'] = 'messages',
-  ['.*/log/news/news%.info'] = 'messages',
-  ['.*/log/syslog%.info'] = 'messages',
-  ['.*/log/user%.info'] = 'messages',
-  ['.*/log/auth%.warn'] = 'messages',
-  ['.*/log/cron%.warn'] = 'messages',
-  ['.*/log/daemon%.warn'] = 'messages',
-  ['.*/log/debug%.warn'] = 'messages',
-  ['.*/log/kern%.warn'] = 'messages',
-  ['.*/log/lpr%.warn'] = 'messages',
-  ['.*/log/mail%.warn'] = 'messages',
-  ['.*/log/messages%.warn'] = 'messages',
-  ['.*/log/news/news%.warn'] = 'messages',
-  ['.*/log/syslog%.warn'] = 'messages',
-  ['.*/log/user%.warn'] = 'messages',
-  ['.*/log/auth%.crit'] = 'messages',
-  ['.*/log/cron%.crit'] = 'messages',
-  ['.*/log/daemon%.crit'] = 'messages',
-  ['.*/log/debug%.crit'] = 'messages',
-  ['.*/log/kern%.crit'] = 'messages',
-  ['.*/log/lpr%.crit'] = 'messages',
-  ['.*/log/mail%.crit'] = 'messages',
-  ['.*/log/messages%.crit'] = 'messages',
-  ['.*/log/news/news%.crit'] = 'messages',
-  ['.*/log/syslog%.crit'] = 'messages',
-  ['.*/log/user%.crit'] = 'messages',
-  ['.*/log/auth%.notice'] = 'messages',
-  ['.*/log/cron%.notice'] = 'messages',
-  ['.*/log/daemon%.notice'] = 'messages',
-  ['.*/log/debug%.notice'] = 'messages',
-  ['.*/log/kern%.notice'] = 'messages',
-  ['.*/log/lpr%.notice'] = 'messages',
-  ['.*/log/mail%.notice'] = 'messages',
-  ['.*/log/messages%.notice'] = 'messages',
-  ['.*/log/news/news%.notice'] = 'messages',
-  ['.*/log/syslog%.notice'] = 'messages',
-  ['.*/log/user%.notice'] = 'messages',
-  ['.*%.[Mm][Oo][Dd]'] = detect.mod,
-  ['.*/etc/modules%.conf'] = 'modconf',
-  ['.*/etc/conf%.modules'] = 'modconf',
-  ['.*/etc/modules'] = 'modconf',
-  ['.*/etc/modprobe%..*'] = starsetf('modconf'),
-  ['.*/etc/modutils/.*'] = starsetf(function(path, bufnr)
+  ['^%.?gtkrc'] = starsetf('gtkrc'),
+  ['^${VIMRUNTIME}/doc/.*%.txt$'] = 'help',
+  ['^hg%-editor%-.*%.txt$'] = 'hgcommit',
+  ['/etc/host%.conf$'] = 'hostconf',
+  ['/etc/hosts%.deny$'] = 'hostsaccess',
+  ['/etc/hosts%.allow$'] = 'hostsaccess',
+  ['%.html%.m4$'] = 'htmlm4',
+  ['/%.i3/config$'] = 'i3config',
+  ['/i3/config$'] = 'i3config',
+  ['/%.icewm/menu$'] = 'icemenu',
+  ['/etc/initng/.*/.*%.i$'] = 'initng',
+  ['^JAM.*%.'] = starsetf('jam'),
+  ['^Prl.*%.'] = starsetf('jam'),
+  ['%.properties_..$'] = 'jproperties',
+  ['%.properties_.._..$'] = 'jproperties',
+  ['^org%.eclipse%..*%.prefs$'] = 'jproperties',
+  ['%.properties_.._.._'] = starsetf('jproperties'),
+  ['^[jt]sconfig.*%.json$'] = 'jsonc',
+  ['^[jJ]ustfile$'] = 'just',
+  ['^Kconfig%.'] = starsetf('kconfig'),
+  ['^Config%.in%.'] = starsetf('kconfig'),
+  ['%.[Ss][Uu][Bb]$'] = 'krl',
+  ['^lilo%.conf'] = starsetf('lilo'),
+  ['/etc/logcheck/.*%.d.*/'] = starsetf('logcheck'),
+  ['/ldscripts/'] = 'ld',
+  ['lftp/rc$'] = 'lftp',
+  ['/%.libao$'] = 'libao',
+  ['/etc/libao%.conf$'] = 'libao',
+  ['/etc/.*limits%.conf$'] = 'limits',
+  ['/etc/limits$'] = 'limits',
+  ['/etc/.*limits%.d/.*%.conf$'] = 'limits',
+  ['/supertux2/config$'] = 'lisp',
+  ['/LiteStep/.*/.*%.rc$'] = 'litestep',
+  ['/etc/login%.access$'] = 'loginaccess',
+  ['/etc/login%.defs$'] = 'logindefs',
+  ['^%.letter%.%d+$'] = 'mail',
+  ['^%.article%.%d+$'] = 'mail',
+  ['^/tmp/SLRN[0-9A-Z.]+$'] = 'mail',
+  ['^ae%d+%.txt$'] = 'mail',
+  ['^pico%.%d+$'] = 'mail',
+  ['^mutt%-.*%-%w+$'] = 'mail',
+  ['^muttng%-.*%-%w+$'] = 'mail',
+  ['^neomutt%-.*%-%w+$'] = 'mail',
+  ['^mutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail',
+  ['^neomutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail',
+  ['^snd%.%d+$'] = 'mail',
+  ['^reportbug%-'] = starsetf('mail'),
+  ['/etc/mail/aliases$'] = 'mailaliases',
+  ['/etc/aliases$'] = 'mailaliases',
+  ['[mM]akefile$'] = 'make',
+  ['^[mM]akefile'] = starsetf('make'),
+  ['/etc/man%.conf$'] = 'manconf',
+  ['/log/auth$'] = 'messages',
+  ['/log/cron$'] = 'messages',
+  ['/log/daemon$'] = 'messages',
+  ['/log/debug$'] = 'messages',
+  ['/log/kern$'] = 'messages',
+  ['/log/lpr$'] = 'messages',
+  ['/log/mail$'] = 'messages',
+  ['/log/messages$'] = 'messages',
+  ['/log/news/news$'] = 'messages',
+  ['/log/syslog$'] = 'messages',
+  ['/log/user$'] = 'messages',
+  ['/log/auth%.log$'] = 'messages',
+  ['/log/cron%.log$'] = 'messages',
+  ['/log/daemon%.log$'] = 'messages',
+  ['/log/debug%.log$'] = 'messages',
+  ['/log/kern%.log$'] = 'messages',
+  ['/log/lpr%.log$'] = 'messages',
+  ['/log/mail%.log$'] = 'messages',
+  ['/log/messages%.log$'] = 'messages',
+  ['/log/news/news%.log$'] = 'messages',
+  ['/log/syslog%.log$'] = 'messages',
+  ['/log/user%.log$'] = 'messages',
+  ['/log/auth%.err$'] = 'messages',
+  ['/log/cron%.err$'] = 'messages',
+  ['/log/daemon%.err$'] = 'messages',
+  ['/log/debug%.err$'] = 'messages',
+  ['/log/kern%.err$'] = 'messages',
+  ['/log/lpr%.err$'] = 'messages',
+  ['/log/mail%.err$'] = 'messages',
+  ['/log/messages%.err$'] = 'messages',
+  ['/log/news/news%.err$'] = 'messages',
+  ['/log/syslog%.err$'] = 'messages',
+  ['/log/user%.err$'] = 'messages',
+  ['/log/auth%.info$'] = 'messages',
+  ['/log/cron%.info$'] = 'messages',
+  ['/log/daemon%.info$'] = 'messages',
+  ['/log/debug%.info$'] = 'messages',
+  ['/log/kern%.info$'] = 'messages',
+  ['/log/lpr%.info$'] = 'messages',
+  ['/log/mail%.info$'] = 'messages',
+  ['/log/messages%.info$'] = 'messages',
+  ['/log/news/news%.info$'] = 'messages',
+  ['/log/syslog%.info$'] = 'messages',
+  ['/log/user%.info$'] = 'messages',
+  ['/log/auth%.warn$'] = 'messages',
+  ['/log/cron%.warn$'] = 'messages',
+  ['/log/daemon%.warn$'] = 'messages',
+  ['/log/debug%.warn$'] = 'messages',
+  ['/log/kern%.warn$'] = 'messages',
+  ['/log/lpr%.warn$'] = 'messages',
+  ['/log/mail%.warn$'] = 'messages',
+  ['/log/messages%.warn$'] = 'messages',
+  ['/log/news/news%.warn$'] = 'messages',
+  ['/log/syslog%.warn$'] = 'messages',
+  ['/log/user%.warn$'] = 'messages',
+  ['/log/auth%.crit$'] = 'messages',
+  ['/log/cron%.crit$'] = 'messages',
+  ['/log/daemon%.crit$'] = 'messages',
+  ['/log/debug%.crit$'] = 'messages',
+  ['/log/kern%.crit$'] = 'messages',
+  ['/log/lpr%.crit$'] = 'messages',
+  ['/log/mail%.crit$'] = 'messages',
+  ['/log/messages%.crit$'] = 'messages',
+  ['/log/news/news%.crit$'] = 'messages',
+  ['/log/syslog%.crit$'] = 'messages',
+  ['/log/user%.crit$'] = 'messages',
+  ['/log/auth%.notice$'] = 'messages',
+  ['/log/cron%.notice$'] = 'messages',
+  ['/log/daemon%.notice$'] = 'messages',
+  ['/log/debug%.notice$'] = 'messages',
+  ['/log/kern%.notice$'] = 'messages',
+  ['/log/lpr%.notice$'] = 'messages',
+  ['/log/mail%.notice$'] = 'messages',
+  ['/log/messages%.notice$'] = 'messages',
+  ['/log/news/news%.notice$'] = 'messages',
+  ['/log/syslog%.notice$'] = 'messages',
+  ['/log/user%.notice$'] = 'messages',
+  ['%.[Mm][Oo][Dd]$'] = detect.mod,
+  ['/etc/modules%.conf$'] = 'modconf',
+  ['/etc/conf%.modules$'] = 'modconf',
+  ['/etc/modules$'] = 'modconf',
+  ['/etc/modprobe%.'] = starsetf('modconf'),
+  ['/etc/modutils/'] = starsetf(function(path, bufnr)
     if fn.executable(fn.expand(path)) ~= 1 then
       return 'modconf'
     end
   end),
-  ['Muttrc'] = 'muttrc',
-  ['Muttngrc'] = 'muttrc',
-  ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'),
-  ['.*/%.mplayer/config'] = 'mplayerconf',
-  ['Muttrc.*'] = detect_muttrc,
-  ['Muttngrc.*'] = detect_muttrc,
+  ['^Muttrc$'] = 'muttrc',
+  ['^Muttngrc$'] = 'muttrc',
+  ['/etc/Muttrc%.d/'] = starsetf('muttrc'),
+  ['/%.mplayer/config$'] = 'mplayerconf',
+  ['^Muttrc'] = detect_muttrc,
+  ['^Muttngrc'] = detect_muttrc,
   -- muttrc* and .muttrc*
-  ['%.?muttrc.*'] = detect_muttrc,
+  ['^%.?muttrc'] = detect_muttrc,
   -- muttngrc* and .muttngrc*
-  ['%.?muttngrc.*'] = detect_muttrc,
-  ['.*/%.mutt/muttrc.*'] = detect_muttrc,
-  ['.*/%.muttng/muttrc.*'] = detect_muttrc,
-  ['.*/%.muttng/muttngrc.*'] = detect_muttrc,
-  ['rndc.*%.conf'] = 'named',
-  ['rndc.*%.key'] = 'named',
-  ['named.*%.conf'] = 'named',
-  ['.*/etc/nanorc'] = 'nanorc',
-  ['.*%.NS[ACGLMNPS]'] = 'natural',
-  ['Neomuttrc.*'] = detect_neomuttrc,
+  ['^%.?muttngrc'] = detect_muttrc,
+  ['/%.mutt/muttrc'] = detect_muttrc,
+  ['/%.muttng/muttrc'] = detect_muttrc,
+  ['/%.muttng/muttngrc'] = detect_muttrc,
+  ['^rndc.*%.conf$'] = 'named',
+  ['^rndc.*%.key$'] = 'named',
+  ['^named.*%.conf$'] = 'named',
+  ['/etc/nanorc$'] = 'nanorc',
+  ['%.NS[ACGLMNPS]$'] = 'natural',
+  ['^Neomuttrc'] = detect_neomuttrc,
   -- neomuttrc* and .neomuttrc*
-  ['%.?neomuttrc.*'] = detect_neomuttrc,
-  ['.*/%.neomutt/neomuttrc.*'] = detect_neomuttrc,
-  ['nginx.*%.conf'] = 'nginx',
-  ['.*/etc/nginx/.*'] = 'nginx',
-  ['.*nginx%.conf'] = 'nginx',
-  ['.*/nginx/.*%.conf'] = 'nginx',
-  ['.*/usr/local/nginx/conf/.*'] = 'nginx',
-  ['.*%.[1-9]'] = detect.nroff,
-  ['.*%.ml%.cppo'] = 'ocaml',
-  ['.*%.mli%.cppo'] = 'ocaml',
-  ['.*/octave/history'] = 'octave',
-  ['.*%.opam%.template'] = 'opam',
-  ['.*/openvpn/.*/.*%.conf'] = 'openvpn',
-  ['.*%.[Oo][Pp][Ll]'] = 'opl',
-  ['.*/etc/pam%.conf'] = 'pamconf',
-  ['.*/etc/pam%.d/.*'] = starsetf('pamconf'),
-  ['.*/etc/passwd%-'] = 'passwd',
-  ['.*/etc/shadow'] = 'passwd',
-  ['.*/etc/shadow%.edit'] = 'passwd',
-  ['.*/var/backups/shadow%.bak'] = 'passwd',
-  ['.*/var/backups/passwd%.bak'] = 'passwd',
-  ['.*/etc/passwd'] = 'passwd',
-  ['.*/etc/passwd%.edit'] = 'passwd',
-  ['.*/etc/shadow%-'] = 'passwd',
-  ['%.?gitolite%.rc'] = 'perl',
-  ['example%.gitolite%.rc'] = 'perl',
-  ['.*%.php%d'] = 'php',
-  ['.*/%.pinforc'] = 'pinfo',
-  ['.*/etc/pinforc'] = 'pinfo',
-  ['.*%.[Pp][Rr][Gg]'] = detect.prg,
-  ['.*/etc/protocols'] = 'protocols',
-  ['.*printcap.*'] = starsetf(function(path, bufnr)
+  ['^%.?neomuttrc'] = detect_neomuttrc,
+  ['/%.neomutt/neomuttrc'] = detect_neomuttrc,
+  ['^nginx.*%.conf$'] = 'nginx',
+  ['/etc/nginx/'] = 'nginx',
+  ['nginx%.conf$'] = 'nginx',
+  ['/nginx/.*%.conf$'] = 'nginx',
+  ['/usr/local/nginx/conf/'] = 'nginx',
+  ['%.[1-9]$'] = detect.nroff,
+  ['%.ml%.cppo$'] = 'ocaml',
+  ['%.mli%.cppo$'] = 'ocaml',
+  ['/octave/history$'] = 'octave',
+  ['%.opam%.template$'] = 'opam',
+  ['/openvpn/.*/.*%.conf$'] = 'openvpn',
+  ['%.[Oo][Pp][Ll]$'] = 'opl',
+  ['/etc/pam%.conf$'] = 'pamconf',
+  ['/etc/pam%.d/'] = starsetf('pamconf'),
+  ['/etc/passwd%-$'] = 'passwd',
+  ['/etc/shadow$'] = 'passwd',
+  ['/etc/shadow%.edit$'] = 'passwd',
+  ['/var/backups/shadow%.bak$'] = 'passwd',
+  ['/var/backups/passwd%.bak$'] = 'passwd',
+  ['/etc/passwd$'] = 'passwd',
+  ['/etc/passwd%.edit$'] = 'passwd',
+  ['/etc/shadow%-$'] = 'passwd',
+  ['^%.?gitolite%.rc$'] = 'perl',
+  ['^example%.gitolite%.rc$'] = 'perl',
+  ['%.php%d$'] = 'php',
+  ['/%.pinforc$'] = 'pinfo',
+  ['/etc/pinforc$'] = 'pinfo',
+  ['%.[Pp][Rr][Gg]$'] = detect.prg,
+  ['/etc/protocols$'] = 'protocols',
+  ['printcap'] = starsetf(function(path, bufnr)
     return require('vim.filetype.detect').printcap('print')
   end),
-  ['.*baseq[2-3]/.*%.cfg'] = 'quake',
-  ['.*quake[1-3]/.*%.cfg'] = 'quake',
-  ['.*id1/.*%.cfg'] = 'quake',
-  ['.*/queries/.*%.scm'] = 'query', -- treesitter queries (Neovim only)
-  ['.*,v'] = 'rcs',
-  ['%.reminders.*'] = starsetf('remind'),
-  ['.*%-requirements%.txt'] = 'requirements',
-  ['requirements/.*%.txt'] = 'requirements',
-  ['requires/.*%.txt'] = 'requirements',
-  ['[rR]akefile.*'] = starsetf('ruby'),
-  ['[rR]antfile'] = 'ruby',
-  ['[rR]akefile'] = 'ruby',
-  ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'),
-  ['.*/etc/sensors%.conf'] = 'sensors',
-  ['.*/etc/sensors3%.conf'] = 'sensors',
-  ['.*/etc/services'] = 'services',
-  ['.*/etc/serial%.conf'] = 'setserial',
-  ['.*/etc/udev/cdsymlinks%.conf'] = 'sh',
-  ['.*/neofetch/config%.conf'] = 'sh',
-  ['%.bash[_%-]aliases'] = detect.bash,
-  ['%.bash[_%-]history'] = detect.bash,
-  ['%.bash[_%-]logout'] = detect.bash,
-  ['%.bash[_%-]profile'] = detect.bash,
-  ['%.kshrc.*'] = detect.ksh,
-  ['%.profile.*'] = detect.sh,
-  ['.*/etc/profile'] = detect.sh,
-  ['bash%-fc[%-%.].*'] = detect.bash,
-  ['%.tcshrc.*'] = detect.tcsh,
-  ['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'),
-  ['.*%._sst%.meta'] = 'sisu',
-  ['.*%.%-sst%.meta'] = 'sisu',
-  ['.*%.sst%.meta'] = 'sisu',
-  ['.*/etc/slp%.conf'] = 'slpconf',
-  ['.*/etc/slp%.reg'] = 'slpreg',
-  ['.*/etc/slp%.spi'] = 'slpspi',
-  ['.*/etc/ssh/ssh_config%.d/.*%.conf'] = 'sshconfig',
-  ['.*/%.ssh/config'] = 'sshconfig',
-  ['.*/%.ssh/.*%.conf'] = 'sshconfig',
-  ['.*/etc/ssh/sshd_config%.d/.*%.conf'] = 'sshdconfig',
-  ['.*%.[Ss][Rr][Cc]'] = detect.src,
-  ['.*/etc/sudoers'] = 'sudoers',
-  ['svn%-commit.*%.tmp'] = 'svn',
-  ['.*/sway/config'] = 'swayconfig',
-  ['.*/%.sway/config'] = 'swayconfig',
-  ['.*%.swift%.gyb'] = 'swiftgyb',
-  ['.*%.[Ss][Yy][Ss]'] = detect.sys,
-  ['.*/etc/sysctl%.conf'] = 'sysctl',
-  ['.*/etc/sysctl%.d/.*%.conf'] = 'sysctl',
-  ['.*/systemd/.*%.automount'] = 'systemd',
-  ['.*/systemd/.*%.dnssd'] = 'systemd',
-  ['.*/systemd/.*%.link'] = 'systemd',
-  ['.*/systemd/.*%.mount'] = 'systemd',
-  ['.*/systemd/.*%.netdev'] = 'systemd',
-  ['.*/systemd/.*%.network'] = 'systemd',
-  ['.*/systemd/.*%.nspawn'] = 'systemd',
-  ['.*/systemd/.*%.path'] = 'systemd',
-  ['.*/systemd/.*%.service'] = 'systemd',
-  ['.*/systemd/.*%.slice'] = 'systemd',
-  ['.*/systemd/.*%.socket'] = 'systemd',
-  ['.*/systemd/.*%.swap'] = 'systemd',
-  ['.*/systemd/.*%.target'] = 'systemd',
-  ['.*/systemd/.*%.timer'] = 'systemd',
-  ['.*/etc/systemd/.*%.conf%.d/.*%.conf'] = 'systemd',
-  ['.*/%.config/systemd/user/.*%.d/.*%.conf'] = 'systemd',
-  ['.*/etc/systemd/system/.*%.d/.*%.conf'] = 'systemd',
-  ['.*/etc/systemd/system/.*%.d/%.#.*'] = 'systemd',
-  ['.*/etc/systemd/system/%.#.*'] = 'systemd',
-  ['.*/%.config/systemd/user/.*%.d/%.#.*'] = 'systemd',
-  ['.*/%.config/systemd/user/%.#.*'] = 'systemd',
-  ['.*termcap.*'] = starsetf(function(path, bufnr)
+  ['baseq[2-3]/.*%.cfg$'] = 'quake',
+  ['quake[1-3]/.*%.cfg$'] = 'quake',
+  ['id1/.*%.cfg$'] = 'quake',
+  ['/queries/.*%.scm$'] = 'query', -- treesitter queries (Neovim only)
+  [',v$'] = 'rcs',
+  ['^%.reminders'] = starsetf('remind'),
+  ['%-requirements%.txt$'] = 'requirements',
+  ['^requirements/.*%.txt$'] = 'requirements',
+  ['^requires/.*%.txt$'] = 'requirements',
+  ['^[rR]akefile'] = starsetf('ruby'),
+  ['^[rR]antfile$'] = 'ruby',
+  ['^[rR]akefile$'] = 'ruby',
+  ['/etc/sensors%.d/[^.]'] = starsetf('sensors'),
+  ['/etc/sensors%.conf$'] = 'sensors',
+  ['/etc/sensors3%.conf$'] = 'sensors',
+  ['/etc/services$'] = 'services',
+  ['/etc/serial%.conf$'] = 'setserial',
+  ['/etc/udev/cdsymlinks%.conf$'] = 'sh',
+  ['/neofetch/config%.conf$'] = 'sh',
+  ['^%.bash[_%-]aliases$'] = detect.bash,
+  ['^%.bash[_%-]history$'] = detect.bash,
+  ['^%.bash[_%-]logout$'] = detect.bash,
+  ['^%.bash[_%-]profile$'] = detect.bash,
+  ['^%.kshrc'] = detect.ksh,
+  ['^%.profile'] = detect.sh,
+  ['/etc/profile$'] = detect.sh,
+  ['^bash%-fc[%-%.]'] = detect.bash,
+  ['^%.tcshrc'] = detect.tcsh,
+  ['/etc/sudoers%.d/'] = starsetf('sudoers'),
+  ['%._sst%.meta$'] = 'sisu',
+  ['%.%-sst%.meta$'] = 'sisu',
+  ['%.sst%.meta$'] = 'sisu',
+  ['/etc/slp%.conf$'] = 'slpconf',
+  ['/etc/slp%.reg$'] = 'slpreg',
+  ['/etc/slp%.spi$'] = 'slpspi',
+  ['/etc/ssh/ssh_config%.d/.*%.conf$'] = 'sshconfig',
+  ['/%.ssh/config$'] = 'sshconfig',
+  ['/%.ssh/.*%.conf$'] = 'sshconfig',
+  ['/etc/ssh/sshd_config%.d/.*%.conf$'] = 'sshdconfig',
+  ['%.[Ss][Rr][Cc]$'] = detect.src,
+  ['/etc/sudoers$'] = 'sudoers',
+  ['^svn%-commit.*%.tmp$'] = 'svn',
+  ['/sway/config$'] = 'swayconfig',
+  ['/%.sway/config$'] = 'swayconfig',
+  ['%.swift%.gyb$'] = 'swiftgyb',
+  ['%.[Ss][Yy][Ss]$'] = detect.sys,
+  ['/etc/sysctl%.conf$'] = 'sysctl',
+  ['/etc/sysctl%.d/.*%.conf$'] = 'sysctl',
+  ['/systemd/.*%.automount$'] = 'systemd',
+  ['/systemd/.*%.dnssd$'] = 'systemd',
+  ['/systemd/.*%.link$'] = 'systemd',
+  ['/systemd/.*%.mount$'] = 'systemd',
+  ['/systemd/.*%.netdev$'] = 'systemd',
+  ['/systemd/.*%.network$'] = 'systemd',
+  ['/systemd/.*%.nspawn$'] = 'systemd',
+  ['/systemd/.*%.path$'] = 'systemd',
+  ['/systemd/.*%.service$'] = 'systemd',
+  ['/systemd/.*%.slice$'] = 'systemd',
+  ['/systemd/.*%.socket$'] = 'systemd',
+  ['/systemd/.*%.swap$'] = 'systemd',
+  ['/systemd/.*%.target$'] = 'systemd',
+  ['/systemd/.*%.timer$'] = 'systemd',
+  ['/etc/systemd/.*%.conf%.d/.*%.conf$'] = 'systemd',
+  ['/%.config/systemd/user/.*%.d/.*%.conf$'] = 'systemd',
+  ['/etc/systemd/system/.*%.d/.*%.conf$'] = 'systemd',
+  ['/etc/systemd/system/.*%.d/%.#'] = 'systemd',
+  ['/etc/systemd/system/%.#'] = 'systemd',
+  ['/%.config/systemd/user/.*%.d/%.#'] = 'systemd',
+  ['/%.config/systemd/user/%.#'] = 'systemd',
+  ['termcap'] = starsetf(function(path, bufnr)
     return require('vim.filetype.detect').printcap('term')
   end),
-  ['.*/tex/latex/.*%.cfg'] = 'tex',
-  ['.*%.t%.html'] = 'tilde',
-  ['%.?tmux.*%.conf'] = 'tmux',
-  ['%.?tmux.*%.conf.*'] = { 'tmux', { priority = -1 } },
-  ['.*/%.cargo/config'] = 'toml',
-  ['.*/%.cargo/credentials'] = 'toml',
-  ['.*/etc/udev/udev%.conf'] = 'udevconf',
-  ['.*/etc/udev/permissions%.d/.*%.permissions'] = 'udevperm',
-  ['.*/etc/updatedb%.conf'] = 'updatedb',
-  ['.*/%.init/.*%.override'] = 'upstart',
-  ['.*/usr/share/upstart/.*%.conf'] = 'upstart',
-  ['.*/%.config/upstart/.*%.override'] = 'upstart',
-  ['.*/etc/init/.*%.conf'] = 'upstart',
-  ['.*/etc/init/.*%.override'] = 'upstart',
-  ['.*/%.config/upstart/.*%.conf'] = 'upstart',
-  ['.*/%.init/.*%.conf'] = 'upstart',
-  ['.*/usr/share/upstart/.*%.override'] = 'upstart',
-  ['.*%.[Ll][Oo][Gg]'] = detect.log,
-  ['.*/etc/config/.*'] = starsetf(detect.uci),
-  ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'),
-  ['.*/Xresources/.*'] = starsetf('xdefaults'),
-  ['.*/app%-defaults/.*'] = starsetf('xdefaults'),
-  ['.*/etc/xinetd%.conf'] = 'xinetd',
-  ['.*/usr/share/X11/xkb/compat/.*'] = starsetf('xkb'),
-  ['.*/usr/share/X11/xkb/geometry/.*'] = starsetf('xkb'),
-  ['.*/usr/share/X11/xkb/keycodes/.*'] = starsetf('xkb'),
-  ['.*/usr/share/X11/xkb/symbols/.*'] = starsetf('xkb'),
-  ['.*/usr/share/X11/xkb/types/.*'] = starsetf('xkb'),
-  ['.*/etc/blkid%.tab'] = 'xml',
-  ['.*/etc/blkid%.tab%.old'] = 'xml',
-  ['.*%.vbproj%.user'] = 'xml',
-  ['.*%.fsproj%.user'] = 'xml',
-  ['.*%.csproj%.user'] = 'xml',
-  ['.*/etc/xdg/menus/.*%.menu'] = 'xml',
-  ['.*Xmodmap'] = 'xmodmap',
-  ['.*/etc/zprofile'] = 'zsh',
-  ['.*vimrc.*'] = starsetf('vim'),
-  ['Xresources.*'] = starsetf('xdefaults'),
-  ['.*/etc/xinetd%.d/.*'] = starsetf('xinetd'),
-  ['.*xmodmap.*'] = starsetf('xmodmap'),
-  ['.*/xorg%.conf%.d/.*%.conf'] = detect.xfree86_v4,
+  ['/tex/latex/.*%.cfg$'] = 'tex',
+  ['%.t%.html$'] = 'tilde',
+  ['^%.?tmux.*%.conf$'] = 'tmux',
+  ['^%.?tmux.*%.conf'] = { 'tmux', { priority = -1 } },
+  ['/%.cargo/config$'] = 'toml',
+  ['/%.cargo/credentials$'] = 'toml',
+  ['/etc/udev/udev%.conf$'] = 'udevconf',
+  ['/etc/udev/permissions%.d/.*%.permissions$'] = 'udevperm',
+  ['/etc/updatedb%.conf$'] = 'updatedb',
+  ['/%.init/.*%.override$'] = 'upstart',
+  ['/usr/share/upstart/.*%.conf$'] = 'upstart',
+  ['/%.config/upstart/.*%.override$'] = 'upstart',
+  ['/etc/init/.*%.conf$'] = 'upstart',
+  ['/etc/init/.*%.override$'] = 'upstart',
+  ['/%.config/upstart/.*%.conf$'] = 'upstart',
+  ['/%.init/.*%.conf$'] = 'upstart',
+  ['/usr/share/upstart/.*%.override$'] = 'upstart',
+  ['%.[Ll][Oo][Gg]$'] = detect.log,
+  ['/etc/config/'] = starsetf(detect.uci),
+  ['%.vhdl_[0-9]'] = starsetf('vhdl'),
+  ['/Xresources/'] = starsetf('xdefaults'),
+  ['/app%-defaults/'] = starsetf('xdefaults'),
+  ['/etc/xinetd%.conf$'] = 'xinetd',
+  ['/usr/share/X11/xkb/compat/'] = starsetf('xkb'),
+  ['/usr/share/X11/xkb/geometry/'] = starsetf('xkb'),
+  ['/usr/share/X11/xkb/keycodes/'] = starsetf('xkb'),
+  ['/usr/share/X11/xkb/symbols/'] = starsetf('xkb'),
+  ['/usr/share/X11/xkb/types/'] = starsetf('xkb'),
+  ['/etc/blkid%.tab$'] = 'xml',
+  ['/etc/blkid%.tab%.old$'] = 'xml',
+  ['%.vbproj%.user$'] = 'xml',
+  ['%.fsproj%.user$'] = 'xml',
+  ['%.csproj%.user$'] = 'xml',
+  ['/etc/xdg/menus/.*%.menu$'] = 'xml',
+  ['Xmodmap$'] = 'xmodmap',
+  ['/etc/zprofile$'] = 'zsh',
+  ['vimrc'] = starsetf('vim'),
+  ['^Xresources'] = starsetf('xdefaults'),
+  ['/etc/xinetd%.d/'] = starsetf('xinetd'),
+  ['xmodmap'] = starsetf('xmodmap'),
+  ['/xorg%.conf%.d/.*%.conf$'] = detect.xfree86_v4,
   -- Increase priority to run before the pattern below
-  ['XF86Config%-4.*'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }),
-  ['XF86Config.*'] = starsetf(detect.xfree86_v3),
-  ['.*/%.bundle/config'] = 'yaml',
-  ['%.zcompdump.*'] = starsetf('zsh'),
+  ['^XF86Config%-4'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }),
+  ['^XF86Config'] = starsetf(detect.xfree86_v3),
+  ['/%.bundle/config$'] = 'yaml',
+  ['^%.zcompdump'] = starsetf('zsh'),
   -- .zlog* and zlog*
-  ['%.?zlog.*'] = starsetf('zsh'),
+  ['^%.?zlog'] = starsetf('zsh'),
   -- .zsh* and zsh*
-  ['%.?zsh.*'] = starsetf('zsh'),
+  ['^%.?zsh'] = starsetf('zsh'),
   -- Ignored extension
-  ['.*~'] = function(path, bufnr)
+  ['~$'] = function(path, bufnr)
     local short = path:gsub('~+$', '', 1)
     if path ~= short and short ~= '' then
       return M.match({ buf = bufnr, filename = fn.fnameescape(short) })
@@ -2219,7 +2222,7 @@ local pattern = {
 -- luacheck: pop
 
 --- Lookup table/cache for patterns
---- @alias vim.filetype.pattern_cache { fullpat: string, has_env: boolean, has_slash: boolean }
+--- @alias vim.filetype.pattern_cache { has_env: boolean, has_slash: boolean }
 --- @type table
 local pattern_lookup = {}
 
@@ -2243,11 +2246,8 @@ local function sort_by_priority(t)
     )
 
     -- Parse pattern for common data and cache it once
-    pattern_lookup[pat] = pattern_lookup[pat] or {
-      fullpat = '^' .. pat .. '$',
-      has_env = pat:find('%$%b{}') ~= nil,
-      has_slash = pat:find('/') ~= nil,
-    }
+    pattern_lookup[pat] = pattern_lookup[pat]
+      or { has_env = pat:find('%$%b{}') ~= nil, has_slash = pat:find('/') ~= nil }
 
     local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or {}
     opts.priority = opts.priority or 0
@@ -2380,7 +2380,8 @@ function M.add(filetypes)
   end
 
   for k, v in pairs(filetypes.pattern or {}) do
-    pattern[normalize_path(k, true)] = v
+    -- User patterns are assumed to be implicitly anchored (as in Vim)
+    pattern['^' .. normalize_path(k, true) .. '$'] = v
   end
 
   if filetypes.pattern then
@@ -2450,15 +2451,15 @@ end
 --- @return string|boolean?
 local function match_pattern(name, path, tail, pat)
   local pat_cache = pattern_lookup[pat]
-  local fullpat, has_slash = pat_cache.fullpat, pat_cache.has_slash
+  local has_slash = pat_cache.has_slash
 
   if pat_cache.has_env then
-    local some_env_missing, expanded = expand_envvar_pattern(fullpat)
+    local some_env_missing, expanded = expand_envvar_pattern(pat)
     -- If any environment variable is present in the pattern but not set, there is no match
     if some_env_missing then
       return false
     end
-    fullpat, has_slash = expanded, expanded:find('/') ~= nil
+    pat, has_slash = expanded, expanded:find('/') ~= nil
   end
 
   -- If the pattern contains a / match against the full path, otherwise just the tail
@@ -2466,10 +2467,10 @@ local function match_pattern(name, path, tail, pat)
     -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against
     -- both the short file name (as typed) and the full file name (after expanding to full path
     -- and resolving symlinks)
-    return (name:match(fullpat) or path:match(fullpat))
+    return (name:match(pat) or path:match(pat))
   end
 
-  return (tail:match(fullpat))
+  return (tail:match(pat))
 end
 
 --- @param name string
-- 
cgit 


From b1aa8f5eb8a5407e869335e9987b73f8515c37e5 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sat, 13 Jul 2024 08:56:58 +0800
Subject: vim-patch:9.1.0572: cannot specify tab page closing behaviour
 (#29682)

Problem:  cannot specify tab page closing behaviour
          (Gianluca Pacchiella)
Solution: Add the 'tabclose' option (LemonBoy).

fixes: vim/vim#5967
closes: vim/vim#15204

https://github.com/vim/vim/commit/5247b0b92e191a046b034171a3b34031e317735f

Co-authored-by: LemonBoy 
---
 runtime/lua/vim/_meta/options.lua | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 40c12d94fd..332dbda6e9 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -6837,6 +6837,22 @@ vim.o.syn = vim.o.syntax
 vim.bo.syntax = vim.o.syntax
 vim.bo.syn = vim.bo.syntax
 
+--- This option controls the behavior when closing tab pages (e.g., using
+--- `:tabclose`).  When empty Vim goes to the next (right) tab page.
+---
+--- Possible values (comma-separated list):
+---    left		If included, go to the previous tab page instead of
+--- 		the next one.
+---    uselast	If included, go to the previously used tab page if
+--- 		possible.  This option takes precedence over the
+--- 		others.
+---
+--- @type string
+vim.o.tabclose = ""
+vim.o.tcl = vim.o.tabclose
+vim.go.tabclose = vim.o.tabclose
+vim.go.tcl = vim.go.tabclose
+
 --- When non-empty, this option determines the content of the tab pages
 --- line at the top of the Vim window.  When empty Vim will use a default
 --- tab pages line.  See `setting-tabline` for more info.
-- 
cgit 


From 60734dc76112c4142c6048839a0b93c2d48e77f3 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sun, 14 Jul 2024 12:02:40 +0200
Subject: vim-patch:9.1.0583: filetype: *.pdf_tex files are not recognized

Problem:  filetype: *.pdf_tex files are not recognized
Solution: Detect '*.pdf_tex' files as tex filetype
          (Jonas Dujava)

Those files are generated by inkscape, when exporting, see e.g.
https://inkscape.org/doc/inkscape-man.html

closes: vim/vim#15250

https://github.com/vim/vim/commit/28145e005d646cb0477aa26ef69d0f651a9f9d27

Co-authored-by: Jonas Dujava 
---
 runtime/lua/vim/filetype.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index f0e1af4f04..cead8871fe 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1076,6 +1076,7 @@ local extension = {
   nls = 'tex',
   thm = 'tex',
   eps_tex = 'tex',
+  pdf_tex = 'tex',
   pygtex = 'tex',
   pygstyle = 'tex',
   clo = 'tex',
-- 
cgit 


From 79130c0fd393e3eef8e4c939c54ea3d3faec2149 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sun, 14 Jul 2024 17:26:40 +0200
Subject: vim-patch:9.1.0586: ocaml runtime files are outdated

Problem:  ocaml runtime files are outdated
Solution: sync those files with the upstream repo,
          detect a few more ocaml files
          (Yinzuo Jiang)

closes: vim/vim#15260

https://github.com/vim/vim/commit/700cf8cfa1e926e2ba676203b3ad90c2c2083f1d

Co-authored-by: Yinzuo Jiang 
---
 runtime/lua/vim/filetype.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index cead8871fe..08451735b6 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1392,6 +1392,7 @@ local filename = {
   jbuild = 'dune',
   ['dune-workspace'] = 'dune',
   ['dune-project'] = 'dune',
+  ['dune-file'] = 'dune',
   Earthfile = 'earthfile',
   ['.editorconfig'] = 'editorconfig',
   ['elinks.conf'] = 'elinks',
@@ -1543,6 +1544,7 @@ local filename = {
   ['octave.conf'] = 'octave',
   ['.ondirrc'] = 'ondir',
   opam = 'opam',
+  ['opam.locked'] = 'opam',
   ['pacman.log'] = 'pacmanlog',
   ['/etc/pam.conf'] = 'pamconf',
   ['pam_env.conf'] = 'pamenv',
@@ -2065,6 +2067,7 @@ local pattern = {
   ['%.ml%.cppo$'] = 'ocaml',
   ['%.mli%.cppo$'] = 'ocaml',
   ['/octave/history$'] = 'octave',
+  ['%.opam%.locked$'] = 'opam',
   ['%.opam%.template$'] = 'opam',
   ['/openvpn/.*/.*%.conf$'] = 'openvpn',
   ['%.[Oo][Pp][Ll]$'] = 'opl',
-- 
cgit 


From 04c158fbec9aeeccd7bd1bb16fc8a688edadd353 Mon Sep 17 00:00:00 2001
From: dundargoc <33953936+dundargoc@users.noreply.github.com>
Date: Mon, 15 Jul 2024 00:54:45 +0200
Subject: docs: misc (#29622)

Co-authored-by: Christian Clason 
Co-authored-by: zeertzjq 
---
 runtime/lua/vim/_meta/vimfn.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index b18ca1ecf8..750f16ef06 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -4316,7 +4316,7 @@ function vim.fn.iconv(string, from, to) end
 --- Note that `v:_null_string`, `v:_null_list`, `v:_null_dict` and
 --- `v:_null_blob` have the same `id()` with different types
 --- because they are internally represented as NULL pointers.
---- `id()` returns a hexadecimal representanion of the pointers to
+--- `id()` returns a hexadecimal representation of the pointers to
 --- the containers (i.e. like `0x994a40`), same as `printf("%p",
 --- {expr})`, but it is advised against counting on the exact
 --- format of the return value.
-- 
cgit 


From 8703e7bd1215a1d67053fc189102391e57de6a78 Mon Sep 17 00:00:00 2001
From: Maria José Solano 
Date: Mon, 15 Jul 2024 12:55:57 -0700
Subject: docs(lpeg): merge upstream changes

---
 runtime/lua/vim/_meta/lpeg.lua | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/lpeg.lua b/runtime/lua/vim/_meta/lpeg.lua
index 39a894aaeb..d354de95df 100644
--- a/runtime/lua/vim/_meta/lpeg.lua
+++ b/runtime/lua/vim/_meta/lpeg.lua
@@ -2,7 +2,7 @@
 error('Cannot require a meta file')
 
 -- These types were taken from https://github.com/LuaCATS/lpeg
--- (based on revision 82c6a8fc676bbc20722026afd952668f3919b11d)
+-- (based on revision 33f4ff5343a64cf613a0634d70092fbc2b64291b)
 -- with types being renamed to include the vim namespace and with some descriptions made less verbose.
 
 --- @brief 
help
@@ -22,16 +22,17 @@ vim.lpeg = {}
 
 --- @nodoc
 --- @class vim.lpeg.Pattern
+--- @operator len: vim.lpeg.Pattern
 --- @operator unm: vim.lpeg.Pattern
 --- @operator add(vim.lpeg.Pattern): vim.lpeg.Pattern
 --- @operator sub(vim.lpeg.Pattern): vim.lpeg.Pattern
 --- @operator mul(vim.lpeg.Pattern): vim.lpeg.Pattern
 --- @operator mul(vim.lpeg.Capture): vim.lpeg.Pattern
 --- @operator div(string): vim.lpeg.Capture
---- @operator div(number): vim.lpeg.Capture
+--- @operator div(integer): vim.lpeg.Capture
 --- @operator div(table): vim.lpeg.Capture
 --- @operator div(function): vim.lpeg.Capture
---- @operator pow(number): vim.lpeg.Pattern
+--- @operator pow(integer): vim.lpeg.Pattern
 --- @operator mod(function): vim.lpeg.Capture
 local Pattern = {}
 
@@ -55,11 +56,12 @@ local Pattern = {}
 --- assert(pattern:match('1 hello') == nil)
 --- ```
 ---
---- @param pattern vim.lpeg.Pattern
+--- @param pattern vim.lpeg.Pattern|string|integer|boolean|table|function
 --- @param subject string
 --- @param init? integer
---- @return integer|vim.lpeg.Capture|nil
-function vim.lpeg.match(pattern, subject, init) end
+--- @param ... any
+--- @return any ...
+function vim.lpeg.match(pattern, subject, init, ...) end
 
 --- Matches the given `pattern` against the `subject` string. If the match succeeds, returns the
 --- index in the subject of the first character after the match, or the captured values (if the
@@ -81,8 +83,9 @@ function vim.lpeg.match(pattern, subject, init) end
 ---
 --- @param subject string
 --- @param init? integer
---- @return integer|vim.lpeg.Capture|nil
-function Pattern:match(subject, init) end
+--- @param ... any
+--- @return any ...
+function Pattern:match(subject, init, ...) end
 
 --- Returns the string `"pattern"` if the given value is a pattern, otherwise `nil`.
 ---
@@ -123,7 +126,7 @@ function vim.lpeg.P(value) end
 --- Pattern `patt` must match only strings with some fixed length, and it cannot contain captures.
 --- Like the `and` predicate, this pattern never consumes any input, independently of success or failure.
 ---
---- @param pattern vim.lpeg.Pattern
+--- @param pattern vim.lpeg.Pattern|string|integer|boolean|table
 --- @return vim.lpeg.Pattern
 function vim.lpeg.B(pattern) end
 
@@ -163,7 +166,7 @@ function vim.lpeg.S(string) end
 --- assert(b:match('(') == nil)
 --- ```
 ---
---- @param v string|integer
+--- @param v boolean|string|number|function|table|thread|userdata|lightuserdata 
 --- @return vim.lpeg.Pattern
 function vim.lpeg.V(v) end
 
@@ -227,7 +230,7 @@ function vim.lpeg.locale(tab) end
 --- assert(c == 'c')
 --- ```
 ---
---- @param patt vim.lpeg.Pattern
+--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function
 --- @return vim.lpeg.Capture
 function vim.lpeg.C(patt) end
 
@@ -258,7 +261,7 @@ function vim.lpeg.Cc(...) end
 --- `func(...func(func(C1, C2), C3)...,Cn)`, that is, it will fold (or accumulate, or reduce) the captures from
 --- `patt` using function `func`. This capture assumes that `patt` should produce at least one capture with at
 --- least one value (of any type), which becomes the initial value of an accumulator. (If you need a specific
---- initial value, you may prefix a constant captureto `patt`.) For each subsequent capture, LPeg calls `func`
+--- initial value, you may prefix a constant capture to `patt`.) For each subsequent capture, LPeg calls `func`
 --- with this accumulator as the first argument and all values produced by the capture as extra arguments;
 --- the first result from this call becomes the new value for the accumulator. The final value of the accumulator
 --- becomes the captured value.
@@ -273,7 +276,7 @@ function vim.lpeg.Cc(...) end
 --- assert(sum:match('10,30,43') == 83)
 --- ```
 ---
---- @param patt vim.lpeg.Pattern
+--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function
 --- @param func fun(acc, newvalue)
 --- @return vim.lpeg.Capture
 function vim.lpeg.Cf(patt, func) end
@@ -282,7 +285,7 @@ function vim.lpeg.Cf(patt, func) end
 --- The group may be anonymous (if no name is given) or named with the given name (which
 --- can be any non-nil Lua value).
 ---
---- @param patt vim.lpeg.Pattern
+--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function
 --- @param name? string
 --- @return vim.lpeg.Capture
 function vim.lpeg.Cg(patt, name) end
@@ -320,7 +323,7 @@ function vim.lpeg.Cp() end
 --- assert(gsub('Hello, xxx!', 'xxx', 'World') == 'Hello, World!')
 --- ```
 ---
---- @param patt vim.lpeg.Pattern
+--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function
 --- @return vim.lpeg.Capture
 function vim.lpeg.Cs(patt) end
 
@@ -329,7 +332,7 @@ function vim.lpeg.Cs(patt) end
 --- Moreover, for each named capture group created by `patt`, the first value of the group is put into
 --- the table with the group name as its key. The captured value is only the table.
 ---
---- @param patt vim.lpeg.Pattern|''
+--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function
 --- @return vim.lpeg.Capture
 function vim.lpeg.Ct(patt) end
 
@@ -343,7 +346,7 @@ function vim.lpeg.Ct(patt) end
 --- (so, to return true is equivalent to return `i`). If the call returns `false`, `nil`, or no value, the match fails.
 --- Any extra values returned by the function become the values produced by the capture.
 ---
---- @param patt vim.lpeg.Pattern
---- @param fn function
+--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function
+--- @param fn fun(s: string, i: integer, ...: any): (position: boolean|integer, ...: any)
 --- @return vim.lpeg.Capture
 function vim.lpeg.Cmt(patt, fn) end
-- 
cgit 


From c2b51e6c41c5230af21dc4d978e896ef9e8b922a Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 16 Jul 2024 06:24:02 +0800
Subject: vim-patch:df62c62: runtime(doc): grammar fixes in options.txt
 (#29729)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

closes: vim/vim#15265

https://github.com/vim/vim/commit/df62c62177bd4dffce880b7a5711594865090953

Co-authored-by: Dominique Pellé 
---
 runtime/lua/vim/_meta/options.lua | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 332dbda6e9..25654e287d 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -544,7 +544,7 @@ vim.wo.bri = vim.wo.breakindent
 --- 		    applying 'breakindent', even if the resulting
 --- 		    text should normally be narrower. This prevents
 --- 		    text indented almost to the right window border
---- 		    occupying lot of vertical space when broken.
+--- 		    occupying lots of vertical space when broken.
 --- 		    (default: 20)
 --- 	shift:{n}   After applying 'breakindent', the wrapped line's
 --- 		    beginning will be shifted by the given number of
@@ -3340,7 +3340,7 @@ vim.go.is = vim.go.incsearch
 --- in Insert mode as specified with the 'indentkeys' option.
 --- When this option is not empty, it overrules the 'cindent' and
 --- 'smartindent' indenting.  When 'lisp' is set, this option is
---- is only used when 'lispoptions' contains "expr:1".
+--- only used when 'lispoptions' contains "expr:1".
 --- The expression is evaluated with `v:lnum` set to the line number for
 --- which the indent is to be computed.  The cursor is also in this line
 --- when the expression is evaluated (but it may be moved around).
@@ -3641,7 +3641,7 @@ vim.go.kp = vim.go.keywordprg
 --- part can be in one of two forms:
 --- 1.  A list of pairs.  Each pair is a "from" character immediately
 ---     followed by the "to" character.  Examples: "aA", "aAbBcC".
---- 2.  A list of "from" characters, a semi-colon and a list of "to"
+--- 2.  A list of "from" characters, a semicolon and a list of "to"
 ---     characters.  Example: "abc;ABC"
 --- Example: "aA,fgh;FGH,cCdDeE"
 --- Special characters need to be preceded with a backslash.  These are
@@ -3733,7 +3733,7 @@ vim.go.ls = vim.go.laststatus
 --- update use `:redraw`.
 --- This may occasionally cause display errors.  It is only meant to be set
 --- temporarily when performing an operation where redrawing may cause
---- flickering or cause a slow down.
+--- flickering or cause a slowdown.
 ---
 --- @type boolean
 vim.o.lazyredraw = false
@@ -4787,7 +4787,7 @@ vim.go.pm = vim.go.patchmode
 --- ```
 --- To use an environment variable, you probably need to replace the
 --- separator.  Here is an example to append $INCL, in which directory
---- names are separated with a semi-colon:
+--- names are separated with a semicolon:
 ---
 --- ```vim
 --- 	let &path = &path .. "," .. substitute($INCL, ';', ',', 'g')
@@ -5794,7 +5794,7 @@ vim.bo.shiftwidth = vim.o.shiftwidth
 vim.bo.sw = vim.bo.shiftwidth
 
 --- This option helps to avoid all the `hit-enter` prompts caused by file
---- messages, for example  with CTRL-G, and to avoid some other messages.
+--- messages, for example with CTRL-G, and to avoid some other messages.
 --- It is a list of flags:
 ---  flag	meaning when present	~
 ---   l	use "999L, 888B" instead of "999 lines, 888 bytes"	*shm-l*
@@ -6283,7 +6283,7 @@ vim.bo.spo = vim.bo.spelloptions
 --- 		minus two.
 ---
 --- timeout:{millisec}   Limit the time searching for suggestions to
---- 		{millisec} milli seconds.  Applies to the following
+--- 		{millisec} milliseconds.  Applies to the following
 --- 		methods.  When omitted the limit is 5000. When
 --- 		negative there is no limit.
 ---
-- 
cgit 


From 25db0a1385377ec28fd6e4ca3553c79ce5cb80e4 Mon Sep 17 00:00:00 2001
From: altermo <107814000+altermo@users.noreply.github.com>
Date: Tue, 16 Jul 2024 05:09:24 +0200
Subject: fix(tohtml): extmark text may be out of bounds

---
 runtime/lua/tohtml.lua | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua
index 37ad60b436..7bb4a26ad6 100644
--- a/runtime/lua/tohtml.lua
+++ b/runtime/lua/tohtml.lua
@@ -519,9 +519,12 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces)
   --- @type integer,integer
   local row, col = extmark[2], extmark[3]
   if
-    extmark[4].virt_text_pos == 'inline'
-    or extmark[4].virt_text_pos == 'eol'
-    or extmark[4].virt_text_pos == 'overlay'
+    row < state.buflen
+    and (
+      extmark[4].virt_text_pos == 'inline'
+      or extmark[4].virt_text_pos == 'eol'
+      or extmark[4].virt_text_pos == 'overlay'
+    )
   then
     if extmark[4].virt_text_pos == 'eol' then
       style_line_insert_virt_text(styletable[row + 1], #vim.fn.getline(row + 1) + 1, { ' ' })
@@ -1144,7 +1147,13 @@ local function extend_pre(out, state)
     local line = vim.api.nvim_buf_get_lines(state.bufnr, row - 1, row, false)[1] or ''
     local s = ''
     s = s .. _pre_text_to_html(state, row)
-    for col = 1, #line + 1 do
+    local true_line_len = #line + 1
+    for k in pairs(style_line) do
+      if type(k) == 'number' and k > true_line_len then
+        true_line_len = k
+      end
+    end
+    for col = 1, true_line_len do
       local cell = style_line[col]
       --- @type table?
       local char
@@ -1191,7 +1200,7 @@ local function extend_pre(out, state)
         char = cell[4][#cell[4]]
       end
 
-      if col == #line + 1 and not char then
+      if col == true_line_len and not char then
         break
       end
 
-- 
cgit 


From 118ae7e5ed6cfab6a49ec70c21da2b850161289c Mon Sep 17 00:00:00 2001
From: altermo <107814000+altermo@users.noreply.github.com>
Date: Thu, 11 Jul 2024 18:16:51 +0200
Subject: fix(tohtml): support ranges again

---
 runtime/lua/tohtml.lua | 90 ++++++++++++++++++++++++++++----------------------
 1 file changed, 51 insertions(+), 39 deletions(-)

(limited to 'runtime/lua')

diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua
index 7bb4a26ad6..a4b5a741bc 100644
--- a/runtime/lua/tohtml.lua
+++ b/runtime/lua/tohtml.lua
@@ -1,6 +1,6 @@
 --- @brief
 ---
help
----:TOhtml {file}                                                       *:TOhtml*
+---:[range]TOhtml {file}                                                *:TOhtml*
 ---Converts the buffer shown in the current window to HTML, opens the generated
 ---HTML in a new split window, and saves its contents to {file}. If {file} is not
 ---given, a temporary file (created by |tempname()|) is used.
@@ -40,7 +40,8 @@
 --- @field winid integer
 --- @field bufnr integer
 --- @field width integer
---- @field buflen integer
+--- @field start integer
+--- @field end_ integer
 
 --- @class (private) vim.tohtml.styletable
 --- @field [integer] vim.tohtml.line (integer: (1-index, exclusive))
@@ -393,7 +394,7 @@ end
 
 --- @param state vim.tohtml.state
 local function styletable_syntax(state)
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     local prev_id = 0
     local prev_col = nil
     for col = 1, #vim.fn.getline(row) + 1 do
@@ -413,7 +414,7 @@ end
 --- @param state vim.tohtml.state
 local function styletable_diff(state)
   local styletable = state.style
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     local style_line = styletable[row]
     local filler = vim.fn.diff_filler(row)
     if filler ~= 0 then
@@ -423,7 +424,7 @@ local function styletable_diff(state)
         { { fill:rep(state.width), register_hl(state, 'DiffDelete') } }
       )
     end
-    if row == state.buflen + 1 then
+    if row == state.end_ + 1 then
       break
     end
     local prev_id = 0
@@ -465,7 +466,9 @@ local function styletable_treesitter(state)
     if not query then
       return
     end
-    for capture, node, metadata in query:iter_captures(root, buf_highlighter.bufnr, 0, state.buflen) do
+    for capture, node, metadata in
+      query:iter_captures(root, buf_highlighter.bufnr, state.start - 1, state.end_)
+    do
       local srow, scol, erow, ecol = node:range()
       --- @diagnostic disable-next-line: invisible
       local c = q._query.captures[capture]
@@ -519,7 +522,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces)
   --- @type integer,integer
   local row, col = extmark[2], extmark[3]
   if
-    row < state.buflen
+    row < vim.api.nvim_buf_line_count(state.bufnr)
     and (
       extmark[4].virt_text_pos == 'inline'
       or extmark[4].virt_text_pos == 'eol'
@@ -628,7 +631,7 @@ end
 local function styletable_folds(state)
   local styletable = state.style
   local has_folded = false
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     if vim.fn.foldclosed(row) > 0 then
       has_folded = true
       styletable[row].hide = true
@@ -650,7 +653,7 @@ end
 local function styletable_conceal(state)
   local bufnr = state.bufnr
   vim._with({ buf = bufnr }, function()
-    for row = 1, state.buflen do
+    for row = state.start, state.end_ do
       --- @type table
       local conceals = {}
       local line_len_exclusive = #vim.fn.getline(row) + 1
@@ -768,7 +771,7 @@ local function styletable_statuscolumn(state)
       local max = tonumber(foldcolumn:match('^%w-:(%d)')) or 1
       local maxfold = 0
       vim._with({ buf = state.bufnr }, function()
-        for row = 1, vim.api.nvim_buf_line_count(state.bufnr) do
+        for row = state.start, state.end_ do
           local foldlevel = vim.fn.foldlevel(row)
           if foldlevel > maxfold then
             maxfold = foldlevel
@@ -783,7 +786,7 @@ local function styletable_statuscolumn(state)
 
   --- @type table
   local statuses = {}
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     local status = vim.api.nvim_eval_statusline(
       statuscolumn,
       { winid = state.winid, use_statuscol_lnum = row, highlights = true }
@@ -833,7 +836,7 @@ local function styletable_listchars(state)
   })
 
   if listchars.eol then
-    for row = 1, state.buflen do
+    for row = state.start, state.end_ do
       local style_line = state.style[row]
       style_line_insert_overlay_char(
         style_line,
@@ -1127,16 +1130,22 @@ end
 local function extend_pre(out, state)
   local styletable = state.style
   table.insert(out, '
')
+  local out_start = #out
   local hide_count = 0
   --- @type integer[]
   local stack = {}
 
+  local before = ''
+  local after = ''
   local function loop(row)
+    local inside = row <= state.end_ and row >= state.start
     local style_line = styletable[row]
     if style_line.hide and (styletable[row - 1] or {}).hide then
       return
     end
-    _extend_virt_lines(out, state, row)
+    if inside then
+      _extend_virt_lines(out, state, row)
+    end
     --Possible improvement (altermo):
     --Instead of looping over all the buffer characters per line,
     --why not loop over all the style_line cells,
@@ -1146,7 +1155,9 @@ local function extend_pre(out, state)
     end
     local line = vim.api.nvim_buf_get_lines(state.bufnr, row - 1, row, false)[1] or ''
     local s = ''
-    s = s .. _pre_text_to_html(state, row)
+    if inside then
+      s = s .. _pre_text_to_html(state, row)
+    end
     local true_line_len = #line + 1
     for k in pairs(style_line) do
       if type(k) == 'number' and k > true_line_len then
@@ -1193,7 +1204,7 @@ local function extend_pre(out, state)
           end
         end
 
-        if cell[3] then
+        if cell[3] and inside then
           s = s .. _virt_text_to_html(state, cell)
         end
 
@@ -1204,7 +1215,7 @@ local function extend_pre(out, state)
         break
       end
 
-      if hide_count == 0 then
+      if hide_count == 0 and inside then
         s = s
           .. _char_to_html(
             state,
@@ -1213,12 +1224,20 @@ local function extend_pre(out, state)
           )
       end
     end
-    table.insert(out, s)
+    if row > state.end_ + 1 then
+      after = after .. s
+    elseif row < state.start then
+      before = s .. before
+    else
+      table.insert(out, s)
+    end
   end
 
-  for row = 1, state.buflen + 1 do
+  for row = 1, vim.api.nvim_buf_line_count(state.bufnr) + 1 do
     loop(row)
   end
+  out[out_start] = out[out_start] .. before
+  out[#out] = out[#out] .. after
   assert(#stack == 0, 'an open HTML tag was never closed')
   table.insert(out, '
') end @@ -1250,6 +1269,7 @@ local function global_state_to_state(winid, global_state) if not width or width < 1 then width = vim.api.nvim_win_get_width(winid) end + local range = opt.range or { 1, vim.api.nvim_buf_line_count(bufnr) } local state = setmetatable({ winid = winid == 0 and vim.api.nvim_get_current_win() or winid, opt = vim.wo[winid], @@ -1257,7 +1277,8 @@ local function global_state_to_state(winid, global_state) bufnr = bufnr, tabstop = (' '):rep(vim.bo[bufnr].tabstop), width = width, - buflen = vim.api.nvim_buf_line_count(bufnr), + start = range[1], + end_ = range[2], }, { __index = global_state }) return state --[[@as vim.tohtml.state]] end @@ -1316,35 +1337,22 @@ local function state_generate_style(state) end) end ---- @param winid integer[]|integer +--- @param winid integer --- @param opt? vim.tohtml.opt --- @return string[] local function win_to_html(winid, opt) - if type(winid) == 'number' then - winid = { winid } - end - --- @cast winid integer[] - assert(#winid > 0, 'no window specified') opt = opt or {} - local title = table.concat( - vim.tbl_map(vim.api.nvim_buf_get_name, vim.tbl_map(vim.api.nvim_win_get_buf, winid)), - ',' - ) + local title = vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(winid)) + local global_state = opt_to_global_state(opt, title) - --- @type vim.tohtml.state[] - local states = {} - for _, i in ipairs(winid) do - local state = global_state_to_state(i, global_state) - state_generate_style(state) - table.insert(states, state) - end + local state = global_state_to_state(winid, global_state) + state_generate_style(state) + local html = {} extend_html(html, function() extend_head(html, global_state) extend_body(html, function() - for _, state in ipairs(states) do - extend_pre(html, state) - end + extend_pre(html, state) end) end) return html @@ -1371,6 +1379,10 @@ local M = {} --- infinitely. --- (default: 'textwidth' if non-zero or window width otherwise) --- @field width? integer +--- +--- Range of rows to use. +--- (default: entire buffer) +--- @field range? integer[] --- Converts the buffer shown in the window {winid} to HTML and returns the output as a list of string. --- @param winid? integer Window to convert (defaults to current window) -- cgit From 5fe4ce6678c0b531487e4d9836774464b5ec56ed Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Tue, 16 Jul 2024 10:30:22 -0700 Subject: fix(snippet): modify base indentation when there's actually whitespace (#29670) --- runtime/lua/vim/snippet.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index a880bf0197..af7e3c6d33 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -514,7 +514,7 @@ function M.expand(input) local snippet_lines = text_to_lines(snippet_text) -- Get the base indentation based on the current line and the last line of the snippet. if #snippet_lines > 0 then - base_indent = base_indent .. (snippet_lines[#snippet_lines]:match('(^%s*)%S') or '') --- @type string + base_indent = base_indent .. (snippet_lines[#snippet_lines]:match('(^%s+)%S') or '') --- @type string end local shiftwidth = vim.fn.shiftwidth() -- cgit From 1f2f460b4a77a8ff58872e03c071b5d0d882dd44 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Tue, 16 Jul 2024 10:48:54 -0700 Subject: fix(lsp): don't show codelens for buffers that don't support it (#29690) --- runtime/lua/vim/lsp.lua | 13 ++++++++++--- runtime/lua/vim/lsp/codelens.lua | 8 +++++++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 382ec58156..168172f345 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -855,17 +855,20 @@ api.nvim_create_autocmd('VimLeavePre', { ---@param params table|nil Parameters to send to the server ---@param handler? lsp.Handler See |lsp-handler| --- If nil, follows resolution strategy defined in |lsp-handler-configuration| ---- +---@param on_unsupported? fun() +--- The function to call when the buffer has no clients that support the given method. +--- Defaults to an `ERROR` level notification. ---@return table client_request_ids Map of client-id:request-id pairs ---for all successful requests. ---@return function _cancel_all_requests Function which can be used to ---cancel all the requests. You could instead ---iterate all clients and call their `cancel_request()` methods. -function lsp.buf_request(bufnr, method, params, handler) +function lsp.buf_request(bufnr, method, params, handler, on_unsupported) validate({ bufnr = { bufnr, 'n', true }, method = { method, 's' }, handler = { handler, 'f', true }, + on_unsupported = { on_unsupported, 'f', true }, }) bufnr = resolve_bufnr(bufnr) @@ -887,7 +890,11 @@ function lsp.buf_request(bufnr, method, params, handler) -- if has client but no clients support the given method, notify the user if next(clients) and not method_supported then - vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR) + if on_unsupported == nil then + vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR) + else + on_unsupported() + end vim.cmd.redraw() return {}, function() end end diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index c85bb6aa32..c1b6bfb28c 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -307,7 +307,13 @@ function M.refresh(opts) } active_refreshes[buf] = true - local request_ids = vim.lsp.buf_request(buf, ms.textDocument_codeLens, params, M.on_codelens) + local request_ids = vim.lsp.buf_request( + buf, + ms.textDocument_codeLens, + params, + M.on_codelens, + function() end + ) if vim.tbl_isempty(request_ids) then active_refreshes[buf] = nil end -- cgit From 4a7371c71486653253ae440a9a4017768ad36262 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 16 Jul 2024 22:22:18 +0200 Subject: vim-patch:9.1.0591: filetype: *.wl files are not recognized Problem: filetype: *.wl files are not recognized Solution: Detect '*.wl' files as Mathematica package files (Jonas Dujava) closes: vim/vim#15269 https://github.com/vim/vim/commit/c6d7dc039342fbe1cf432c7f8e7e391063de210b Co-authored-by: Jonas Dujava --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 08451735b6..bbe24a6e06 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -711,6 +711,7 @@ local extension = { mixal = 'mix', mm = detect.mm, nb = 'mma', + wl = 'mma', mmp = 'mmp', mms = detect.mms, DEF = 'modula2', -- cgit From 61ea4665916909853cf74256a6b350a680f08565 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 16 Jul 2024 22:23:44 +0200 Subject: vim-patch:9.1.0592: runtime: filetype: Mediawiki files are not recognized Problem: filetype: Mediawiki files are not recognized Solution: detect "*.mw" and "*.wiki" as mediawiki filetype, include basic syntax and filetype plugins. (AvidSeeker) closes: vim/vim#15266 https://github.com/vim/vim/commit/b5844104ab1259e061e023ea6259e4eb002e7170 Co-authored-by: AvidSeeker --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index bbe24a6e06..aa406b229e 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -698,6 +698,8 @@ local extension = { dm3 = 'maxima', dmt = 'maxima', wxm = 'maxima', + mw = 'mediawiki', + wiki = 'mediawiki', mel = 'mel', mmd = 'mermaid', mmdc = 'mermaid', -- cgit From 8e590cae83c321445a598fcd87bb31b6187402f7 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 16 Jul 2024 22:29:39 +0200 Subject: vim-patch:9.1.0593: filetype: Asymptote files are not recognized Problem: filetype: Asymptote files are not recognized Solution: detect '*.asy' files as asy filetype, include ftplugin and syntax plugin (AvidSeeker). Reference: https://asymptote.sourceforge.io/ closes: vim/vim#15252 https://github.com/vim/vim/commit/3088ef094da721dac8c0363a6c9e14eaf9313929 Co-authored-by: AvidSeeker --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index aa406b229e..99c5e037e5 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -214,6 +214,7 @@ local extension = { asn = 'asn', asp = detect.asp, astro = 'astro', + asy = 'asy', atl = 'atlas', as = 'atlas', zed = 'authzed', -- cgit From 05dcda8f9b0583505327692570a2cfd0225124dc Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 14 Jul 2024 08:10:19 -0700 Subject: fix(treesitter): recognize aliased parsers in omnifunc, query linter **Problem:** A query file for something like `html_tags` will not be given html node completion **Solution:** Check for parser aliases before offering completions Co-authored-by: Lewis Russell --- runtime/lua/vim/treesitter/_query_linter.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index 12b4cbc7b9..6b8c3a17f2 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -40,7 +40,8 @@ end local function guess_query_lang(buf) local filename = api.nvim_buf_get_name(buf) if filename ~= '' then - return vim.F.npcall(vim.fn.fnamemodify, filename, ':p:h:t') + local resolved_filename = vim.F.npcall(vim.fn.fnamemodify, filename, ':p:h:t') + return resolved_filename and vim.treesitter.language.get_lang(resolved_filename) or nil end end -- cgit From e29f245a10821fcce454f7ede684aa0dd64efc33 Mon Sep 17 00:00:00 2001 From: Amit Singh <29333147+amitds1997@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:14:53 +0530 Subject: fix(lsp): inlay hints are rendered in the correct order (#29707) Problem: When there are multiple inlay hints present at the same position, they should be rendered in the order they are received in the response from LSP as per the LSP spec. Currently, this is not respected. Solution: Gather all hints for a given position, and then set it in a single extmark call instead of multiple set_extmark calls. This leads to fewer extmark calls and correct inlay hints being rendered. --- runtime/lua/vim/lsp/inlay_hint.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index aa84294cc4..1e224d1bef 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -336,6 +336,8 @@ api.nvim_set_decoration_provider(namespace, { for lnum = topline, botline do if bufstate.applied[lnum] ~= bufstate.version then api.nvim_buf_clear_namespace(bufnr, namespace, lnum, lnum + 1) + + local hint_virtual_texts = {} --- @type table for _, lnum_hints in pairs(client_hints) do local hints = lnum_hints[lnum] or {} for _, hint in pairs(hints) do @@ -348,7 +350,7 @@ api.nvim_set_decoration_provider(namespace, { text = text .. part.value end end - local vt = {} --- @type [string, string?][] + local vt = hint_virtual_texts[hint.position.character] or {} if hint.paddingLeft then vt[#vt + 1] = { ' ' } end @@ -356,13 +358,18 @@ api.nvim_set_decoration_provider(namespace, { if hint.paddingRight then vt[#vt + 1] = { ' ' } end - api.nvim_buf_set_extmark(bufnr, namespace, lnum, hint.position.character, { - virt_text_pos = 'inline', - ephemeral = false, - virt_text = vt, - }) + hint_virtual_texts[hint.position.character] = vt end end + + for pos, vt in pairs(hint_virtual_texts) do + api.nvim_buf_set_extmark(bufnr, namespace, lnum, pos, { + virt_text_pos = 'inline', + ephemeral = false, + virt_text = vt, + }) + end + bufstate.applied[lnum] = bufstate.version end end -- cgit From 18f1a3aaa5e28421ebe631346e5cca6f75c9b104 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 18 Jul 2024 08:08:56 +0800 Subject: vim-patch:c1b3984: runtime(doc): minor updates. (#29778) closes: vim/vim#15280 https://github.com/vim/vim/commit/c1b3984a7b3cd6adcd1f43e558cb04fad1af3182 Co-authored-by: Shane Harper --- runtime/lua/vim/_meta/vimfn.lua | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 750f16ef06..b68a16d014 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -203,16 +203,17 @@ function vim.fn.assert_beeps(cmd) end --- added to |v:errors| and 1 is returned. Otherwise zero is --- returned. |assert-return| --- The error is in the form "Expected {expected} but got ---- {actual}". When {msg} is present it is prefixed to that. +--- {actual}". When {msg} is present it is prefixed to that, along +--- with the location of the assert when run from a script. --- --- There is no automatic conversion, the String "4" is different --- from the Number 4. And the number 4 is different from the --- Float 4.0. The value of 'ignorecase' is not used here, case --- always matters. --- Example: >vim ---- assert_equal('foo', 'bar') ---- Date: Thu, 18 Jul 2024 09:13:16 +0200 Subject: vim-patch:9.1.0596: filetype: devscripts config files are not recognized (#29773) Problem: filetype: Debian devscripts config files are not recognized Solution: detect devscripts.conf and .devscripts files as sh filetype (sourced by /bin/sh) closes: vim/vim#15227 https://github.com/vim/vim/commit/76c19028ffc8b00816df7bc48985c92f7bacbcfb Co-authored-by: Wu, Zhenyu --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 99c5e037e5..834eb9e89c 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1626,6 +1626,8 @@ local filename = { ['/etc/serial.conf'] = 'setserial', ['/etc/udev/cdsymlinks.conf'] = 'sh', ['.ash_history'] = 'sh', + ['.devscripts'] = 'sh', + ['devscripts.conf'] = 'sh', ['makepkg.conf'] = 'sh', ['.makepkg.conf'] = 'sh', ['user-dirs.dirs'] = 'sh', -- cgit From f61efe3fe77c9a517dccb9fd5ff7f16c0660ced4 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Thu, 18 Jul 2024 18:26:27 +0300 Subject: perf(filetype): implement parent pattern pre-matching (#29660) Problem: calling `vim.filetype.match()` has performance bottleneck in that it has to match a lot of Lua patterns against several versions of input file name. This might be the problem if users need to call it synchronously a lot of times. Solution: add "parent pattern pre-matching" which can be used to quickly reject several potential pattern matches at (usually rare) cost of adding time for one extra Lua pattern match. "Parent pattern" is a manually added/tracked grouping of filetype patterns which should have two properties: - Match at least the same set of strings as its filetype patterns. But not too much more. - Be fast to match. For them to be effective, group should consist from at least three filetype patterns. Example: for a filetpye pattern ".*/etc/a2ps/.*%.cfg", both "/etc/" and "%.cfg" are good parent patterns (prefer the one which can group more filetype patterns). After this commit, `vim.filetype.match()` on most inputs runs ~3.4 times faster (while some inputs may see less impact if they match many parent patterns). --- runtime/lua/vim/filetype.lua | 1115 +++++++++++++++++++++++------------------- 1 file changed, 605 insertions(+), 510 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 834eb9e89c..b497485b53 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -4,12 +4,13 @@ local fn = vim.fn local M = {} --- @alias vim.filetype.mapfn fun(path:string,bufnr:integer, ...):string?, fun(b:integer)? ---- @alias vim.filetype.maptbl [string|vim.filetype.mapfn, {priority:integer}] +--- @alias vim.filetype.mapopts { parent: string, priority: number } +--- @alias vim.filetype.maptbl [string|vim.filetype.mapfn, vim.filetype.mapopts] --- @alias vim.filetype.mapping.value string|vim.filetype.mapfn|vim.filetype.maptbl --- @alias vim.filetype.mapping table --- @param ft string|vim.filetype.mapfn ---- @param opts? {priority:integer} +--- @param opts? vim.filetype.mapopts --- @return vim.filetype.maptbl local function starsetf(ft, opts) return { @@ -26,6 +27,9 @@ local function starsetf(ft, opts) end end, { + -- Allow setting "parent" to be reused in closures, but don't have default as it will be + -- assigned later from grouping + parent = opts and opts.parent, -- Starset matches should have lowest priority by default priority = (opts and opts.priority) or -math.huge, }, @@ -1735,497 +1739,556 @@ local filename = { } -- Re-use closures as much as possible -local detect_apache = starsetf('apache') -local detect_muttrc = starsetf('muttrc') -local detect_neomuttrc = starsetf('neomuttrc') +local detect_apache_diretc = starsetf('apache', { parent = '/etc/' }) +local detect_apache_dotconf = starsetf('apache', { parent = '%.conf' }) +local detect_muttrc = starsetf('muttrc', { parent = 'utt' }) +local detect_neomuttrc = starsetf('neomuttrc', { parent = 'utt' }) +local detect_xkb = starsetf('xkb', { parent = '/usr/' }) +--- Table of filetype pattern matching rules grouped by their parent pattern. +--- +--- Every filetype pattern match is prefaced with a matching of its parent pattern. +--- If there is no match, skip all matching inside group. +--- Note that unlike leaf patterns, parent patterns do not have special matching behaviour if they +--- contain a `/`. +--- +--- When modifying an existing regular pattern, make sure that it still fits its group. +--- --- Vim regexes are converted into explicit Lua patterns (without implicit anchoring): --- '*/debian/changelog' -> '/debian/changelog$' --- '*/bind/db.*' -> '/bind/db%.' ---- @type vim.filetype.mapping +--- @type table local pattern = { -- BEGIN PATTERN - ['/etc/a2ps/.*%.cfg$'] = 'a2ps', - ['/etc/a2ps%.cfg$'] = 'a2ps', - ['/usr/share/alsa/alsa%.conf$'] = 'alsaconf', - ['/etc/asound%.conf$'] = 'alsaconf', - ['/etc/apache2/sites%-.*/.*%.com$'] = 'apache', - ['/etc/httpd/.*%.conf$'] = 'apache', - ['/etc/apache2/.*%.conf'] = detect_apache, - ['/etc/apache2/conf%..*/'] = detect_apache, - ['/etc/apache2/mods%-.*/'] = detect_apache, - ['/etc/apache2/sites%-.*/'] = detect_apache, - ['^access%.conf'] = detect_apache, - ['^apache%.conf'] = detect_apache, - ['^apache2%.conf'] = detect_apache, - ['^httpd%.conf'] = detect_apache, - ['^srm%.conf'] = detect_apache, - ['/etc/httpd/conf%..*/'] = detect_apache, - ['/etc/httpd/conf%.d/.*%.conf'] = detect_apache, - ['/etc/httpd/mods%-.*/'] = detect_apache, - ['/etc/httpd/sites%-.*/'] = detect_apache, - ['/etc/proftpd/.*%.conf'] = starsetf('apachestyle'), - ['/etc/proftpd/conf%..*/'] = starsetf('apachestyle'), - ['^proftpd%.conf'] = starsetf('apachestyle'), - ['asterisk/.*%.conf'] = starsetf('asterisk'), - ['asterisk.*/.*voicemail%.conf'] = starsetf('asteriskvm'), - ['/%.aptitude/config$'] = 'aptconf', - ['^[mM]akefile%.am$'] = 'automake', - ['/bind/db%.'] = starsetf('bindzone'), - ['/named/db%.'] = starsetf('bindzone'), - ['/build/conf/.*%.conf$'] = 'bitbake', - ['/meta/conf/.*%.conf$'] = 'bitbake', - ['/meta%-.*/conf/.*%.conf$'] = 'bitbake', - ['%.blade%.php$'] = 'blade', - ['^bzr_log%.'] = 'bzr', - ['enlightenment/.*%.cfg$'] = 'c', - ['/%.cabal/config$'] = 'cabalconfig', - ['/cabal/config$'] = 'cabalconfig', - ['^cabal%.project%.'] = starsetf('cabalproject'), - ['/%.calendar/'] = starsetf('calendar'), - ['/share/calendar/.*/calendar%.'] = starsetf('calendar'), - ['/share/calendar/calendar%.'] = starsetf('calendar'), - ['^sgml%.catalog'] = starsetf('catalog'), - ['/etc/defaults/cdrdao$'] = 'cdrdaoconf', - ['/etc/cdrdao%.conf$'] = 'cdrdaoconf', - ['/etc/default/cdrdao$'] = 'cdrdaoconf', - ['hgrc$'] = 'cfg', - ['%.[Cc][Ff][Gg]$'] = { - detect.cfg, - -- Decrease priority to avoid conflicts with more specific patterns - -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. - { priority = -1 }, + ['/debian/'] = { + ['/debian/changelog$'] = 'debchangelog', + ['/debian/control$'] = 'debcontrol', + ['/debian/copyright$'] = 'debcopyright', + ['/debian/patches/'] = detect.dep3patch, }, - ['^[cC]hange[lL]og'] = starsetf(detect.changelog), - ['%.%.ch$'] = 'chill', - ['/etc/translate%-shell$'] = 'clojure', - ['%.cmake%.in$'] = 'cmake', - -- */cmus/rc and */.cmus/rc - ['/%.?cmus/rc$'] = 'cmusrc', - -- */cmus/*.theme and */.cmus/*.theme - ['/%.?cmus/.*%.theme$'] = 'cmusrc', - ['/%.cmus/autosave$'] = 'cmusrc', - ['/%.cmus/command%-history$'] = 'cmusrc', - ['/etc/hostname%.'] = starsetf('config'), - ['^crontab%.'] = starsetf('crontab'), - ['/etc/cron%.d/'] = starsetf('crontab'), - ['^%.cshrc'] = detect.csh, - ['^%.login'] = detect.csh, - ['^cvs%d+$'] = 'cvs', - ['%.[Dd][Aa][Tt]$'] = detect.dat, - ['/debian/patches/'] = detect.dep3patch, - ['/etc/dnsmasq%.d/'] = starsetf('dnsmasq'), - ['^Containerfile%.'] = starsetf('dockerfile'), - ['^Dockerfile%.'] = starsetf('dockerfile'), - ['/etc/yum%.repos%.d/'] = starsetf('dosini'), - ['^drac%.'] = starsetf('dracula'), - ['/debian/changelog$'] = 'debchangelog', - ['/debian/control$'] = 'debcontrol', - ['/debian/copyright$'] = 'debcopyright', - ['/etc/apt/sources%.list%.d/.*%.list$'] = 'debsources', - ['/etc/apt/sources%.list$'] = 'debsources', - ['/etc/apt/sources%.list%.d/.*%.sources$'] = 'deb822sources', - ['^dictd.*%.conf$'] = 'dictdconf', - ['/etc/DIR_COLORS$'] = 'dircolors', - ['/etc/dnsmasq%.conf$'] = 'dnsmasq', - ['^php%.ini%-'] = 'dosini', - ['/%.aws/config$'] = 'confini', - ['/%.aws/credentials$'] = 'confini', - ['/etc/yum%.conf$'] = 'dosini', - ['/lxqt/.*%.conf$'] = 'dosini', - ['/screengrab/.*%.conf$'] = 'dosini', - ['/bpython/config$'] = 'dosini', - ['/mypy/config$'] = 'dosini', - ['/flatpak/repo/config$'] = 'dosini', - ['lvs$'] = 'dracula', - ['lpe$'] = 'dracula', - ['/dtrace/.*%.d$'] = 'dtrace', - ['esmtprc$'] = 'esmtprc', - ['Eterm/.*%.cfg$'] = 'eterm', - ['s6.*/up$'] = 'execline', - ['s6.*/down$'] = 'execline', - ['s6.*/run$'] = 'execline', - ['s6.*/finish$'] = 'execline', - ['^s6%-'] = 'execline', - ['^[a-zA-Z0-9].*Dict$'] = detect.foam, - ['^[a-zA-Z0-9].*Dict%.'] = detect.foam, - ['^[a-zA-Z].*Properties$'] = detect.foam, - ['^[a-zA-Z].*Properties%.'] = detect.foam, - ['Transport%.'] = detect.foam, - ['/constant/g$'] = detect.foam, - ['/0/'] = detect.foam, - ['/0%.orig/'] = detect.foam, - ['/%.fvwm/'] = starsetf('fvwm'), - ['fvwmrc'] = starsetf(detect.fvwm_v1), - ['fvwm95.*%.hook$'] = starsetf(detect.fvwm_v1), - ['fvwm2rc'] = starsetf(detect.fvwm_v2), - ['/tmp/lltmp'] = starsetf('gedcom'), - ['/etc/gitconfig%.d/'] = starsetf('gitconfig'), - ['/gitolite%-admin/conf/'] = starsetf('gitolite'), - ['^tmac%.'] = starsetf('nroff'), - ['/%.gitconfig%.d/'] = starsetf('gitconfig'), - ['%.git/'] = { - detect.git, - -- Decrease priority to run after simple pattern checks - { priority = -1 }, + ['/etc/'] = { + ['/etc/a2ps/.*%.cfg$'] = 'a2ps', + ['/etc/a2ps%.cfg$'] = 'a2ps', + ['/etc/asound%.conf$'] = 'alsaconf', + ['/etc/apache2/sites%-.*/.*%.com$'] = 'apache', + ['/etc/httpd/.*%.conf$'] = 'apache', + ['/etc/apache2/.*%.conf'] = detect_apache_diretc, + ['/etc/apache2/conf%..*/'] = detect_apache_diretc, + ['/etc/apache2/mods%-.*/'] = detect_apache_diretc, + ['/etc/apache2/sites%-.*/'] = detect_apache_diretc, + ['/etc/httpd/conf%..*/'] = detect_apache_diretc, + ['/etc/httpd/conf%.d/.*%.conf'] = detect_apache_diretc, + ['/etc/httpd/mods%-.*/'] = detect_apache_diretc, + ['/etc/httpd/sites%-.*/'] = detect_apache_diretc, + ['/etc/proftpd/.*%.conf'] = starsetf('apachestyle'), + ['/etc/proftpd/conf%..*/'] = starsetf('apachestyle'), + ['/etc/cdrdao%.conf$'] = 'cdrdaoconf', + ['/etc/default/cdrdao$'] = 'cdrdaoconf', + ['/etc/defaults/cdrdao$'] = 'cdrdaoconf', + ['/etc/translate%-shell$'] = 'clojure', + ['/etc/hostname%.'] = starsetf('config'), + ['/etc/cron%.d/'] = starsetf('crontab'), + ['/etc/apt/sources%.list%.d/.*%.sources$'] = 'deb822sources', + ['/etc/apt/sources%.list%.d/.*%.list$'] = 'debsources', + ['/etc/apt/sources%.list$'] = 'debsources', + ['/etc/DIR_COLORS$'] = 'dircolors', + ['/etc/dnsmasq%.conf$'] = 'dnsmasq', + ['/etc/dnsmasq%.d/'] = starsetf('dnsmasq'), + ['/etc/yum%.conf$'] = 'dosini', + ['/etc/yum%.repos%.d/'] = starsetf('dosini'), + ['/etc/gitconfig%.d/'] = starsetf('gitconfig'), + ['/etc/gitconfig$'] = 'gitconfig', + ['/etc/gitattributes$'] = 'gitattributes', + ['/etc/group$'] = 'group', + ['/etc/group%-$'] = 'group', + ['/etc/group%.edit$'] = 'group', + ['/etc/gshadow%-$'] = 'group', + ['/etc/gshadow%.edit$'] = 'group', + ['/etc/gshadow$'] = 'group', + ['/etc/grub%.conf$'] = 'grub', + ['/etc/host%.conf$'] = 'hostconf', + ['/etc/hosts%.allow$'] = 'hostsaccess', + ['/etc/hosts%.deny$'] = 'hostsaccess', + ['/etc/initng/.*/.*%.i$'] = 'initng', + ['/etc/libao%.conf$'] = 'libao', + ['/etc/.*limits%.conf$'] = 'limits', + ['/etc/.*limits%.d/.*%.conf$'] = 'limits', + ['/etc/limits$'] = 'limits', + ['/etc/logcheck/.*%.d.*/'] = starsetf('logcheck'), + ['/etc/login%.access$'] = 'loginaccess', + ['/etc/login%.defs$'] = 'logindefs', + ['/etc/aliases$'] = 'mailaliases', + ['/etc/mail/aliases$'] = 'mailaliases', + ['/etc/man%.conf$'] = 'manconf', + ['/etc/conf%.modules$'] = 'modconf', + ['/etc/modprobe%.'] = starsetf('modconf'), + ['/etc/modules%.conf$'] = 'modconf', + ['/etc/modules$'] = 'modconf', + ['/etc/modutils/'] = starsetf(function(path, bufnr) + if fn.executable(fn.expand(path)) ~= 1 then + return 'modconf' + end + end), + ['/etc/Muttrc%.d/'] = starsetf('muttrc'), + ['/etc/nanorc$'] = 'nanorc', + ['/etc/nginx/'] = 'nginx', + ['/etc/pam%.conf$'] = 'pamconf', + ['/etc/pam%.d/'] = starsetf('pamconf'), + ['/etc/passwd%-$'] = 'passwd', + ['/etc/shadow$'] = 'passwd', + ['/etc/shadow%.edit$'] = 'passwd', + ['/etc/passwd$'] = 'passwd', + ['/etc/passwd%.edit$'] = 'passwd', + ['/etc/shadow%-$'] = 'passwd', + ['/etc/pinforc$'] = 'pinfo', + ['/etc/protocols$'] = 'protocols', + ['/etc/sensors%.d/[^.]'] = starsetf('sensors'), + ['/etc/sensors%.conf$'] = 'sensors', + ['/etc/sensors3%.conf$'] = 'sensors', + ['/etc/services$'] = 'services', + ['/etc/serial%.conf$'] = 'setserial', + ['/etc/udev/cdsymlinks%.conf$'] = 'sh', + ['/etc/profile$'] = detect.sh, + ['/etc/slp%.conf$'] = 'slpconf', + ['/etc/slp%.reg$'] = 'slpreg', + ['/etc/slp%.spi$'] = 'slpspi', + ['/etc/sudoers%.d/'] = starsetf('sudoers'), + ['/etc/ssh/ssh_config%.d/.*%.conf$'] = 'sshconfig', + ['/etc/ssh/sshd_config%.d/.*%.conf$'] = 'sshdconfig', + ['/etc/sudoers$'] = 'sudoers', + ['/etc/sysctl%.conf$'] = 'sysctl', + ['/etc/sysctl%.d/.*%.conf$'] = 'sysctl', + ['/etc/systemd/.*%.conf%.d/.*%.conf$'] = 'systemd', + ['/etc/systemd/system/.*%.d/.*%.conf$'] = 'systemd', + ['/etc/systemd/system/.*%.d/%.#'] = 'systemd', + ['/etc/systemd/system/%.#'] = 'systemd', + ['/etc/config/'] = starsetf(detect.uci), + ['/etc/udev/udev%.conf$'] = 'udevconf', + ['/etc/udev/permissions%.d/.*%.permissions$'] = 'udevperm', + ['/etc/updatedb%.conf$'] = 'updatedb', + ['/etc/init/.*%.conf$'] = 'upstart', + ['/etc/init/.*%.override$'] = 'upstart', + ['/etc/xinetd%.conf$'] = 'xinetd', + ['/etc/xinetd%.d/'] = starsetf('xinetd'), + ['/etc/blkid%.tab%.old$'] = 'xml', + ['/etc/blkid%.tab$'] = 'xml', + ['/etc/xdg/menus/.*%.menu$'] = 'xml', + ['/etc/zprofile$'] = 'zsh', + }, + ['/log/'] = { + ['/log/auth%.crit$'] = 'messages', + ['/log/auth%.err$'] = 'messages', + ['/log/auth%.info$'] = 'messages', + ['/log/auth%.log$'] = 'messages', + ['/log/auth%.notice$'] = 'messages', + ['/log/auth%.warn$'] = 'messages', + ['/log/auth$'] = 'messages', + ['/log/cron%.crit$'] = 'messages', + ['/log/cron%.err$'] = 'messages', + ['/log/cron%.info$'] = 'messages', + ['/log/cron%.log$'] = 'messages', + ['/log/cron%.notice$'] = 'messages', + ['/log/cron%.warn$'] = 'messages', + ['/log/cron$'] = 'messages', + ['/log/daemon%.crit$'] = 'messages', + ['/log/daemon%.err$'] = 'messages', + ['/log/daemon%.info$'] = 'messages', + ['/log/daemon%.log$'] = 'messages', + ['/log/daemon%.notice$'] = 'messages', + ['/log/daemon%.warn$'] = 'messages', + ['/log/daemon$'] = 'messages', + ['/log/debug%.crit$'] = 'messages', + ['/log/debug%.err$'] = 'messages', + ['/log/debug%.info$'] = 'messages', + ['/log/debug%.log$'] = 'messages', + ['/log/debug%.notice$'] = 'messages', + ['/log/debug%.warn$'] = 'messages', + ['/log/debug$'] = 'messages', + ['/log/kern%.crit$'] = 'messages', + ['/log/kern%.err$'] = 'messages', + ['/log/kern%.info$'] = 'messages', + ['/log/kern%.log$'] = 'messages', + ['/log/kern%.notice$'] = 'messages', + ['/log/kern%.warn$'] = 'messages', + ['/log/kern$'] = 'messages', + ['/log/lpr%.crit$'] = 'messages', + ['/log/lpr%.err$'] = 'messages', + ['/log/lpr%.info$'] = 'messages', + ['/log/lpr%.log$'] = 'messages', + ['/log/lpr%.notice$'] = 'messages', + ['/log/lpr%.warn$'] = 'messages', + ['/log/lpr$'] = 'messages', + ['/log/mail%.crit$'] = 'messages', + ['/log/mail%.err$'] = 'messages', + ['/log/mail%.info$'] = 'messages', + ['/log/mail%.log$'] = 'messages', + ['/log/mail%.notice$'] = 'messages', + ['/log/mail%.warn$'] = 'messages', + ['/log/mail$'] = 'messages', + ['/log/messages%.crit$'] = 'messages', + ['/log/messages%.err$'] = 'messages', + ['/log/messages%.info$'] = 'messages', + ['/log/messages%.log$'] = 'messages', + ['/log/messages%.notice$'] = 'messages', + ['/log/messages%.warn$'] = 'messages', + ['/log/messages$'] = 'messages', + ['/log/news/news%.crit$'] = 'messages', + ['/log/news/news%.err$'] = 'messages', + ['/log/news/news%.info$'] = 'messages', + ['/log/news/news%.log$'] = 'messages', + ['/log/news/news%.notice$'] = 'messages', + ['/log/news/news%.warn$'] = 'messages', + ['/log/news/news$'] = 'messages', + ['/log/syslog%.crit$'] = 'messages', + ['/log/syslog%.err$'] = 'messages', + ['/log/syslog%.info$'] = 'messages', + ['/log/syslog%.log$'] = 'messages', + ['/log/syslog%.notice$'] = 'messages', + ['/log/syslog%.warn$'] = 'messages', + ['/log/syslog$'] = 'messages', + ['/log/user%.crit$'] = 'messages', + ['/log/user%.err$'] = 'messages', + ['/log/user%.info$'] = 'messages', + ['/log/user%.log$'] = 'messages', + ['/log/user%.notice$'] = 'messages', + ['/log/user%.warn$'] = 'messages', + ['/log/user$'] = 'messages', + }, + ['/systemd/'] = { + ['/%.config/systemd/user/%.#'] = 'systemd', + ['/%.config/systemd/user/.*%.d/%.#'] = 'systemd', + ['/%.config/systemd/user/.*%.d/.*%.conf$'] = 'systemd', + ['/systemd/.*%.automount$'] = 'systemd', + ['/systemd/.*%.dnssd$'] = 'systemd', + ['/systemd/.*%.link$'] = 'systemd', + ['/systemd/.*%.mount$'] = 'systemd', + ['/systemd/.*%.netdev$'] = 'systemd', + ['/systemd/.*%.network$'] = 'systemd', + ['/systemd/.*%.nspawn$'] = 'systemd', + ['/systemd/.*%.path$'] = 'systemd', + ['/systemd/.*%.service$'] = 'systemd', + ['/systemd/.*%.slice$'] = 'systemd', + ['/systemd/.*%.socket$'] = 'systemd', + ['/systemd/.*%.swap$'] = 'systemd', + ['/systemd/.*%.target$'] = 'systemd', + ['/systemd/.*%.timer$'] = 'systemd', + }, + ['/usr/'] = { + ['/usr/share/alsa/alsa%.conf$'] = 'alsaconf', + ['/usr/.*/gnupg/options%.skel$'] = 'gpg', + ['/usr/share/upstart/.*%.conf$'] = 'upstart', + ['/usr/share/upstart/.*%.override$'] = 'upstart', + ['/usr/share/X11/xkb/compat/'] = detect_xkb, + ['/usr/share/X11/xkb/geometry/'] = detect_xkb, + ['/usr/share/X11/xkb/keycodes/'] = detect_xkb, + ['/usr/share/X11/xkb/symbols/'] = detect_xkb, + ['/usr/share/X11/xkb/types/'] = detect_xkb, + }, + ['/var/'] = { + ['/var/backups/group%.bak$'] = 'group', + ['/var/backups/gshadow%.bak$'] = 'group', + ['/var/backups/passwd%.bak$'] = 'passwd', + ['/var/backups/shadow%.bak$'] = 'passwd', + }, + ['/conf'] = { + ['/%.aptitude/config$'] = 'aptconf', + ['/build/conf/.*%.conf$'] = 'bitbake', + ['/meta%-.*/conf/.*%.conf$'] = 'bitbake', + ['/meta/conf/.*%.conf$'] = 'bitbake', + ['/%.cabal/config$'] = 'cabalconfig', + ['/cabal/config$'] = 'cabalconfig', + ['/%.aws/config$'] = 'confini', + ['/bpython/config$'] = 'dosini', + ['/flatpak/repo/config$'] = 'dosini', + ['/mypy/config$'] = 'dosini', + ['^${XDG_CONFIG_HOME}/git/config$'] = 'gitconfig', + ['%.git/config%.worktree$'] = 'gitconfig', + ['%.git/config$'] = 'gitconfig', + ['%.git/modules/.*/config$'] = 'gitconfig', + ['%.git/modules/config$'] = 'gitconfig', + ['%.git/worktrees/.*/config%.worktree$'] = 'gitconfig', + ['/%.config/git/config$'] = 'gitconfig', + ['/gitolite%-admin/conf/'] = starsetf('gitolite'), + ['/%.i3/config$'] = 'i3config', + ['/i3/config$'] = 'i3config', + ['/supertux2/config$'] = 'lisp', + ['/%.mplayer/config$'] = 'mplayerconf', + ['/neofetch/config%.conf$'] = 'sh', + ['/%.ssh/config$'] = 'sshconfig', + ['/%.sway/config$'] = 'swayconfig', + ['/sway/config$'] = 'swayconfig', + ['/%.cargo/config$'] = 'toml', + ['/%.bundle/config$'] = 'yaml', + }, + ['/%.'] = { + ['/%.aws/credentials$'] = 'confini', + ['/%.gitconfig%.d/'] = starsetf('gitconfig'), + ['/%.gnupg/gpg%.conf$'] = 'gpg', + ['/%.gnupg/options$'] = 'gpg', + ['/%.icewm/menu$'] = 'icemenu', + ['/%.libao$'] = 'libao', + ['/%.pinforc$'] = 'pinfo', + ['/%.cargo/credentials$'] = 'toml', + ['/%.init/.*%.override$'] = 'upstart', + }, + ['calendar/'] = { + ['/%.calendar/'] = starsetf('calendar'), + ['/share/calendar/.*/calendar%.'] = starsetf('calendar'), + ['/share/calendar/calendar%.'] = starsetf('calendar'), + }, + ['cmus/'] = { + -- */cmus/*.theme and */.cmus/*.theme + ['/%.?cmus/.*%.theme$'] = 'cmusrc', + -- */cmus/rc and */.cmus/rc + ['/%.?cmus/rc$'] = 'cmusrc', + ['/%.cmus/autosave$'] = 'cmusrc', + ['/%.cmus/command%-history$'] = 'cmusrc', + }, + ['git/'] = { + ['%.git/'] = { + detect.git, + -- Decrease priority to run after simple pattern checks + { priority = -1 }, + }, + ['^${XDG_CONFIG_HOME}/git/attributes$'] = 'gitattributes', + ['%.git/info/attributes$'] = 'gitattributes', + ['/%.config/git/attributes$'] = 'gitattributes', + ['^${XDG_CONFIG_HOME}/git/ignore$'] = 'gitignore', + ['%.git/info/exclude$'] = 'gitignore', + ['/%.config/git/ignore$'] = 'gitignore', + }, + ['bash'] = { + ['^%.bash[_%-]aliases$'] = detect.bash, + ['^%.bash[_%-]history$'] = detect.bash, + ['^%.bash[_%-]logout$'] = detect.bash, + ['^%.bash[_%-]profile$'] = detect.bash, + ['^bash%-fc[%-%.]'] = detect.bash, + }, + ['%.cfg'] = { + ['enlightenment/.*%.cfg$'] = 'c', + ['Eterm/.*%.cfg$'] = 'eterm', + ['baseq[2-3]/.*%.cfg$'] = 'quake', + ['id1/.*%.cfg$'] = 'quake', + ['quake[1-3]/.*%.cfg$'] = 'quake', + ['/tex/latex/.*%.cfg$'] = 'tex', + }, + ['%.conf'] = { + ['^proftpd%.conf'] = starsetf('apachestyle'), + ['^access%.conf'] = detect_apache_dotconf, + ['^apache%.conf'] = detect_apache_dotconf, + ['^apache2%.conf'] = detect_apache_dotconf, + ['^httpd%.conf'] = detect_apache_dotconf, + ['^srm%.conf'] = detect_apache_dotconf, + ['asterisk/.*%.conf'] = starsetf('asterisk'), + ['asterisk.*/.*voicemail%.conf'] = starsetf('asteriskvm'), + ['^dictd.*%.conf$'] = 'dictdconf', + ['/lxqt/.*%.conf$'] = 'dosini', + ['/screengrab/.*%.conf$'] = 'dosini', + ['^${GNUPGHOME}/gpg%.conf$'] = 'gpg', + ['/boot/grub/grub%.conf$'] = 'grub', + ['^lilo%.conf'] = starsetf('lilo'), + ['^named.*%.conf$'] = 'named', + ['^rndc.*%.conf$'] = 'named', + ['/openvpn/.*/.*%.conf$'] = 'openvpn', + ['/%.ssh/.*%.conf$'] = 'sshconfig', + ['^%.?tmux.*%.conf$'] = 'tmux', + ['^%.?tmux.*%.conf'] = { 'tmux', { priority = -1 } }, + ['/%.config/upstart/.*%.conf$'] = 'upstart', + ['/%.config/upstart/.*%.override$'] = 'upstart', + ['/%.init/.*%.conf$'] = 'upstart', + ['/xorg%.conf%.d/.*%.conf$'] = detect.xfree86_v4, + }, + ['sst%.meta'] = { + ['%.%-sst%.meta$'] = 'sisu', + ['%._sst%.meta$'] = 'sisu', + ['%.sst%.meta$'] = 'sisu', + }, + ['file'] = { + ['^[mM]akefile%.am$'] = 'automake', + ['^Containerfile%.'] = starsetf('dockerfile'), + ['^Dockerfile%.'] = starsetf('dockerfile'), + ['^[jJ]ustfile$'] = 'just', + ['[mM]akefile$'] = 'make', + ['^[mM]akefile'] = starsetf('make'), + ['^[rR]akefile$'] = 'ruby', + ['^[rR]akefile'] = starsetf('ruby'), + ['^[rR]antfile$'] = 'ruby', + ['^%.profile'] = detect.sh, + }, + ['fvwm'] = { + ['/%.fvwm/'] = starsetf('fvwm'), + ['fvwmrc'] = starsetf(detect.fvwm_v1), + ['fvwm95.*%.hook$'] = starsetf(detect.fvwm_v1), + ['fvwm2rc'] = starsetf(detect.fvwm_v2), + }, + ['nginx'] = { + ['/nginx/.*%.conf$'] = 'nginx', + ['/usr/local/nginx/conf/'] = 'nginx', + ['nginx%.conf$'] = 'nginx', + ['^nginx.*%.conf$'] = 'nginx', + }, + ['require'] = { + ['%-requirements%.txt$'] = 'requirements', + ['^requirements/.*%.txt$'] = 'requirements', + ['^requires/.*%.txt$'] = 'requirements', + }, + ['s6'] = { + ['s6.*/down$'] = 'execline', + ['s6.*/finish$'] = 'execline', + ['s6.*/run$'] = 'execline', + ['s6.*/up$'] = 'execline', + ['^s6%-'] = 'execline', + }, + ['utt'] = { + ['^mutt%-.*%-%w+$'] = 'mail', + ['^mutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail', + ['^muttng%-.*%-%w+$'] = 'mail', + ['^neomutt%-.*%-%w+$'] = 'mail', + ['^neomutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail', + -- muttngrc* and .muttngrc* + ['^%.?muttngrc'] = detect_muttrc, + -- muttrc* and .muttrc* + ['^%.?muttrc'] = detect_muttrc, + ['/%.mutt/muttrc'] = detect_muttrc, + ['/%.muttng/muttngrc'] = detect_muttrc, + ['/%.muttng/muttrc'] = detect_muttrc, + ['^Muttngrc$'] = 'muttrc', + ['^Muttngrc'] = detect_muttrc, + ['^Muttrc$'] = 'muttrc', + ['^Muttrc'] = detect_muttrc, + -- neomuttrc* and .neomuttrc* + ['^%.?neomuttrc'] = detect_neomuttrc, + ['/%.neomutt/neomuttrc'] = detect_neomuttrc, + ['^Neomuttrc'] = detect_neomuttrc, + }, + ['^%.'] = { + ['^%.cshrc'] = detect.csh, + ['^%.login'] = detect.csh, + ['^%.gitsendemail%.msg%.......$'] = 'gitsendemail', + ['^%.kshrc'] = detect.ksh, + ['^%.article%.%d+$'] = 'mail', + ['^%.letter%.%d+$'] = 'mail', + ['^%.reminders'] = starsetf('remind'), + ['^%.tcshrc'] = detect.tcsh, + ['^%.zcompdump'] = starsetf('zsh'), + }, + ['proj%.user$'] = { + ['%.csproj%.user$'] = 'xml', + ['%.fsproj%.user$'] = 'xml', + ['%.vbproj%.user$'] = 'xml', + }, + [''] = { + ['/bind/db%.'] = starsetf('bindzone'), + ['/named/db%.'] = starsetf('bindzone'), + ['%.blade%.php$'] = 'blade', + ['^bzr_log%.'] = 'bzr', + ['^cabal%.project%.'] = starsetf('cabalproject'), + ['^sgml%.catalog'] = starsetf('catalog'), + ['%.[Cc][Ff][Gg]$'] = { + detect.cfg, + -- Decrease priority to avoid conflicts with more specific patterns + -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. + { priority = -1 }, + }, + ['hgrc$'] = 'cfg', + ['^[cC]hange[lL]og'] = starsetf(detect.changelog), + ['%.%.ch$'] = 'chill', + ['%.cmake%.in$'] = 'cmake', + ['^crontab%.'] = starsetf('crontab'), + ['^cvs%d+$'] = 'cvs', + ['%.[Dd][Aa][Tt]$'] = detect.dat, + ['^php%.ini%-'] = 'dosini', + ['lpe$'] = 'dracula', + ['lvs$'] = 'dracula', + ['^drac%.'] = starsetf('dracula'), + ['/dtrace/.*%.d$'] = 'dtrace', + ['esmtprc$'] = 'esmtprc', + ['/0%.orig/'] = detect.foam, + ['/0/'] = detect.foam, + ['/constant/g$'] = detect.foam, + ['Transport%.'] = detect.foam, + ['^[a-zA-Z0-9].*Dict%.'] = detect.foam, + ['^[a-zA-Z0-9].*Dict$'] = detect.foam, + ['^[a-zA-Z].*Properties%.'] = detect.foam, + ['^[a-zA-Z].*Properties$'] = detect.foam, + ['/tmp/lltmp'] = starsetf('gedcom'), + ['^gkrellmrc_.$'] = 'gkrellmrc', + ['^${GNUPGHOME}/options$'] = 'gpg', + ['/boot/grub/menu%.lst$'] = 'grub', + -- gtkrc* and .gtkrc* + ['^%.?gtkrc'] = starsetf('gtkrc'), + ['^${VIMRUNTIME}/doc/.*%.txt$'] = 'help', + ['^hg%-editor%-.*%.txt$'] = 'hgcommit', + ['%.html%.m4$'] = 'htmlm4', + ['^JAM.*%.'] = starsetf('jam'), + ['^Prl.*%.'] = starsetf('jam'), + ['%.properties_..$'] = 'jproperties', + ['%.properties_.._..$'] = 'jproperties', + ['%.properties_.._.._'] = starsetf('jproperties'), + ['^org%.eclipse%..*%.prefs$'] = 'jproperties', + ['^[jt]sconfig.*%.json$'] = 'jsonc', + ['^Config%.in%.'] = starsetf('kconfig'), + ['^Kconfig%.'] = starsetf('kconfig'), + ['%.[Ss][Uu][Bb]$'] = 'krl', + ['/ldscripts/'] = 'ld', + ['lftp/rc$'] = 'lftp', + ['/LiteStep/.*/.*%.rc$'] = 'litestep', + ['%.[Ll][Oo][Gg]$'] = detect.log, + ['^/tmp/SLRN[0-9A-Z.]+$'] = 'mail', + ['^ae%d+%.txt$'] = 'mail', + ['^pico%.%d+$'] = 'mail', + ['^reportbug%-'] = starsetf('mail'), + ['^snd%.%d+$'] = 'mail', + ['%.[Mm][Oo][Dd]$'] = detect.mod, + ['^rndc.*%.key$'] = 'named', + ['%.NS[ACGLMNPS]$'] = 'natural', + ['%.[1-9]$'] = detect.nroff, + ['^tmac%.'] = starsetf('nroff'), + ['%.ml%.cppo$'] = 'ocaml', + ['%.mli%.cppo$'] = 'ocaml', + ['/octave/history$'] = 'octave', + ['%.opam%.locked$'] = 'opam', + ['%.opam%.template$'] = 'opam', + ['%.[Oo][Pp][Ll]$'] = 'opl', + ['^%.?gitolite%.rc$'] = 'perl', + ['^example%.gitolite%.rc$'] = 'perl', + ['%.php%d$'] = 'php', + ['%.[Pp][Rr][Gg]$'] = detect.prg, + ['printcap'] = starsetf(function(path, bufnr) + return require('vim.filetype.detect').printcap('print') + end), + ['/queries/.*%.scm$'] = 'query', -- treesitter queries (Neovim only) + [',v$'] = 'rcs', + ['%.[Ss][Rr][Cc]$'] = detect.src, + ['^svn%-commit.*%.tmp$'] = 'svn', + ['%.swift%.gyb$'] = 'swiftgyb', + ['%.[Ss][Yy][Ss]$'] = detect.sys, + ['termcap'] = starsetf(function(path, bufnr) + return require('vim.filetype.detect').printcap('term') + end), + ['%.t%.html$'] = 'tilde', + ['%.vhdl_[0-9]'] = starsetf('vhdl'), + ['vimrc'] = starsetf('vim'), + ['/Xresources/'] = starsetf('xdefaults'), + ['/app%-defaults/'] = starsetf('xdefaults'), + ['^Xresources'] = starsetf('xdefaults'), + -- Increase priority to run before the pattern below + ['^XF86Config%-4'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }), + ['^XF86Config'] = starsetf(detect.xfree86_v3), + ['Xmodmap$'] = 'xmodmap', + ['xmodmap'] = starsetf('xmodmap'), + -- .zlog* and zlog* + ['^%.?zlog'] = starsetf('zsh'), + -- .zsh* and zsh* + ['^%.?zsh'] = starsetf('zsh'), + -- Ignored extension + ['~$'] = function(path, bufnr) + local short = path:gsub('~+$', '', 1) + if path ~= short and short ~= '' then + return M.match({ buf = bufnr, filename = fn.fnameescape(short) }) + end + end, }, - ['%.git/modules/.*/config$'] = 'gitconfig', - ['%.git/modules/config$'] = 'gitconfig', - ['%.git/config$'] = 'gitconfig', - ['/etc/gitconfig$'] = 'gitconfig', - ['/%.config/git/config$'] = 'gitconfig', - ['%.git/config%.worktree$'] = 'gitconfig', - ['%.git/worktrees/.*/config%.worktree$'] = 'gitconfig', - ['^${XDG_CONFIG_HOME}/git/config$'] = 'gitconfig', - ['%.git/info/attributes$'] = 'gitattributes', - ['/etc/gitattributes$'] = 'gitattributes', - ['/%.config/git/attributes$'] = 'gitattributes', - ['^${XDG_CONFIG_HOME}/git/attributes$'] = 'gitattributes', - ['%.git/info/exclude$'] = 'gitignore', - ['/%.config/git/ignore$'] = 'gitignore', - ['^${XDG_CONFIG_HOME}/git/ignore$'] = 'gitignore', - ['^%.gitsendemail%.msg%.......$'] = 'gitsendemail', - ['^gkrellmrc_.$'] = 'gkrellmrc', - ['/usr/.*/gnupg/options%.skel$'] = 'gpg', - ['/%.gnupg/options$'] = 'gpg', - ['/%.gnupg/gpg%.conf$'] = 'gpg', - ['^${GNUPGHOME}/options$'] = 'gpg', - ['^${GNUPGHOME}/gpg%.conf$'] = 'gpg', - ['/etc/group$'] = 'group', - ['/etc/gshadow$'] = 'group', - ['/etc/group%.edit$'] = 'group', - ['/var/backups/gshadow%.bak$'] = 'group', - ['/etc/group%-$'] = 'group', - ['/etc/gshadow%-$'] = 'group', - ['/var/backups/group%.bak$'] = 'group', - ['/etc/gshadow%.edit$'] = 'group', - ['/boot/grub/grub%.conf$'] = 'grub', - ['/boot/grub/menu%.lst$'] = 'grub', - ['/etc/grub%.conf$'] = 'grub', - -- gtkrc* and .gtkrc* - ['^%.?gtkrc'] = starsetf('gtkrc'), - ['^${VIMRUNTIME}/doc/.*%.txt$'] = 'help', - ['^hg%-editor%-.*%.txt$'] = 'hgcommit', - ['/etc/host%.conf$'] = 'hostconf', - ['/etc/hosts%.deny$'] = 'hostsaccess', - ['/etc/hosts%.allow$'] = 'hostsaccess', - ['%.html%.m4$'] = 'htmlm4', - ['/%.i3/config$'] = 'i3config', - ['/i3/config$'] = 'i3config', - ['/%.icewm/menu$'] = 'icemenu', - ['/etc/initng/.*/.*%.i$'] = 'initng', - ['^JAM.*%.'] = starsetf('jam'), - ['^Prl.*%.'] = starsetf('jam'), - ['%.properties_..$'] = 'jproperties', - ['%.properties_.._..$'] = 'jproperties', - ['^org%.eclipse%..*%.prefs$'] = 'jproperties', - ['%.properties_.._.._'] = starsetf('jproperties'), - ['^[jt]sconfig.*%.json$'] = 'jsonc', - ['^[jJ]ustfile$'] = 'just', - ['^Kconfig%.'] = starsetf('kconfig'), - ['^Config%.in%.'] = starsetf('kconfig'), - ['%.[Ss][Uu][Bb]$'] = 'krl', - ['^lilo%.conf'] = starsetf('lilo'), - ['/etc/logcheck/.*%.d.*/'] = starsetf('logcheck'), - ['/ldscripts/'] = 'ld', - ['lftp/rc$'] = 'lftp', - ['/%.libao$'] = 'libao', - ['/etc/libao%.conf$'] = 'libao', - ['/etc/.*limits%.conf$'] = 'limits', - ['/etc/limits$'] = 'limits', - ['/etc/.*limits%.d/.*%.conf$'] = 'limits', - ['/supertux2/config$'] = 'lisp', - ['/LiteStep/.*/.*%.rc$'] = 'litestep', - ['/etc/login%.access$'] = 'loginaccess', - ['/etc/login%.defs$'] = 'logindefs', - ['^%.letter%.%d+$'] = 'mail', - ['^%.article%.%d+$'] = 'mail', - ['^/tmp/SLRN[0-9A-Z.]+$'] = 'mail', - ['^ae%d+%.txt$'] = 'mail', - ['^pico%.%d+$'] = 'mail', - ['^mutt%-.*%-%w+$'] = 'mail', - ['^muttng%-.*%-%w+$'] = 'mail', - ['^neomutt%-.*%-%w+$'] = 'mail', - ['^mutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail', - ['^neomutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail', - ['^snd%.%d+$'] = 'mail', - ['^reportbug%-'] = starsetf('mail'), - ['/etc/mail/aliases$'] = 'mailaliases', - ['/etc/aliases$'] = 'mailaliases', - ['[mM]akefile$'] = 'make', - ['^[mM]akefile'] = starsetf('make'), - ['/etc/man%.conf$'] = 'manconf', - ['/log/auth$'] = 'messages', - ['/log/cron$'] = 'messages', - ['/log/daemon$'] = 'messages', - ['/log/debug$'] = 'messages', - ['/log/kern$'] = 'messages', - ['/log/lpr$'] = 'messages', - ['/log/mail$'] = 'messages', - ['/log/messages$'] = 'messages', - ['/log/news/news$'] = 'messages', - ['/log/syslog$'] = 'messages', - ['/log/user$'] = 'messages', - ['/log/auth%.log$'] = 'messages', - ['/log/cron%.log$'] = 'messages', - ['/log/daemon%.log$'] = 'messages', - ['/log/debug%.log$'] = 'messages', - ['/log/kern%.log$'] = 'messages', - ['/log/lpr%.log$'] = 'messages', - ['/log/mail%.log$'] = 'messages', - ['/log/messages%.log$'] = 'messages', - ['/log/news/news%.log$'] = 'messages', - ['/log/syslog%.log$'] = 'messages', - ['/log/user%.log$'] = 'messages', - ['/log/auth%.err$'] = 'messages', - ['/log/cron%.err$'] = 'messages', - ['/log/daemon%.err$'] = 'messages', - ['/log/debug%.err$'] = 'messages', - ['/log/kern%.err$'] = 'messages', - ['/log/lpr%.err$'] = 'messages', - ['/log/mail%.err$'] = 'messages', - ['/log/messages%.err$'] = 'messages', - ['/log/news/news%.err$'] = 'messages', - ['/log/syslog%.err$'] = 'messages', - ['/log/user%.err$'] = 'messages', - ['/log/auth%.info$'] = 'messages', - ['/log/cron%.info$'] = 'messages', - ['/log/daemon%.info$'] = 'messages', - ['/log/debug%.info$'] = 'messages', - ['/log/kern%.info$'] = 'messages', - ['/log/lpr%.info$'] = 'messages', - ['/log/mail%.info$'] = 'messages', - ['/log/messages%.info$'] = 'messages', - ['/log/news/news%.info$'] = 'messages', - ['/log/syslog%.info$'] = 'messages', - ['/log/user%.info$'] = 'messages', - ['/log/auth%.warn$'] = 'messages', - ['/log/cron%.warn$'] = 'messages', - ['/log/daemon%.warn$'] = 'messages', - ['/log/debug%.warn$'] = 'messages', - ['/log/kern%.warn$'] = 'messages', - ['/log/lpr%.warn$'] = 'messages', - ['/log/mail%.warn$'] = 'messages', - ['/log/messages%.warn$'] = 'messages', - ['/log/news/news%.warn$'] = 'messages', - ['/log/syslog%.warn$'] = 'messages', - ['/log/user%.warn$'] = 'messages', - ['/log/auth%.crit$'] = 'messages', - ['/log/cron%.crit$'] = 'messages', - ['/log/daemon%.crit$'] = 'messages', - ['/log/debug%.crit$'] = 'messages', - ['/log/kern%.crit$'] = 'messages', - ['/log/lpr%.crit$'] = 'messages', - ['/log/mail%.crit$'] = 'messages', - ['/log/messages%.crit$'] = 'messages', - ['/log/news/news%.crit$'] = 'messages', - ['/log/syslog%.crit$'] = 'messages', - ['/log/user%.crit$'] = 'messages', - ['/log/auth%.notice$'] = 'messages', - ['/log/cron%.notice$'] = 'messages', - ['/log/daemon%.notice$'] = 'messages', - ['/log/debug%.notice$'] = 'messages', - ['/log/kern%.notice$'] = 'messages', - ['/log/lpr%.notice$'] = 'messages', - ['/log/mail%.notice$'] = 'messages', - ['/log/messages%.notice$'] = 'messages', - ['/log/news/news%.notice$'] = 'messages', - ['/log/syslog%.notice$'] = 'messages', - ['/log/user%.notice$'] = 'messages', - ['%.[Mm][Oo][Dd]$'] = detect.mod, - ['/etc/modules%.conf$'] = 'modconf', - ['/etc/conf%.modules$'] = 'modconf', - ['/etc/modules$'] = 'modconf', - ['/etc/modprobe%.'] = starsetf('modconf'), - ['/etc/modutils/'] = starsetf(function(path, bufnr) - if fn.executable(fn.expand(path)) ~= 1 then - return 'modconf' - end - end), - ['^Muttrc$'] = 'muttrc', - ['^Muttngrc$'] = 'muttrc', - ['/etc/Muttrc%.d/'] = starsetf('muttrc'), - ['/%.mplayer/config$'] = 'mplayerconf', - ['^Muttrc'] = detect_muttrc, - ['^Muttngrc'] = detect_muttrc, - -- muttrc* and .muttrc* - ['^%.?muttrc'] = detect_muttrc, - -- muttngrc* and .muttngrc* - ['^%.?muttngrc'] = detect_muttrc, - ['/%.mutt/muttrc'] = detect_muttrc, - ['/%.muttng/muttrc'] = detect_muttrc, - ['/%.muttng/muttngrc'] = detect_muttrc, - ['^rndc.*%.conf$'] = 'named', - ['^rndc.*%.key$'] = 'named', - ['^named.*%.conf$'] = 'named', - ['/etc/nanorc$'] = 'nanorc', - ['%.NS[ACGLMNPS]$'] = 'natural', - ['^Neomuttrc'] = detect_neomuttrc, - -- neomuttrc* and .neomuttrc* - ['^%.?neomuttrc'] = detect_neomuttrc, - ['/%.neomutt/neomuttrc'] = detect_neomuttrc, - ['^nginx.*%.conf$'] = 'nginx', - ['/etc/nginx/'] = 'nginx', - ['nginx%.conf$'] = 'nginx', - ['/nginx/.*%.conf$'] = 'nginx', - ['/usr/local/nginx/conf/'] = 'nginx', - ['%.[1-9]$'] = detect.nroff, - ['%.ml%.cppo$'] = 'ocaml', - ['%.mli%.cppo$'] = 'ocaml', - ['/octave/history$'] = 'octave', - ['%.opam%.locked$'] = 'opam', - ['%.opam%.template$'] = 'opam', - ['/openvpn/.*/.*%.conf$'] = 'openvpn', - ['%.[Oo][Pp][Ll]$'] = 'opl', - ['/etc/pam%.conf$'] = 'pamconf', - ['/etc/pam%.d/'] = starsetf('pamconf'), - ['/etc/passwd%-$'] = 'passwd', - ['/etc/shadow$'] = 'passwd', - ['/etc/shadow%.edit$'] = 'passwd', - ['/var/backups/shadow%.bak$'] = 'passwd', - ['/var/backups/passwd%.bak$'] = 'passwd', - ['/etc/passwd$'] = 'passwd', - ['/etc/passwd%.edit$'] = 'passwd', - ['/etc/shadow%-$'] = 'passwd', - ['^%.?gitolite%.rc$'] = 'perl', - ['^example%.gitolite%.rc$'] = 'perl', - ['%.php%d$'] = 'php', - ['/%.pinforc$'] = 'pinfo', - ['/etc/pinforc$'] = 'pinfo', - ['%.[Pp][Rr][Gg]$'] = detect.prg, - ['/etc/protocols$'] = 'protocols', - ['printcap'] = starsetf(function(path, bufnr) - return require('vim.filetype.detect').printcap('print') - end), - ['baseq[2-3]/.*%.cfg$'] = 'quake', - ['quake[1-3]/.*%.cfg$'] = 'quake', - ['id1/.*%.cfg$'] = 'quake', - ['/queries/.*%.scm$'] = 'query', -- treesitter queries (Neovim only) - [',v$'] = 'rcs', - ['^%.reminders'] = starsetf('remind'), - ['%-requirements%.txt$'] = 'requirements', - ['^requirements/.*%.txt$'] = 'requirements', - ['^requires/.*%.txt$'] = 'requirements', - ['^[rR]akefile'] = starsetf('ruby'), - ['^[rR]antfile$'] = 'ruby', - ['^[rR]akefile$'] = 'ruby', - ['/etc/sensors%.d/[^.]'] = starsetf('sensors'), - ['/etc/sensors%.conf$'] = 'sensors', - ['/etc/sensors3%.conf$'] = 'sensors', - ['/etc/services$'] = 'services', - ['/etc/serial%.conf$'] = 'setserial', - ['/etc/udev/cdsymlinks%.conf$'] = 'sh', - ['/neofetch/config%.conf$'] = 'sh', - ['^%.bash[_%-]aliases$'] = detect.bash, - ['^%.bash[_%-]history$'] = detect.bash, - ['^%.bash[_%-]logout$'] = detect.bash, - ['^%.bash[_%-]profile$'] = detect.bash, - ['^%.kshrc'] = detect.ksh, - ['^%.profile'] = detect.sh, - ['/etc/profile$'] = detect.sh, - ['^bash%-fc[%-%.]'] = detect.bash, - ['^%.tcshrc'] = detect.tcsh, - ['/etc/sudoers%.d/'] = starsetf('sudoers'), - ['%._sst%.meta$'] = 'sisu', - ['%.%-sst%.meta$'] = 'sisu', - ['%.sst%.meta$'] = 'sisu', - ['/etc/slp%.conf$'] = 'slpconf', - ['/etc/slp%.reg$'] = 'slpreg', - ['/etc/slp%.spi$'] = 'slpspi', - ['/etc/ssh/ssh_config%.d/.*%.conf$'] = 'sshconfig', - ['/%.ssh/config$'] = 'sshconfig', - ['/%.ssh/.*%.conf$'] = 'sshconfig', - ['/etc/ssh/sshd_config%.d/.*%.conf$'] = 'sshdconfig', - ['%.[Ss][Rr][Cc]$'] = detect.src, - ['/etc/sudoers$'] = 'sudoers', - ['^svn%-commit.*%.tmp$'] = 'svn', - ['/sway/config$'] = 'swayconfig', - ['/%.sway/config$'] = 'swayconfig', - ['%.swift%.gyb$'] = 'swiftgyb', - ['%.[Ss][Yy][Ss]$'] = detect.sys, - ['/etc/sysctl%.conf$'] = 'sysctl', - ['/etc/sysctl%.d/.*%.conf$'] = 'sysctl', - ['/systemd/.*%.automount$'] = 'systemd', - ['/systemd/.*%.dnssd$'] = 'systemd', - ['/systemd/.*%.link$'] = 'systemd', - ['/systemd/.*%.mount$'] = 'systemd', - ['/systemd/.*%.netdev$'] = 'systemd', - ['/systemd/.*%.network$'] = 'systemd', - ['/systemd/.*%.nspawn$'] = 'systemd', - ['/systemd/.*%.path$'] = 'systemd', - ['/systemd/.*%.service$'] = 'systemd', - ['/systemd/.*%.slice$'] = 'systemd', - ['/systemd/.*%.socket$'] = 'systemd', - ['/systemd/.*%.swap$'] = 'systemd', - ['/systemd/.*%.target$'] = 'systemd', - ['/systemd/.*%.timer$'] = 'systemd', - ['/etc/systemd/.*%.conf%.d/.*%.conf$'] = 'systemd', - ['/%.config/systemd/user/.*%.d/.*%.conf$'] = 'systemd', - ['/etc/systemd/system/.*%.d/.*%.conf$'] = 'systemd', - ['/etc/systemd/system/.*%.d/%.#'] = 'systemd', - ['/etc/systemd/system/%.#'] = 'systemd', - ['/%.config/systemd/user/.*%.d/%.#'] = 'systemd', - ['/%.config/systemd/user/%.#'] = 'systemd', - ['termcap'] = starsetf(function(path, bufnr) - return require('vim.filetype.detect').printcap('term') - end), - ['/tex/latex/.*%.cfg$'] = 'tex', - ['%.t%.html$'] = 'tilde', - ['^%.?tmux.*%.conf$'] = 'tmux', - ['^%.?tmux.*%.conf'] = { 'tmux', { priority = -1 } }, - ['/%.cargo/config$'] = 'toml', - ['/%.cargo/credentials$'] = 'toml', - ['/etc/udev/udev%.conf$'] = 'udevconf', - ['/etc/udev/permissions%.d/.*%.permissions$'] = 'udevperm', - ['/etc/updatedb%.conf$'] = 'updatedb', - ['/%.init/.*%.override$'] = 'upstart', - ['/usr/share/upstart/.*%.conf$'] = 'upstart', - ['/%.config/upstart/.*%.override$'] = 'upstart', - ['/etc/init/.*%.conf$'] = 'upstart', - ['/etc/init/.*%.override$'] = 'upstart', - ['/%.config/upstart/.*%.conf$'] = 'upstart', - ['/%.init/.*%.conf$'] = 'upstart', - ['/usr/share/upstart/.*%.override$'] = 'upstart', - ['%.[Ll][Oo][Gg]$'] = detect.log, - ['/etc/config/'] = starsetf(detect.uci), - ['%.vhdl_[0-9]'] = starsetf('vhdl'), - ['/Xresources/'] = starsetf('xdefaults'), - ['/app%-defaults/'] = starsetf('xdefaults'), - ['/etc/xinetd%.conf$'] = 'xinetd', - ['/usr/share/X11/xkb/compat/'] = starsetf('xkb'), - ['/usr/share/X11/xkb/geometry/'] = starsetf('xkb'), - ['/usr/share/X11/xkb/keycodes/'] = starsetf('xkb'), - ['/usr/share/X11/xkb/symbols/'] = starsetf('xkb'), - ['/usr/share/X11/xkb/types/'] = starsetf('xkb'), - ['/etc/blkid%.tab$'] = 'xml', - ['/etc/blkid%.tab%.old$'] = 'xml', - ['%.vbproj%.user$'] = 'xml', - ['%.fsproj%.user$'] = 'xml', - ['%.csproj%.user$'] = 'xml', - ['/etc/xdg/menus/.*%.menu$'] = 'xml', - ['Xmodmap$'] = 'xmodmap', - ['/etc/zprofile$'] = 'zsh', - ['vimrc'] = starsetf('vim'), - ['^Xresources'] = starsetf('xdefaults'), - ['/etc/xinetd%.d/'] = starsetf('xinetd'), - ['xmodmap'] = starsetf('xmodmap'), - ['/xorg%.conf%.d/.*%.conf$'] = detect.xfree86_v4, - -- Increase priority to run before the pattern below - ['^XF86Config%-4'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }), - ['^XF86Config'] = starsetf(detect.xfree86_v3), - ['/%.bundle/config$'] = 'yaml', - ['^%.zcompdump'] = starsetf('zsh'), - -- .zlog* and zlog* - ['^%.?zlog'] = starsetf('zsh'), - -- .zsh* and zsh* - ['^%.?zsh'] = starsetf('zsh'), - -- Ignored extension - ['~$'] = function(path, bufnr) - local short = path:gsub('~+$', '', 1) - if path ~= short and short ~= '' then - return M.match({ buf = bufnr, filename = fn.fnameescape(short) }) - end - end, -- END PATTERN } -- luacheck: pop @@ -2240,7 +2303,13 @@ local function compare_by_priority(a, b) return a[next(a)][2].priority > b[next(b)][2].priority end ---- @param t vim.filetype.mapping +--- @param pat string +--- @return { has_env: boolean, has_slash: boolean } +local function parse_pattern(pat) + return { has_env = pat:find('%$%b{}') ~= nil, has_slash = pat:find('/') ~= nil } +end + +--- @param t table --- @return vim.filetype.mapping[] --- @return vim.filetype.mapping[] local function sort_by_priority(t) @@ -2248,21 +2317,24 @@ local function sort_by_priority(t) -- will be processed separately local pos = {} --- @type vim.filetype.mapping[] local neg = {} --- @type vim.filetype.mapping[] - for pat, maptbl in pairs(t) do - local ft = type(maptbl) == 'table' and maptbl[1] or maptbl - assert( - type(ft) == 'string' or type(ft) == 'function', - 'Expected string or function for filetype' - ) + for parent, ft_map in pairs(t) do + pattern_lookup[parent] = pattern_lookup[parent] or parse_pattern(parent) + for pat, maptbl in pairs(ft_map) do + local ft = type(maptbl) == 'table' and maptbl[1] or maptbl + assert( + type(ft) == 'string' or type(ft) == 'function', + 'Expected string or function for filetype' + ) - -- Parse pattern for common data and cache it once - pattern_lookup[pat] = pattern_lookup[pat] - or { has_env = pat:find('%$%b{}') ~= nil, has_slash = pat:find('/') ~= nil } + -- Parse pattern for common data and cache it once + pattern_lookup[pat] = pattern_lookup[pat] or parse_pattern(pat) - local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or {} - opts.priority = opts.priority or 0 + local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or {} + opts.parent = opts.parent or parent + opts.priority = opts.priority or 0 - table.insert(opts.priority >= 0 and pos or neg, { [pat] = { ft, opts } }) + table.insert(opts.priority >= 0 and pos or neg, { [pat] = { ft, opts } }) + end end table.sort(pos, compare_by_priority) @@ -2390,8 +2462,10 @@ function M.add(filetypes) end for k, v in pairs(filetypes.pattern or {}) do + -- Add to "match all" parent pattern (might be better to optimize later or document + -- supplying `opts.parent` directly) -- User patterns are assumed to be implicitly anchored (as in Vim) - pattern['^' .. normalize_path(k, true) .. '$'] = v + pattern['']['^' .. normalize_path(k, true) .. '$'] = v end if filetypes.pattern then @@ -2458,8 +2532,9 @@ end --- @param path string --- @param tail string --- @param pat string ---- @return string|boolean? -local function match_pattern(name, path, tail, pat) +--- @param try_all_candidates boolean +--- @return string? +local function match_pattern(name, path, tail, pat, try_all_candidates) local pat_cache = pattern_lookup[pat] local has_slash = pat_cache.has_slash @@ -2467,11 +2542,16 @@ local function match_pattern(name, path, tail, pat) local some_env_missing, expanded = expand_envvar_pattern(pat) -- If any environment variable is present in the pattern but not set, there is no match if some_env_missing then - return false + return nil end pat, has_slash = expanded, expanded:find('/') ~= nil end + -- Try all possible candidates to make parent patterns not depend on slash presence + if try_all_candidates then + return (path:match(pat) or name:match(pat) or tail:match(pat)) + end + -- If the pattern contains a / match against the full path, otherwise just the tail if has_slash then -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against @@ -2487,15 +2567,26 @@ end --- @param path string --- @param tail string --- @param pattern_sorted vim.filetype.mapping[] +--- @param parent_matches table --- @param bufnr integer? -local function match_pattern_sorted(name, path, tail, pattern_sorted, bufnr) +local function match_pattern_sorted(name, path, tail, pattern_sorted, parent_matches, bufnr) for i = 1, #pattern_sorted do local pat, ft_data = next(pattern_sorted[i]) - local matches = match_pattern(name, path, tail, pat) - if matches then - local ft, on_detect = dispatch(ft_data[1], path, bufnr, matches) - if ft then - return ft, on_detect + + local parent = ft_data[2].parent + local parent_is_matched = parent_matches[parent] + if parent_is_matched == nil then + parent_matches[parent] = match_pattern(name, path, tail, parent, true) ~= nil + parent_is_matched = parent_matches[parent] + end + + if parent_is_matched then + local matches = match_pattern(name, path, tail, pat, false) + if matches then + local ft, on_detect = dispatch(ft_data[1], path, bufnr, matches) + if ft then + return ft, on_detect + end end end end @@ -2594,7 +2685,10 @@ function M.match(args) end -- Next, check the file path against available patterns with non-negative priority - ft, on_detect = match_pattern_sorted(name, path, tail, pattern_sorted_pos, bufnr) + -- Cache match results of all parent patterns to improve performance + local parent_matches = {} + ft, on_detect = + match_pattern_sorted(name, path, tail, pattern_sorted_pos, parent_matches, bufnr) if ft then return ft, on_detect end @@ -2609,7 +2703,8 @@ function M.match(args) end -- Next, check patterns with negative priority - ft, on_detect = match_pattern_sorted(name, path, tail, pattern_sorted_neg, bufnr) + ft, on_detect = + match_pattern_sorted(name, path, tail, pattern_sorted_neg, parent_matches, bufnr) if ft then return ft, on_detect end -- cgit From f73904f9d6b6129c6358e2a54521abda271127db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 19 Jul 2024 12:12:13 +0800 Subject: vim-patch:eb6d733: runtime(doc): fix more inconsistencies in assert function docs (#29796) related: https://github.com/vim/vim/pull/15280#issuecomment-2233771449 closes: vim/vim#15285 https://github.com/vim/vim/commit/eb6d733bef312a0634770e023e8a41f0347f1503 --- runtime/lua/vim/_meta/vimfn.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index b68a16d014..bd6550941d 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -203,8 +203,8 @@ function vim.fn.assert_beeps(cmd) end --- added to |v:errors| and 1 is returned. Otherwise zero is --- returned. |assert-return| --- The error is in the form "Expected {expected} but got ---- {actual}". When {msg} is present it is prefixed to that, along ---- with the location of the assert when run from a script. +--- {actual}". When {msg} is present it is prefixed to that, +--- along with the location of the assert when run from a script. --- --- There is no automatic conversion, the String "4" is different --- from the Number 4. And the number 4 is different from the @@ -255,16 +255,16 @@ function vim.fn.assert_exception(error, msg) end --- When {error} is a string it must be found literally in the --- first reported error. Most often this will be the error code, --- including the colon, e.g. "E123:". >vim ---- assert_fails('bad cmd', 'E987:') +--- call assert_fails('bad cmd', 'E987:') --- < --- When {error} is a |List| with one or two strings, these are --- used as patterns. The first pattern is matched against the --- first reported error: >vim ---- assert_fails('cmd', ['E987:.*expected bool']) +--- call assert_fails('cmd', ['E987:.*expected bool']) --- vim ---- assert_fails('cmd', ['', 'E987:']) +--- call assert_fails('cmd', ['', 'E987:']) --- < --- If {msg} is empty then it is not used. Do this to get the --- default message when passing the {lnum} argument. @@ -292,8 +292,8 @@ function vim.fn.assert_fails(cmd, error, msg, lnum, context) end --- When {actual} is not false an error message is added to --- |v:errors|, like with |assert_equal()|. --- The error is in the form "Expected False but got {actual}". ---- When {msg} is present it is prepended to that, along ---- with the location of the assert when run from a script. +--- When {msg} is present it is prefixed to that, along with the +--- location of the assert when run from a script. --- Also see |assert-return|. --- --- A value is false when it is zero. When {actual} is not a @@ -333,7 +333,7 @@ function vim.fn.assert_inrange(lower, upper, actual, msg) end --- Use both to match the whole text. --- --- Example: >vim ---- assert_match('^f.*o$', 'foobar') +--- call assert_match('^f.*o$', 'foobar') --- Date: Fri, 19 Jul 2024 12:57:56 +0800 Subject: vim-patch:9.1.0602: filetype: Prolog detection can be improved Problem: filetype: Prolog detection can be improved Solution: update the prolog detection regex (igna_martinoli) related: vim/vim#10835 related: vim/vim#15206 closes: vim/vim#15253 https://github.com/vim/vim/commit/37853b7de31ef34153fe76aa2b740d517ed0e5d4 N/A patch: vim-patch:7347642: runtime(filetype): Fix Prolog file detection regex Problem: filetype: .pro file detection for Prolog is broken Solution: fixed the regex to only match on the tested cases (igna_martinoli) fixes: vim/vim#10835 closes: vim/vim#15206 https://github.com/vim/vim/commit/7347642633eb2de23a78c51a4388c9080440eec4 Co-authored-by: igna_martinoli Co-authored-by: clason --- runtime/lua/vim/filetype/detect.lua | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 95e55ebb21..1fe7db0e1f 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -1116,6 +1116,8 @@ function M.perl(path, bufnr) end end +local prolog_patterns = { '^%s*:%-', '^%s*%%+%s', '^%s*%%+$', '^%s*/%*', '%.%s*$' } + --- @type vim.filetype.mapfn function M.pl(_, bufnr) if vim.g.filetype_pl then @@ -1124,11 +1126,7 @@ function M.pl(_, bufnr) -- Recognize Prolog by specific text in the first non-empty line; -- require a blank after the '%' because Perl uses "%list" and "%translate" local line = nextnonblank(bufnr, 1) - if - line and line:find(':%-') - or matchregex(line, [[\c\]]) - or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' }) - then + if line and matchregex(line, [[\c\]]) or findany(line, prolog_patterns) then return 'prolog' else return 'perl' @@ -1232,11 +1230,7 @@ function M.proto(_, bufnr) -- Recognize Prolog by specific text in the first non-empty line; -- require a blank after the '%' because Perl uses "%list" and "%translate" local line = nextnonblank(bufnr, 1) - if - line and line:find(':%-') - or matchregex(line, [[\c\]]) - or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' }) - then + if line and matchregex(line, [[\c\]]) or findany(line, prolog_patterns) then return 'prolog' end end -- cgit From 2a24d0a4357d24d6edbd454ab2465abf460467db Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 19 Jul 2024 16:56:41 +0200 Subject: vim-patch:9.1.0603: filetype: use correct extension for Dracula Problem: pattern detection for Dracula language uses "*lvs" and "*lpe". as there is no dot, those are not treated as extensions which they should (judging by 'runtime/syntax/dracula.vim' and common sense). Solution: use "*.lvs" and "*.lpe" patterns (Evgeni Chasnovski) closes: vim/vim#15303 https://github.com/vim/vim/commit/5fb801a74faaf3ef1262c2988b8801500ca71646 Co-authored-by: Evgeni Chasnovski --- runtime/lua/vim/filetype.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index b497485b53..ea4fa4d2a2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -377,6 +377,8 @@ local extension = { gv = 'dot', drac = 'dracula', drc = 'dracula', + lvs = 'dracula', + lpe = 'dracula', dsp = detect.dsp, dtd = 'dtd', d = detect.dtrace, @@ -2198,8 +2200,6 @@ local pattern = { ['^cvs%d+$'] = 'cvs', ['%.[Dd][Aa][Tt]$'] = detect.dat, ['^php%.ini%-'] = 'dosini', - ['lpe$'] = 'dracula', - ['lvs$'] = 'dracula', ['^drac%.'] = starsetf('dracula'), ['/dtrace/.*%.d$'] = 'dtrace', ['esmtprc$'] = 'esmtprc', -- cgit From 79d492a4218ee6b4da5becbebb712a0f1f65d0f5 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:28:05 -0500 Subject: vim-patch:9.1.0610: filetype: OpenGL Shading Language files are not detected (#29831) Problem: filetype: OpenGL Shading Language files are not detected Solution: detect various file extensions as GLSL filetype, include indent and syntax script, do no longer recognize '*.comp' as Mason filetype (Gregory Anders) closes: vim/vim#15317 https://github.com/vim/vim/commit/e4b991ed36f96dd01c6d75e46a04fd1a99180e58 --- runtime/lua/vim/filetype.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index ea4fa4d2a2..229f989229 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -485,7 +485,19 @@ local extension = { gift = 'gift', prettierignore = 'gitignore', gleam = 'gleam', + vert = 'glsl', + tesc = 'glsl', + tese = 'glsl', glsl = 'glsl', + geom = 'glsl', + frag = 'glsl', + comp = 'glsl', + rgen = 'glsl', + rmiss = 'glsl', + rchit = 'glsl', + rahit = 'glsl', + rint = 'glsl', + rcall = 'glsl', gn = 'gn', gni = 'gn', gnuplot = 'gnuplot', @@ -695,7 +707,6 @@ local extension = { markdown = detect.markdown, mdown = detect.markdown, mhtml = 'mason', - comp = 'mason', mason = 'mason', master = 'master', mas = 'master', -- cgit From b4b4cf46a7a2b6d7b4e997179166444b0e338ac8 Mon Sep 17 00:00:00 2001 From: Abao Zhang Date: Wed, 17 Jul 2024 14:07:20 +0800 Subject: fix(health): fix pyenv root and python exepath detect issue Fix the following two issues: - pyenv root detection issue When `PYENV_ROOT` environment variable is not set, neovim will detect pyenv's root via `pyenv root` command, but which will be always fail because `vim.fn.system()` returns result with additional `\n`. Using `vim.system` instead prevents this problem. to trim it before check whether it is exists - python executable path detection issue Filter unrelated `python-config` in cases where multiple python versions are installed, e.g. `python-config`, `python3.10-config`, `python3.11-config` etc. --- runtime/lua/vim/provider/health.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index 9ff4d15257..47d66307e9 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -366,7 +366,17 @@ local function check_for_pyenv() local pyenv_root = vim.fn.resolve(os.getenv('PYENV_ROOT') or '') if pyenv_root == '' then - pyenv_root = vim.fn.system({ pyenv_path, 'root' }) + local p = vim.system({ pyenv_path, 'root' }):wait() + if p.code ~= 0 then + local message = string.format( + 'pyenv: Failed to infer the root of pyenv by running `%s root` : %s. Ignoring pyenv for all following checks.', + pyenv_path, + p.stderr + ) + health.warn(message) + return { '', '' } + end + pyenv_root = vim.trim(p.stdout) health.info('pyenv: $PYENV_ROOT is not set. Infer from `pyenv root`.') end @@ -754,7 +764,7 @@ local function python() local venv_bins = vim.fn.glob(string.format('%s/%s/python*', virtual_env, bin_dir), true, true) venv_bins = vim.tbl_filter(function(v) -- XXX: Remove irrelevant executables found in bin/. - return not v:match('python%-config') + return not v:match('python.*%-config') end, venv_bins) if vim.tbl_count(venv_bins) > 0 then for _, venv_bin in pairs(venv_bins) do -- cgit From 807eb4434c890118e632ec57e396fd151c441714 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 25 Jul 2024 09:22:58 +0200 Subject: vim-patch:9.1.0612: filetype: deno.lock file not recognized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: filetype: deno.lock file not recognized Solution: detect 'deno.lock' as json filetype (カワリミ人形) Reference: https://docs.deno.com/runtime/manual/basics/modules/integrity_checking/#caching-and-lock-files closes: vim/vim#15333 https://github.com/vim/vim/commit/df77c8ad3974e44df2e588de5f465072371cab69 Co-authored-by: カワリミ人形 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 229f989229..7cbf3a158d 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1492,6 +1492,7 @@ local filename = { ['.prettierrc'] = 'json', ['.stylelintrc'] = 'json', ['.lintstagedrc'] = 'json', + ['deno.lock'] = 'json', ['flake.lock'] = 'json', ['.babelrc'] = 'jsonc', ['.eslintrc'] = 'jsonc', -- cgit From 60967cd9aac545a5a5f17070d39121d4070e2298 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 27 Jul 2024 16:48:29 +0800 Subject: vim-patch:9.1.0616: filetype: Make syntax highlighting off for MS Makefiles (#29874) Problem: filetype: Make syntax highlighting off for MS Makefiles Solution: Try to detect MS Makefiles and adjust syntax rules to it. (Ken Takata) Highlighting of variable expansion in Microsoft Makefile can be broken. E.g.: https://github.com/vim/vim/blob/2979cfc2627d76a9c09cad46a1647dcd4aa73f5f/src/Make_mvc.mak#L1331 Don't use backslash as escape characters if `make_microsoft` is set. Also fix that `make_no_comments` was not considered if `make_microsoft` was set. Also add description for `make_microsoft` and `make_no_comments` to the documentation and include a very simple filetype test closes: vim/vim#15341 https://github.com/vim/vim/commit/eb4b903c9b238ebcc1d14cfcb207129b4931a33d Co-authored-by: Ken Takata --- runtime/lua/vim/filetype.lua | 6 +++--- runtime/lua/vim/filetype/detect.lua | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 7cbf3a158d..bf00392087 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -693,8 +693,8 @@ local extension = { return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4' or nil end, eml = 'mail', - mk = 'make', - mak = 'make', + mk = detect.make, + mak = detect.make, page = 'mallard', map = 'map', mws = 'maple', @@ -2122,7 +2122,7 @@ local pattern = { ['^Containerfile%.'] = starsetf('dockerfile'), ['^Dockerfile%.'] = starsetf('dockerfile'), ['^[jJ]ustfile$'] = 'just', - ['[mM]akefile$'] = 'make', + ['[mM]akefile$'] = detect.make, ['^[mM]akefile'] = starsetf('make'), ['^[rR]akefile$'] = 'ruby', ['^[rR]akefile'] = starsetf('ruby'), diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 1fe7db0e1f..cb953f9d0c 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -972,6 +972,24 @@ local function m4(contents) end end +--- Check if it is a Microsoft Makefile +--- @type vim.filetype.mapfn +function M.make(_, bufnr) + vim.b.make_microsoft = nil + for _, line in ipairs(getlines(bufnr, 1, 1000)) do + if matchregex(line, [[\c^\s*!\s*\(ifn\=\(def\)\=\|include\|message\|error\)\>]]) then + vim.b.make_microsoft = 1 + break + elseif + matchregex(line, [[^ *ifn\=\(eq\|def\)\>]]) + or findany(line, { '^ *[-s]?%s', '^ *%w+%s*[!?:+]=' }) + then + break + end + end + return 'make' +end + --- @type vim.filetype.mapfn function M.markdown(_, _) return vim.g.filetype_md or 'markdown' -- cgit From 8bdfc2ab2b2565f06d41921d57a0c6184a097271 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Fri, 26 Jul 2024 19:19:39 -0700 Subject: fix(version): return nil with empty string --- runtime/lua/vim/version.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/version.lua b/runtime/lua/vim/version.lua index 0b149700b5..7c8823bd72 100644 --- a/runtime/lua/vim/version.lua +++ b/runtime/lua/vim/version.lua @@ -174,6 +174,10 @@ function M._version(version, strict) -- Adapted from https://github.com/folke/la version = version:match('%d[^ ]*') end + if version == nil then + return nil + end + local prerel = version:match('%-([^+]*)') local prerel_strict = version:match('%-([0-9A-Za-z-]*)') if -- cgit From bdff50dee56ebf6de58d58315920abf2f8e262f7 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 27 Jul 2024 22:30:14 +0200 Subject: fix(lsp): revert text edit application order change (#29877) Reverts https://github.com/neovim/neovim/pull/29212 and adds a few additional test cases From the spec > All text edits ranges refer to positions in the document they are > computed on. They therefore move a document from state S1 to S2 without > describing any intermediate state. Text edits ranges must never overlap, > that means no part of the original document must be manipulated by more > than one edit. However, it is possible that multiple edits have the same > start position: multiple inserts, or any number of inserts followed by a > single remove or replace edit. If multiple inserts have the same > position, the order in the array defines the order in which the inserted > strings appear in the resulting text. The previous fix seems wrong. The important part: > If multiple inserts have the same position, the order in the array > defines the order in which the inserted strings appear in the > resulting text. Emphasis on _appear in the resulting text_ Which means that in: local edits1 = { make_edit(0, 3, 0, 3, { 'World' }), make_edit(0, 3, 0, 3, { 'Hello' }), } `World` must appear before `Hello` in the final text. That means the old logic was correct, and the fix was wrong. --- runtime/lua/vim/lsp/util.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b0fd25af3a..59ae3beae4 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -396,10 +396,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) if a.range.start.character ~= b.range.start.character then return a.range.start.character > b.range.start.character end - if a._index ~= b._index then - return a._index < b._index - end - return false + return a._index > b._index end) -- save and restore local marks since they get deleted by nvim_buf_set_lines -- cgit From fe5030c05ec52cab7de03a9ee9150e855b9eefa1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 29 Jul 2024 08:02:31 +0800 Subject: vim-patch:partial:52e7cc2: runtime(doc): tweak documentation style a bit (#29897) closes: vim/vim#15371 https://github.com/vim/vim/commit/52e7cc26d81c61fff1b2e3b32e8b9b04347be1d3 Co-authored-by: h-east --- runtime/lua/vim/_meta/options.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 25654e287d..fffc561604 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -4550,17 +4550,17 @@ vim.go.mouset = vim.go.mousetime --- Using CTRL-X on "0" or CTRL-A on "18446744073709551615" --- (2^64 - 1) has no effect, overflow is prevented. --- blank If included, treat numbers as signed or unsigned based on ---- preceding whitespace. If a number with a leading dash has its +--- preceding whitespace. If a number with a leading dash has its --- dash immediately preceded by a non-whitespace character (i.e., --- not a tab or a " "), the negative sign won't be considered as --- part of the number. For example: --- Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15" --- (without "blank" it would become "Carbon-13"). --- Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9" ---- (because -8 is preceded by whitespace. If "unsigned" was +--- (because -8 is preceded by whitespace. If "unsigned" was --- set, it would result in "Carbon -7"). --- If this format is included, overflow is prevented as if ---- "unsigned" were set. If both this format and "unsigned" are +--- "unsigned" were set. If both this format and "unsigned" are --- included, "unsigned" will take precedence. --- --- Numbers which simply begin with a digit in the range 1-9 are always -- cgit From e596b6a18d84aa56b5189bb7921feec58279976c Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 28 Jul 2024 22:29:20 +0200 Subject: vim-patch:9.1.0635: filetype: SuperHTML template files not recognized Problem: filetype: SuperHTML template files not recognized Solution: Update the filetype detection code to detect '*.shtml' either as HTML (Server Side Includes) or SuperHTML (template files) (EliSauder) related: vim/vim#15355 related: vim/vim#15367 https://github.com/vim/vim/commit/e57c9a19edc906a96ccb8821ae33fa6a8b20c3cd Co-authored-by: EliSauder <24995216+EliSauder@users.noreply.github.com> --- runtime/lua/vim/filetype/detect.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index cb953f9d0c..1cc81b177f 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -735,6 +735,8 @@ function M.html(_, bufnr) ) then return 'htmldjango' + elseif findany(line, { '' }) then + return 'superhtml' end end return 'html' -- cgit From 01a56a056cd5da89350583ef9fbc97fa29dcd8ef Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 28 Jul 2024 22:32:05 +0200 Subject: vim-patch:9.1.0636: filetype: ziggy files are not recognized Problem: filetype: ziggy files are not recognized Solution: detect '*.ziggy' files as ziggy filetype, detect '*.ziggy-schema' files as ziggy-schema filetype (EliSauder) References: https://ziggy-lang.io/ fixes: vim/vim#15355 closes: vim/vim#15367 https://github.com/vim/vim/commit/f4572cee35a6c224985e71116e676ab711c09af3 Co-authored-by: EliSauder <24995216+EliSauder@users.noreply.github.com> --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index bf00392087..52b5392467 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1246,6 +1246,8 @@ local extension = { z8a = 'z8a', zig = 'zig', zon = 'zig', + ziggy = 'ziggy', + ['ziggy-schema'] = 'ziggy_schema', zu = 'zimbu', zut = 'zimbutempl', zs = 'zserio', -- cgit From bd3b6ec8360e0dd6edfe74c3d0013fd2b98b989e Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 28 Jul 2024 13:23:40 -0700 Subject: feat(treesitter): add node_for_range function This is identical to `named_node_for_range` except that it includes anonymous nodes. This maintains consistency in the API because we already have `descendant_for_range` and `named_descendant_for_range`. --- runtime/lua/vim/treesitter/languagetree.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 3523ea95e0..03803f5869 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -1133,6 +1133,18 @@ function LanguageTree:tree_for_range(range, opts) return nil end +--- Gets the smallest node that contains {range}. +--- +---@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts +---@return TSNode? +function LanguageTree:node_for_range(range, opts) + local tree = self:tree_for_range(range, opts) + if tree then + return tree:root():descendant_for_range(unpack(range)) + end +end + --- Gets the smallest named node that contains {range}. --- ---@param range Range4 `{ start_line, start_col, end_line, end_col }` -- cgit From 1af55bfcf21b9bc7594b9c5ee0c2f60cbb887654 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 28 Jul 2024 13:30:33 -0700 Subject: feat(treesitter): allow get_node to return anonymous nodes Adds a new field `include_anonymous` to the `get_node` options to allow anonymous nodes to be returned. --- runtime/lua/vim/treesitter.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index e36aacfd94..4629203138 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -342,6 +342,9 @@ end --- --- Ignore injected languages (default true) --- @field ignore_injections boolean? +--- +--- Include anonymous nodes (default false) +--- @field include_anonymous boolean? --- Returns the smallest named node at the given position --- @@ -388,6 +391,9 @@ function M.get_node(opts) return end + if opts.include_anonymous then + return root_lang_tree:node_for_range(ts_range, opts) + end return root_lang_tree:named_node_for_range(ts_range, opts) end -- cgit From 94d42a3e7239a4035ee4429cbd71d5b0162b8289 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 28 Jul 2024 13:42:18 -0700 Subject: fix(treesitter): highlight anonymous nodes in inspect_tree **Problem:** With anonymous nodes toggled in the inspect tree, only named nodes will be highlighted when moving the cursor in the source code buffer. **Solution:** Retrieve the anonymous node at the cursor (when toggled on in the inspect tree) and highlight them when appropriate, for better clarity/specificity. --- runtime/lua/vim/treesitter/dev.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua index bd0ef5a011..e89aea2b85 100644 --- a/runtime/lua/vim/treesitter/dev.lua +++ b/runtime/lua/vim/treesitter/dev.lua @@ -183,6 +183,7 @@ local function set_inspector_cursor(treeview, lang, source_buf, inspect_buf, ins lang = lang, pos = pos, ignore_injections = false, + include_anonymous = treeview.opts.anon, }) if not cursor_node then return -- cgit From 0af056ebce189deedb58f7048108977fa5d81713 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 30 Jul 2024 11:46:24 +0800 Subject: vim-patch:49cdd62: runtime(doc): list of new/changed features in version9.txt closes: vim/vim#13753 https://github.com/vim/vim/commit/49cdd629a39d7e40e7349e65cb177e2442871a04 Co-authored-by: Yegappan Lakshmanan --- runtime/lua/vim/_meta/vimfn.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index bd6550941d..17cd6e3318 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -4699,6 +4699,10 @@ function vim.fn.isnan(expr) end --- for [key, value] in items(mydict) --- echo key .. ': ' .. value --- endfor +--- < +--- A List or a String argument is also supported. In these +--- cases, items() returns a List with the index and the value at +--- the index. --- --- @param dict any --- @return any -- cgit From 4e90bc30237ae81bf15e77c17ac8089a2cc74046 Mon Sep 17 00:00:00 2001 From: glepnir Date: Wed, 31 Jul 2024 22:15:34 +0800 Subject: feat(lsp): lsp.completion support set deprecated (#29882) Problem: CompletionItem in lsp spec mentioned the deprecated attribute Solution: when item has deprecated attribute set hl_group to DiagnosticDeprecated in complete function --- runtime/lua/vim/lsp/completion.lua | 8 ++++++++ runtime/lua/vim/lsp/protocol.lua | 12 +++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 1078e3eb7e..6a6659fd25 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -253,6 +253,13 @@ function M._lsp_to_complete_items(result, prefix, client_id) for _, item in ipairs(items) do if matches(item) then local word = get_completion_word(item) + local hl_group = '' + if + item.deprecated + or vim.list_contains((item.tags or {}), protocol.CompletionTag.Deprecated) + then + hl_group = 'DiagnosticDeprecated' + end table.insert(candidates, { word = word, abbr = item.label, @@ -262,6 +269,7 @@ function M._lsp_to_complete_items(result, prefix, client_id) icase = 1, dup = 1, empty = 1, + hl_group = hl_group, user_data = { nvim = { lsp = { diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 656921644d..b53f9a207a 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -99,6 +99,13 @@ local constants = { TriggerForIncompleteCompletions = 3, }, + -- Completion item tags are extra annotations that tweak the rendering of a + -- completion item + CompletionTag = { + -- Render a completion as obsolete, usually using a strike-out. + Deprecated = 1, + }, + -- A document highlight kind. DocumentHighlightKind = { -- A textual occurrence. @@ -433,13 +440,16 @@ function protocol.make_client_capabilities() snippetSupport = true, commitCharactersSupport = false, preselectSupport = false, - deprecatedSupport = false, + deprecatedSupport = true, documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, resolveSupport = { properties = { 'additionalTextEdits', }, }, + tagSupport = { + valueSet = get_value_set(constants.CompletionTag), + }, }, completionItemKind = { valueSet = get_value_set(constants.CompletionItemKind), -- cgit From 6bb40f3dbffb4b9858d9b13486d1832db8f51755 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Wed, 31 Jul 2024 23:18:24 +0900 Subject: fix(lsp): prevent desync due to empty buffer (#29904) Problem: Some language servers (e.g., rust-analyzer, texlab) are desynced when the user deletes the entire contents of the buffer. This is due to the discrepancy between how nvim computes diff and how nvim treats empty buffer. * diff: If the buffer became empty, then the diff includes the last line's eol. * empty buffer: Even if the buffer is empty, nvim regards it as having a single empty line with eol. Solution: Add special case for diff computation when the buffer becomes empty so that it does not include the eol of the last line. --- runtime/lua/vim/lsp/sync.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 936579e003..bdfe8d51b8 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -212,7 +212,8 @@ end ---@param lastline integer ---@param new_lastline integer ---@param offset_encoding string ----@return vim.lsp.sync.Range, vim.lsp.sync.Range +---@return vim.lsp.sync.Range prev_end_range +---@return vim.lsp.sync.Range curr_end_range local function compute_end_range( prev_lines, curr_lines, @@ -222,6 +223,16 @@ local function compute_end_range( new_lastline, offset_encoding ) + -- A special case for the following `firstline == new_lastline` case where lines are deleted. + -- Even if the buffer has become empty, nvim behaves as if it has an empty line with eol. + if #curr_lines == 1 and curr_lines[1] == '' then + local prev_line = prev_lines[lastline - 1] + return { + line_idx = lastline - 1, + byte_idx = #prev_line + 1, + char_idx = compute_line_length(prev_line, offset_encoding) + 1, + }, { line_idx = 1, byte_idx = 1, char_idx = 1 } + end -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- In this case, the last_byte... if firstline == new_lastline then -- cgit From 2b4049719ab6cc01afcde3b5be7ba33fd1e33ab4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Aug 2024 11:50:38 +0800 Subject: vim-patch:partial:f10911e: Update runtime files (#29936) https://github.com/vim/vim/commit/f10911e5db16f1fe6ab519c5d091ad0c1df0d063 Also cherry-pick E1142 and E1156 tags from Vim. Co-authored-by: Bram Moolenaar --- runtime/lua/vim/_meta/options.lua | 11 +++++++++++ runtime/lua/vim/_meta/vimfn.lua | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index fffc561604..ebb6ee2329 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -785,6 +785,17 @@ vim.bo.channel = vim.o.channel --- v:fname_in name of the input file --- v:fname_out name of the output file --- Note that v:fname_in and v:fname_out will never be the same. +--- +--- If the 'charconvert' expression starts with s: or ``, then it is +--- replaced with the script ID (`local-function`). Example: +--- +--- ```vim +--- set charconvert=s:MyConvert() +--- set charconvert=SomeConvert() +--- ``` +--- Otherwise the expression is evaluated in the context of the script +--- where the option was set, thus script-local items are available. +--- --- This option cannot be set from a `modeline` or in the `sandbox`, for --- security reasons. --- diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 17cd6e3318..4ec6925134 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -268,12 +268,12 @@ function vim.fn.assert_exception(error, msg) end --- < --- If {msg} is empty then it is not used. Do this to get the --- default message when passing the {lnum} argument. ---- +--- *E1115* --- When {lnum} is present and not negative, and the {error} --- argument is present and matches, then this is compared with --- the line number at which the error was reported. That can be --- the line number in a function or in a script. ---- +--- *E1116* --- When {context} is present it is used as a pattern and matched --- against the context (script name or function name) where --- {lnum} is located in. -- cgit From 32e128f20992e350b3e39c7469baa1f692418203 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 1 Aug 2024 16:00:48 +0200 Subject: fix(watch): exclude .git when using inotifywait (#29914) inotifywait man page specifies: The file must be specified with a relative or absolute path according to whether a relative or absolute path is given for watched directories. So it would only work this way in case the path is relative (which at least for gopls it is not) --- runtime/lua/vim/_watch.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua index 40f18ce5b0..3c090af3ff 100644 --- a/runtime/lua/vim/_watch.lua +++ b/runtime/lua/vim/_watch.lua @@ -277,7 +277,7 @@ function M.inotify(path, opts, callback) 'modify', '--event', 'move', - '@.git', -- ignore git directory + string.format('@%s/.git', path), -- ignore git directory path, }, { stderr = function(err, data) -- cgit From 720b309c786c4a258adccc9c468d433fb0f755b9 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 1 Aug 2024 16:01:15 +0200 Subject: fix(lsp): don't send foreign diagnostics to servers in buf.code_action (#29501) `buf.code_action` always included diagnostics on a given line from all clients. Servers should only receive diagnostics they published, and in the exact same format they sent it. Should fix https://github.com/neovim/neovim/issues/29500 --- runtime/lua/vim/lsp/buf.lua | 18 +++++++++++++----- runtime/lua/vim/lsp/diagnostic.lua | 18 ++++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index f20730b8e6..a512d48a06 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -852,14 +852,10 @@ function M.code_action(opts) if opts.diagnostics or opts.only then opts = { options = opts } end - local context = opts.context or {} + local context = opts.context and vim.deepcopy(opts.context) or {} if not context.triggerKind then context.triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Invoked end - if not context.diagnostics then - local bufnr = api.nvim_get_current_buf() - context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr) - end local mode = api.nvim_get_mode().mode local bufnr = api.nvim_get_current_buf() local win = api.nvim_get_current_win() @@ -901,6 +897,18 @@ function M.code_action(opts) else params = util.make_range_params(win, client.offset_encoding) end + if not context.diagnostics then + local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false) + local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true) + local diagnostics = {} + local lnum = api.nvim_win_get_cursor(0)[1] - 1 + vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum })) + vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum })) + ---@diagnostic disable-next-line: no-unknown + context.diagnostics = vim.tbl_map(function(d) + return d.user_data.lsp + end, diagnostics) + end params.context = context client.request(ms.textDocument_codeAction, params, on_result, bufnr) end diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 08cea13548..5ed42700e3 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -122,13 +122,7 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) code = diagnostic.code, _tags = tags_lsp_to_vim(diagnostic, client_id), user_data = { - lsp = { - -- usage of user_data.lsp.code is deprecated in favor of the top-level code field - code = diagnostic.code, - codeDescription = diagnostic.codeDescription, - relatedInformation = diagnostic.relatedInformation, - data = diagnostic.data, - }, + lsp = diagnostic, }, } end, diagnostics) @@ -157,8 +151,11 @@ local function diagnostic_vim_to_lsp(diagnostics) ---@param diagnostic vim.Diagnostic ---@return lsp.Diagnostic return vim.tbl_map(function(diagnostic) - return vim.tbl_extend('keep', { - -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp + local user_data = diagnostic.user_data or {} + if user_data.lsp then + return user_data.lsp + end + return { range = { start = { line = diagnostic.lnum, @@ -174,7 +171,7 @@ local function diagnostic_vim_to_lsp(diagnostics) source = diagnostic.source, code = diagnostic.code, tags = tags_vim_to_lsp(diagnostic), - }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {}) + } end, diagnostics) end @@ -366,6 +363,7 @@ end --- Structured: { [1] = {...}, [5] = {.... } } ---@private function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) + vim.deprecate('vim.lsp.diagnostic.get_line_diagnostics', 'vim.diagnostic.get', '0.12') convert_severity(opts) local diag_opts = {} --- @type vim.diagnostic.GetOpts -- cgit From 582bf4f1e15988565da53a91395e2d0131628fbb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Aug 2024 10:41:08 +0800 Subject: vim-patch:9.0.0634: evaluating "expr" options has more overhead than needed Problem: Evaluating "expr" options has more overhead than needed. Solution: Use call_simple_func() for 'foldtext', 'includeexpr', 'printexpr', "expr" of 'spellsuggest', 'diffexpr', 'patchexpr', 'balloonexpr', 'formatexpr', 'indentexpr' and 'charconvert'. https://github.com/vim/vim/commit/a4e0b9785e409e9e660171cea76dfcc5fdafad9b vim-patch:9.0.0635: build error and compiler warnings Problem: Build error and compiler warnings. Solution: Add missing change. Add type casts. https://github.com/vim/vim/commit/3292a229402c9892f5ab90645fbfe2b1db342f5b Co-authored-by: Bram Moolenaar --- runtime/lua/vim/_meta/options.lua | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index ebb6ee2329..10c888548c 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -786,6 +786,9 @@ vim.bo.channel = vim.o.channel --- v:fname_out name of the output file --- Note that v:fname_in and v:fname_out will never be the same. --- +--- The advantage of using a function call without arguments is that it is +--- faster, see `expr-option-function`. +--- --- If the 'charconvert' expression starts with s: or ``, then it is --- replaced with the script ID (`local-function`). Example: --- @@ -2521,6 +2524,9 @@ vim.wo.fdt = vim.wo.foldtext --- This will invoke the mylang#Format() function in the --- autoload/mylang.vim file in 'runtimepath'. `autoload` --- +--- The advantage of using a function call without arguments is that it is +--- faster, see `expr-option-function`. +--- --- The expression is also evaluated when 'textwidth' is set and adding --- text beyond that limit. This happens under the same conditions as --- when internal formatting is used. Make sure the cursor is kept in the @@ -3286,12 +3292,15 @@ vim.go.inc = vim.go.include --- the script ID (`local-function`). Example: --- --- ```vim ---- setlocal includeexpr=s:MyIncludeExpr(v:fname) ---- setlocal includeexpr=SomeIncludeExpr(v:fname) +--- setlocal includeexpr=s:MyIncludeExpr() +--- setlocal includeexpr=SomeIncludeExpr() --- ``` --- Otherwise, the expression is evaluated in the context of the script --- where the option was set, thus script-local items are available. --- +--- It is more efficient if the value is just a function call without +--- arguments, see `expr-option-function`. +--- --- The expression will be evaluated in the `sandbox` when set from a --- modeline, see `sandbox-option`. --- This option cannot be set in a modeline when 'modelineexpr' is off. @@ -3366,6 +3375,9 @@ vim.go.is = vim.go.incsearch --- Otherwise, the expression is evaluated in the context of the script --- where the option was set, thus script-local items are available. --- +--- The advantage of using a function call without arguments is that it is +--- faster, see `expr-option-function`. +--- --- The expression must return the number of spaces worth of indent. It --- can return "-1" to keep the current indent (this means 'autoindent' is --- used for the indent). @@ -6314,9 +6326,11 @@ vim.bo.spo = vim.bo.spelloptions --- The file is used for all languages. --- --- expr:{expr} Evaluate expression {expr}. Use a function to avoid ---- trouble with spaces. `v:val` holds the badly spelled ---- word. The expression must evaluate to a List of ---- Lists, each with a suggestion and a score. +--- trouble with spaces. Best is to call a function +--- without arguments, see `expr-option-function|. +--- |v:val` holds the badly spelled word. The expression +--- must evaluate to a List of Lists, each with a +--- suggestion and a score. --- Example: --- [['the', 33], ['that', 44]] ~ --- Set 'verbose' and use `z=` to see the scores that the -- cgit From e7f8349a2eec01dda531d93fecb8df920b042d9f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 2 Aug 2024 20:13:17 +0200 Subject: vim-patch:9.1.0655: filetype: goaccess config file not recognized Problem: filetype: goaccess config file not recognized Solution: detect 'goaccess.conf' as goaccess filetype, also include a basic syntax and ftplugin (Adam Monsen) Add syntax highlighting for GoAccess configuration file. GoAccess is a real-time web log analyzer and interactive viewer that runs in a terminal in *nix systems or through your browser. GoAccess home page: https://goaccess.io closes: vim/vim#15414 https://github.com/vim/vim/commit/0aa65b48fbe64e18a767b207802483026baecb5d Co-authored-by: Adam Monsen --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 52b5392467..3dea4e1046 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1452,6 +1452,7 @@ local filename = { gnashpluginrc = 'gnash', gnashrc = 'gnash', ['.gnuplot_history'] = 'gnuplot', + ['goaccess.conf'] = 'goaccess', ['go.sum'] = 'gosum', ['go.work.sum'] = 'gosum', ['go.work'] = 'gowork', -- cgit From 6072153796d1b1e54067ac9823583be96b24ede1 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 3 Aug 2024 11:14:12 +0200 Subject: feat(lsp): announce codeLens resolveSupport (#29956) The codelens implementation can resolve command via `codeLens/resolve`. The spec added client capabilities for that: https://github.com/microsoft/language-server-protocol/pull/1979 --- runtime/lua/vim/lsp/protocol.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index b53f9a207a..2514a62f89 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -427,6 +427,12 @@ function protocol.make_client_capabilities() properties = { 'edit' }, }, }, + codeLens = { + dynamicRegistration = false, + resolveSupport = { + properties = { 'command' }, + }, + }, formatting = { dynamicRegistration = true, }, -- cgit From eb629cce917155a4d436327db10c8b1b44ae7861 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 3 Aug 2024 18:14:34 +0900 Subject: fix(lsp): redundant spaces in lsp log (#29970) --- runtime/lua/vim/lsp/log.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 0438ca84af..4f177b47fd 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -19,7 +19,7 @@ local current_log_level = log_levels.WARN local log_date_format = '%F %H:%M:%S' local function format_func(arg) - return vim.inspect(arg, { newline = '' }) + return vim.inspect(arg, { newline = ' ', indent = '' }) end local function notify(msg, level) -- cgit From 66a74535d40c6b68d38cb92088315fa67dc1304b Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Thu, 1 Aug 2024 12:43:42 +0300 Subject: refactor(filetype): use file name match instead of pattern if possible Problem: some patterns are used as a replacement for one-two explicit file matches (like '^[mM]akefile$'). As matching file name directly is faster and more explicit, it should be preferred. Solution: move those patterns to direct file name match. NOTE: this is not strictly backwards compatible, because exact file name matching is done *before* pattern matching. If user has conflicting `vim.filetype.add()` call with high priority (like with `pattern='file$'` and `priority=100`), after this change it will be ignored (i.e. 'makefile' will match exactly). Judging by converted cases, it seems reasonable to prefer exact matches there. --- runtime/lua/vim/filetype.lua | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 3dea4e1046..c7f8041172 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1332,7 +1332,17 @@ local filename = { ['/.aptitude/config'] = 'aptconf', ['=tagging-method'] = 'arch', ['.arch-inventory'] = 'arch', + ['makefile.am'] = 'automake', + ['Makefile.am'] = 'automake', ['GNUmakefile.am'] = 'automake', + ['.bash_aliases'] = detect.bash, + ['.bash-aliases'] = detect.bash, + ['.bash_history'] = detect.bash, + ['.bash-history'] = detect.bash, + ['.bash_logout'] = detect.bash, + ['.bash-logout'] = detect.bash, + ['.bash_profile'] = detect.bash, + ['.bash-profile'] = detect.bash, ['named.root'] = 'bindzone', WORKSPACE = 'bzl', ['WORKSPACE.bzlmod'] = 'bzl', @@ -1507,6 +1517,8 @@ local filename = { ['.swrc'] = 'jsonc', ['.vsconfig'] = 'jsonc', ['.justfile'] = 'just', + ['justfile'] = 'just', + ['Justfile'] = 'just', Kconfig = 'kconfig', ['Kconfig.debug'] = 'kconfig', ['Config.in'] = 'kconfig', @@ -1558,6 +1570,8 @@ local filename = { mrxvtrc = 'mrxvtrc', ['.mrxvtrc'] = 'mrxvtrc', ['.msmtprc'] = 'msmtp', + ['Muttngrc'] = 'muttrc', + ['Muttrc'] = 'muttrc', ['.mysql_history'] = 'mysql', ['/etc/nanorc'] = 'nanorc', Neomuttrc = 'neomuttrc', @@ -1582,6 +1596,9 @@ local filename = { ['/etc/shadow-'] = 'passwd', ['/etc/shadow'] = 'passwd', ['/etc/passwd.edit'] = 'passwd', + ['.gitolite.rc'] = 'perl', + ['gitolite.rc'] = 'perl', + ['example.gitolite.rc'] = 'perl', ['latexmkrc'] = 'perl', ['.latexmkrc'] = 'perl', ['pf.conf'] = 'pf', @@ -1637,6 +1654,10 @@ local filename = { irbrc = 'ruby', ['.irb_history'] = 'ruby', irb_history = 'ruby', + ['rakefile'] = 'ruby', + ['Rakefile'] = 'ruby', + ['rantfile'] = 'ruby', + ['Rantfile'] = 'ruby', Vagrantfile = 'ruby', ['smb.conf'] = 'samba', screenrc = 'screen', @@ -2074,13 +2095,6 @@ local pattern = { ['%.git/info/exclude$'] = 'gitignore', ['/%.config/git/ignore$'] = 'gitignore', }, - ['bash'] = { - ['^%.bash[_%-]aliases$'] = detect.bash, - ['^%.bash[_%-]history$'] = detect.bash, - ['^%.bash[_%-]logout$'] = detect.bash, - ['^%.bash[_%-]profile$'] = detect.bash, - ['^bash%-fc[%-%.]'] = detect.bash, - }, ['%.cfg'] = { ['enlightenment/.*%.cfg$'] = 'c', ['Eterm/.*%.cfg$'] = 'eterm', @@ -2121,15 +2135,11 @@ local pattern = { ['%.sst%.meta$'] = 'sisu', }, ['file'] = { - ['^[mM]akefile%.am$'] = 'automake', ['^Containerfile%.'] = starsetf('dockerfile'), ['^Dockerfile%.'] = starsetf('dockerfile'), - ['^[jJ]ustfile$'] = 'just', ['[mM]akefile$'] = detect.make, ['^[mM]akefile'] = starsetf('make'), - ['^[rR]akefile$'] = 'ruby', ['^[rR]akefile'] = starsetf('ruby'), - ['^[rR]antfile$'] = 'ruby', ['^%.profile'] = detect.sh, }, ['fvwm'] = { @@ -2169,9 +2179,7 @@ local pattern = { ['/%.mutt/muttrc'] = detect_muttrc, ['/%.muttng/muttngrc'] = detect_muttrc, ['/%.muttng/muttrc'] = detect_muttrc, - ['^Muttngrc$'] = 'muttrc', ['^Muttngrc'] = detect_muttrc, - ['^Muttrc$'] = 'muttrc', ['^Muttrc'] = detect_muttrc, -- neomuttrc* and .neomuttrc* ['^%.?neomuttrc'] = detect_neomuttrc, @@ -2195,6 +2203,7 @@ local pattern = { ['%.vbproj%.user$'] = 'xml', }, [''] = { + ['^bash%-fc[%-%.]'] = detect.bash, ['/bind/db%.'] = starsetf('bindzone'), ['/named/db%.'] = starsetf('bindzone'), ['%.blade%.php$'] = 'blade', @@ -2265,8 +2274,6 @@ local pattern = { ['%.opam%.locked$'] = 'opam', ['%.opam%.template$'] = 'opam', ['%.[Oo][Pp][Ll]$'] = 'opl', - ['^%.?gitolite%.rc$'] = 'perl', - ['^example%.gitolite%.rc$'] = 'perl', ['%.php%d$'] = 'php', ['%.[Pp][Rr][Gg]$'] = detect.prg, ['printcap'] = starsetf(function(path, bufnr) -- cgit From 95e0289cb24e349b0ac1b170adefc57b767d2e78 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 19 Jul 2024 12:01:27 +0300 Subject: refactor(filetype): use extension match instead of pattern if possible Problem: some patterns are used as a replacement for several explicit extension matches (like '%.[Ss][Yy][Ss]$', '%.php%d$', etc.). They usually correspond to Vim's "ignore case" regexes (like '*.sys\c') and "convenience" patterns to not define many of them (like '*.php\d'). As matching extension directly is faster and more explicit, it should be preferred. Solution: move all such patterns to direct extension match. --- runtime/lua/vim/filetype.lua | 118 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 17 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c7f8041172..6343a540ed 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -273,6 +273,16 @@ local extension = { cfm = 'cf', cfi = 'cf', hgrc = 'cfg', + -- Extension match does not conflict with specific patterns such as '.*/etc/a2ps/.*%.cfg', etc., + -- as it is done after those are tried to match + cfg = detect.cfg, + cfG = detect.cfg, + cFg = detect.cfg, + cFG = detect.cfg, + Cfg = detect.cfg, + CfG = detect.cfg, + CFg = detect.cfg, + CFG = detect.cfg, chf = 'ch', chai = 'chaiscript', ch = detect.change, @@ -355,6 +365,14 @@ local extension = { dart = 'dart', drt = 'dart', ds = 'datascript', + dat = detect.dat, + daT = detect.dat, + dAt = detect.dat, + dAT = detect.dat, + Dat = detect.dat, + DaT = detect.dat, + DAt = detect.dat, + DAT = detect.dat, dcd = 'dcd', decl = detect.decl, dec = detect.decl, @@ -635,6 +653,14 @@ local extension = { kts = 'kotlin', kt = 'kotlin', ktm = 'kotlin', + sub = 'krl', + suB = 'krl', + sUb = 'krl', + sUB = 'krl', + Sub = 'krl', + SuB = 'krl', + SUb = 'krl', + SUB = 'krl', ks = 'kscript', k = 'kwt', ACE = 'lace', @@ -668,6 +694,14 @@ local extension = { lt = 'lite', lite = 'lite', livemd = 'livebook', + log = detect.log, + loG = detect.log, + lOg = detect.log, + lOG = detect.log, + Log = detect.log, + LoG = detect.log, + LOg = detect.log, + LOG = detect.log, lgt = 'logtalk', lotos = 'lotos', lot = detect_line1('\\contentsline', 'tex', 'lotos'), @@ -734,6 +768,14 @@ local extension = { wl = 'mma', mmp = 'mmp', mms = detect.mms, + mod = detect.mod, + moD = detect.mod, + mOd = detect.mod, + mOD = detect.mod, + Mod = detect.mod, + MoD = detect.mod, + MOd = detect.mod, + MOD = detect.mod, DEF = 'modula2', m3 = 'modula3', i3 = 'modula3', @@ -763,6 +805,14 @@ local extension = { n1ql = 'n1ql', nql = 'n1ql', nanorc = 'nanorc', + NSA = 'natural', + NSC = 'natural', + NSG = 'natural', + NSL = 'natural', + NSM = 'natural', + NSN = 'natural', + NSP = 'natural', + NSS = 'natural', ncf = 'ncf', nginx = 'nginx', nim = 'nim', @@ -772,6 +822,15 @@ local extension = { nix = 'nix', norg = 'norg', nqc = 'nqc', + ['1'] = detect.nroff, + ['2'] = detect.nroff, + ['3'] = detect.nroff, + ['4'] = detect.nroff, + ['5'] = detect.nroff, + ['6'] = detect.nroff, + ['7'] = detect.nroff, + ['8'] = detect.nroff, + ['9'] = detect.nroff, roff = 'nroff', tmac = 'nroff', man = 'nroff', @@ -803,6 +862,14 @@ local extension = { ['or'] = 'openroad', scad = 'openscad', ovpn = 'openvpn', + opl = 'opl', + opL = 'opl', + oPl = 'opl', + oPL = 'opl', + Opl = 'opl', + OpL = 'opl', + OPl = 'opl', + OPL = 'opl', ora = 'ora', org = 'org', org_archive = 'org', @@ -834,6 +901,16 @@ local extension = { ctp = 'php', php = 'php', phpt = 'php', + php0 = 'php', + php1 = 'php', + php2 = 'php', + php3 = 'php', + php4 = 'php', + php5 = 'php', + php6 = 'php', + php7 = 'php', + php8 = 'php', + php9 = 'php', phtml = 'php', theme = 'php', pike = 'pike', @@ -866,6 +943,14 @@ local extension = { it = 'ppwiz', ih = 'ppwiz', action = 'privoxy', + prg = detect.prg, + prG = detect.prg, + pRg = detect.prg, + pRG = detect.prg, + Prg = detect.prg, + PrG = detect.prg, + PRg = detect.prg, + PRG = detect.prg, pc = 'proc', pdb = 'prolog', pml = 'promela', @@ -1043,6 +1128,14 @@ local extension = { sqi = 'sqr', sqr = 'sqr', nut = 'squirrel', + src = detect.src, + srC = detect.src, + sRc = detect.src, + sRC = detect.src, + Src = detect.src, + SrC = detect.src, + SRc = detect.src, + SRC = detect.src, s28 = 'srec', s37 = 'srec', srec = 'srec', @@ -1069,6 +1162,14 @@ local extension = { swift = 'swift', swig = 'swig', swg = 'swig', + sys = detect.sys, + syS = detect.sys, + sYs = detect.sys, + sYS = detect.sys, + Sys = detect.sys, + SyS = detect.sys, + SYs = detect.sys, + SYS = detect.sys, svh = 'systemverilog', sv = 'systemverilog', cmm = 'trace32', @@ -2210,19 +2311,12 @@ local pattern = { ['^bzr_log%.'] = 'bzr', ['^cabal%.project%.'] = starsetf('cabalproject'), ['^sgml%.catalog'] = starsetf('catalog'), - ['%.[Cc][Ff][Gg]$'] = { - detect.cfg, - -- Decrease priority to avoid conflicts with more specific patterns - -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. - { priority = -1 }, - }, ['hgrc$'] = 'cfg', ['^[cC]hange[lL]og'] = starsetf(detect.changelog), ['%.%.ch$'] = 'chill', ['%.cmake%.in$'] = 'cmake', ['^crontab%.'] = starsetf('crontab'), ['^cvs%d+$'] = 'cvs', - ['%.[Dd][Aa][Tt]$'] = detect.dat, ['^php%.ini%-'] = 'dosini', ['^drac%.'] = starsetf('dracula'), ['/dtrace/.*%.d$'] = 'dtrace', @@ -2253,38 +2347,28 @@ local pattern = { ['^[jt]sconfig.*%.json$'] = 'jsonc', ['^Config%.in%.'] = starsetf('kconfig'), ['^Kconfig%.'] = starsetf('kconfig'), - ['%.[Ss][Uu][Bb]$'] = 'krl', ['/ldscripts/'] = 'ld', ['lftp/rc$'] = 'lftp', ['/LiteStep/.*/.*%.rc$'] = 'litestep', - ['%.[Ll][Oo][Gg]$'] = detect.log, ['^/tmp/SLRN[0-9A-Z.]+$'] = 'mail', ['^ae%d+%.txt$'] = 'mail', ['^pico%.%d+$'] = 'mail', ['^reportbug%-'] = starsetf('mail'), ['^snd%.%d+$'] = 'mail', - ['%.[Mm][Oo][Dd]$'] = detect.mod, ['^rndc.*%.key$'] = 'named', - ['%.NS[ACGLMNPS]$'] = 'natural', - ['%.[1-9]$'] = detect.nroff, ['^tmac%.'] = starsetf('nroff'), ['%.ml%.cppo$'] = 'ocaml', ['%.mli%.cppo$'] = 'ocaml', ['/octave/history$'] = 'octave', ['%.opam%.locked$'] = 'opam', ['%.opam%.template$'] = 'opam', - ['%.[Oo][Pp][Ll]$'] = 'opl', - ['%.php%d$'] = 'php', - ['%.[Pp][Rr][Gg]$'] = detect.prg, ['printcap'] = starsetf(function(path, bufnr) return require('vim.filetype.detect').printcap('print') end), ['/queries/.*%.scm$'] = 'query', -- treesitter queries (Neovim only) [',v$'] = 'rcs', - ['%.[Ss][Rr][Cc]$'] = detect.src, ['^svn%-commit.*%.tmp$'] = 'svn', ['%.swift%.gyb$'] = 'swiftgyb', - ['%.[Ss][Yy][Ss]$'] = detect.sys, ['termcap'] = starsetf(function(path, bufnr) return require('vim.filetype.detect').printcap('term') end), -- cgit From 37910f270341d8b36f2f26b6d628274b85e2522b Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 23 Jul 2024 14:35:45 +0300 Subject: docs(filetype): add note about prefering explicit lists over pattern --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 6343a540ed..4192645acb 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1896,6 +1896,8 @@ local detect_xkb = starsetf('xkb', { parent = '/usr/' }) --- Vim regexes are converted into explicit Lua patterns (without implicit anchoring): --- '*/debian/changelog' -> '/debian/changelog$' --- '*/bind/db.*' -> '/bind/db%.' +--- +--- See more info in `:h dev-vimpatch-filetype`. --- @type table local pattern = { -- BEGIN PATTERN -- cgit From 3b58d93aaeaea363ff1066fc791f5d8af1946218 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 3 Aug 2024 13:04:47 +0200 Subject: docs(filetype): consolidate comments in dev_vimpatch.txt --- runtime/lua/vim/filetype.lua | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 4192645acb..71a49445de 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -174,9 +174,15 @@ end -- luacheck: push no unused args -- luacheck: push ignore 122 --- Filetypes based on file extension +-- Filetype detection logic is encoded in three tables: +-- 1. `extension` for literal extension lookup +-- 2. `filename` for literal full path or basename lookup; +-- 3. `pattern` for matching filenames or paths against Lua patterns, +-- optimized for fast lookup. +-- See `:h dev-vimpatch-filetype` for guidance when porting Vim filetype patches. + ---@diagnostic disable: unused-local ---- @type vim.filetype.mapping +---@type vim.filetype.mapping local extension = { -- BEGIN EXTENSION ['8th'] = '8th', @@ -273,8 +279,6 @@ local extension = { cfm = 'cf', cfi = 'cf', hgrc = 'cfg', - -- Extension match does not conflict with specific patterns such as '.*/etc/a2ps/.*%.cfg', etc., - -- as it is done after those are tried to match cfg = detect.cfg, cfG = detect.cfg, cFg = detect.cfg, @@ -1418,7 +1422,7 @@ local extension = { -- END EXTENSION } ---- @type vim.filetype.mapping +---@type vim.filetype.mapping local filename = { -- BEGIN FILENAME ['a2psrc'] = 'a2ps', @@ -1884,21 +1888,7 @@ local detect_muttrc = starsetf('muttrc', { parent = 'utt' }) local detect_neomuttrc = starsetf('neomuttrc', { parent = 'utt' }) local detect_xkb = starsetf('xkb', { parent = '/usr/' }) ---- Table of filetype pattern matching rules grouped by their parent pattern. ---- ---- Every filetype pattern match is prefaced with a matching of its parent pattern. ---- If there is no match, skip all matching inside group. ---- Note that unlike leaf patterns, parent patterns do not have special matching behaviour if they ---- contain a `/`. ---- ---- When modifying an existing regular pattern, make sure that it still fits its group. ---- ---- Vim regexes are converted into explicit Lua patterns (without implicit anchoring): ---- '*/debian/changelog' -> '/debian/changelog$' ---- '*/bind/db.*' -> '/bind/db%.' ---- ---- See more info in `:h dev-vimpatch-filetype`. ---- @type table +---@type table local pattern = { -- BEGIN PATTERN ['/debian/'] = { -- cgit From 28fbba2092adb9659253434605cb94252241f5e0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 6 Aug 2024 20:49:59 +0800 Subject: vim-patch:9.1.0465: missing filecopy() function (#29989) Problem: missing filecopy() function Solution: implement filecopy() Vim script function (Shougo Matsushita) closes: vim/vim#12346 https://github.com/vim/vim/commit/60c8743ab6c90e402e6ed49d27455ef7e5698abe Co-authored-by: Shougo Matsushita --- runtime/lua/vim/_meta/vimfn.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 4ec6925134..4f9cc881c1 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1993,6 +1993,19 @@ function vim.fn.feedkeys(string, mode) end --- @return any function vim.fn.file_readable(file) end +--- Copy the file pointed to by the name {from} to {to}. The +--- result is a Number, which is |TRUE| if the file was copied +--- successfully, and |FALSE| when it failed. +--- If a file with name {to} already exists, it will fail. +--- Note that it does not handle directories (yet). +--- +--- This function is not available in the |sandbox|. +--- +--- @param from string +--- @param to string +--- @return 0|1 +function vim.fn.filecopy(from, to) end + --- The result is a Number, which is |TRUE| when a file with the --- name {file} exists, and can be read. If {file} doesn't exist, --- or is a directory, the result is |FALSE|. {file} is any -- cgit From 37952bf7b442cac794c4663f2e0123e7d72bc443 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 6 Aug 2024 21:19:12 +0800 Subject: vim-patch:8.2.4838: checking for absolute path is not trivial (#29990) Problem: Checking for absolute path is not trivial. Solution: Add isabsolutepath(). (closes vim/vim#10303) https://github.com/vim/vim/commit/dca1d40cd0f2af0755519e7028378bd3c8fefd31 vim-patch:8a3b805c6c9c Co-authored-by: LemonBoy --- runtime/lua/vim/_meta/vimfn.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 4f9cc881c1..9cddf0e81f 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -4659,6 +4659,24 @@ function vim.fn.interrupt() end --- @return any function vim.fn.invert(expr) end +--- The result is a Number, which is |TRUE| when {path} is an +--- absolute path. +--- On Unix, a path is considered absolute when it starts with '/'. +--- On MS-Windows, it is considered absolute when it starts with an +--- optional drive prefix and is followed by a '\' or '/'. UNC paths +--- are always absolute. +--- Example: >vim +--- echo isabsolutepath('/usr/share/') " 1 +--- echo isabsolutepath('./foobar') " 0 +--- echo isabsolutepath('C:\Windows') " 1 +--- echo isabsolutepath('foobar') " 0 +--- echo isabsolutepath('\\remote\file') " 1 +--- < +--- +--- @param path any +--- @return 0|1 +function vim.fn.isabsolutepath(path) end + --- The result is a Number, which is |TRUE| when a directory --- with the name {directory} exists. If {directory} doesn't --- exist, or isn't a directory, the result is |FALSE|. {directory} -- cgit From 0a1212ef94547f04db789a660639fab6837e00ce Mon Sep 17 00:00:00 2001 From: Yi Ming Date: Tue, 6 Aug 2024 19:28:42 +0800 Subject: docs(treesitter): generate inline docs for `Range`s docs(treesitter): in-place parameter description docs(treesitter): remove internal type names docs(treesitter): add missing private annotation --- runtime/lua/vim/treesitter/_range.lua | 4 ++++ runtime/lua/vim/treesitter/languagetree.lua | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/_range.lua b/runtime/lua/vim/treesitter/_range.lua index 8d727c3c52..82ab8517aa 100644 --- a/runtime/lua/vim/treesitter/_range.lua +++ b/runtime/lua/vim/treesitter/_range.lua @@ -3,16 +3,19 @@ local api = vim.api local M = {} ---@class Range2 +---@inlinedoc ---@field [1] integer start row ---@field [2] integer end row ---@class Range4 +---@inlinedoc ---@field [1] integer start row ---@field [2] integer start column ---@field [3] integer end row ---@field [4] integer end column ---@class Range6 +---@inlinedoc ---@field [1] integer start row ---@field [2] integer start column ---@field [3] integer start bytes @@ -150,6 +153,7 @@ function M.contains(r1, r2) return true end +--- @private --- @param source integer|string --- @param index integer --- @return integer diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 03803f5869..d43a0a5d0b 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -638,6 +638,8 @@ end ---Gets the set of included regions managed by this LanguageTree. This can be different from the ---regions set by injection query, because a partial |LanguageTree:parse()| drops the regions ---outside the requested range. +---Each list represents a range in the form of +---{ {start_row}, {start_col}, {start_bytes}, {end_row}, {end_col}, {end_bytes} }. ---@return table function LanguageTree:included_regions() if self._regions then @@ -1087,7 +1089,7 @@ end --- Determines whether {range} is contained in the |LanguageTree|. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@return boolean function LanguageTree:contains(range) for _, tree in pairs(self._trees) do @@ -1108,7 +1110,7 @@ end --- Gets the tree that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts ---@return TSTree? function LanguageTree:tree_for_range(range, opts) @@ -1135,7 +1137,7 @@ end --- Gets the smallest node that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts ---@return TSNode? function LanguageTree:node_for_range(range, opts) @@ -1147,7 +1149,7 @@ end --- Gets the smallest named node that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts ---@return TSNode? function LanguageTree:named_node_for_range(range, opts) @@ -1159,7 +1161,7 @@ end --- Gets the appropriate language that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@return vim.treesitter.LanguageTree tree Managing {range} function LanguageTree:language_for_range(range) for _, child in pairs(self._children) do -- cgit From 7031949be065870f0daf74a9f1be3df47f83312c Mon Sep 17 00:00:00 2001 From: Grzegorz Rozdzialik Date: Wed, 7 Aug 2024 17:28:01 +0200 Subject: fix(lsp): avoid reusing diagnostics from different servers in actions (#30002) Problem: When preparing the parameters for a code actions LSP request, the code set `context.diagnostics` when processing the first LSP client, and then reused those `context.diagnostics` for subsequent LSP clients. This meant that the second and next LSP clients got diagnostics that did not originate from them, and they did not get the diagnostics that they sent. Solution: Avoid setting `context.diagnostics` (which is referenced by all clients). Instead, set `params.context.diagnostics` directly, which is specific to a single client. Fixes #30001 Caused by #29501 --- runtime/lua/vim/lsp/buf.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index a512d48a06..d7463d74f8 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -897,19 +897,23 @@ function M.code_action(opts) else params = util.make_range_params(win, client.offset_encoding) end - if not context.diagnostics then + if context.diagnostics then + params.context = context + else local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false) local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true) local diagnostics = {} local lnum = api.nvim_win_get_cursor(0)[1] - 1 vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum })) vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum })) - ---@diagnostic disable-next-line: no-unknown - context.diagnostics = vim.tbl_map(function(d) - return d.user_data.lsp - end, diagnostics) + params.context = vim.tbl_extend('force', context, { + ---@diagnostic disable-next-line: no-unknown + diagnostics = vim.tbl_map(function(d) + return d.user_data.lsp + end, diagnostics), + }) end - params.context = context + client.request(ms.textDocument_codeAction, params, on_result, bufnr) end end -- cgit From e01ccda1bebf2d420d725478b480740ff45ad6ad Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 9 Aug 2024 07:05:33 +0800 Subject: vim-patch:0cc5dce: runtime(doc): clarify directory of Vim's executable vs CWD According to :h win32-PATH, "the same directory as Vim" means the same directory as the Vim executable, not Vim's current directory. In patch 8.2.4860 these two concepts were mixed up. closes: vim/vim#15451 https://github.com/vim/vim/commit/0cc5dce5780d39fe621f6146d4fb862318918125 --- runtime/lua/vim/_meta/vimfn.lua | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 9cddf0e81f..62f9e0e702 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1586,8 +1586,10 @@ function vim.fn.eventhandler() end --- This function checks if an executable with the name {expr} --- exists. {expr} must be the name of the program without any --- arguments. +--- --- executable() uses the value of $PATH and/or the normal ---- searchpath for programs. *PATHEXT* +--- searchpath for programs. +--- *PATHEXT* --- On MS-Windows the ".exe", ".bat", etc. can optionally be --- included. Then the extensions in $PATHEXT are tried. Thus if --- "foo.exe" does not exist, "foo.exe.bat" can be found. If @@ -1597,8 +1599,13 @@ function vim.fn.eventhandler() end --- then the name is also tried without adding an extension. --- On MS-Windows it only checks if the file exists and is not a --- directory, not if it's really executable. ---- On Windows an executable in the same directory as Vim is ---- always found (it is added to $PATH at |startup|). +--- On MS-Windows an executable in the same directory as the Vim +--- executable is always found (it's added to $PATH at |startup|). +--- *NoDefaultCurrentDirectoryInExePath* +--- On MS-Windows an executable in Vim's current working directory +--- is also normally found, but this can be disabled by setting +--- the $NoDefaultCurrentDirectoryInExePath environment variable. +--- --- The result is a Number: --- 1 exists --- 0 does not exist -- cgit From 8df6736ca14d09f87cf0a8486758ac5708819434 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 24 May 2023 10:04:49 +0200 Subject: feat(term): enable reflow by default (#21124) Problem: Contents of terminal buffer are not reflown when Nvim is resized. Solution: Enable reflow in libvterm by default. Now that libvterm is vendored, also fix "TUI rapid resize" test failures there. Note: Neovim's scrollback buffer does not support reflow (yet), so lines vanishing into the buffer due to a too small window will be restored without reflow. --- runtime/lua/vim/_meta/options.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 10c888548c..b4ac478b61 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -5253,6 +5253,9 @@ vim.wo.scr = vim.wo.scroll --- Minimum is 1, maximum is 100000. --- Only in `terminal` buffers. --- +--- Note: Lines that are not visible and kept in scrollback are not +--- reflown when the terminal buffer is resized horizontally. +--- --- @type integer vim.o.scrollback = -1 vim.o.scbk = vim.o.scrollback -- cgit From 9b5ab66678f8efa1f5fe89205839fe053fe5efaf Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 11 Aug 2024 11:58:15 +0100 Subject: test(lsp): refactor and tidy - Merge all the top level 'LSP' describe blocks - Refactor text edit tests - Fix typing errors - Add linebreaks between tests --- runtime/lua/vim/_meta/builtin_types.lua | 66 +++++++++++++++++++++++++++++++++ runtime/lua/vim/_meta/vimfn.lua | 2 +- runtime/lua/vim/lsp/util.lua | 4 +- 3 files changed, 69 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua index 9afb8c84f4..aca6649957 100644 --- a/runtime/lua/vim/_meta/builtin_types.lua +++ b/runtime/lua/vim/_meta/builtin_types.lua @@ -140,3 +140,69 @@ --- @field sid string --- @field variables? table --- @field version 1 + +--- @class vim.fn.undotree.entry +--- +--- Undo sequence number. Same as what appears in +--- \|:undolist|. +--- @field seq integer +--- +--- Timestamp when the change happened. Use +--- \|strftime()| to convert to something readable. +--- @field time integer +--- +--- Only appears in the item that is the last one +--- that was added. This marks the last change +--- and where further changes will be added. +--- @field newhead? integer +--- +--- Only appears in the item that is the last one +--- that was undone. This marks the current +--- position in the undo tree, the block that will +--- be used by a redo command. When nothing was +--- undone after the last change this item will +--- not appear anywhere. +--- @field curhead? integer +--- +--- Only appears on the last block before a file +--- write. The number is the write count. The +--- first write has number 1, the last one the +--- "save_last" mentioned above. +--- @field save integer +--- +--- Alternate entry. This is again a List of undo +--- blocks. Each item may again have an "alt" +--- item. +--- @field alt vim.fn.undotree.entry[] + +--- @class vim.fn.undotree.ret +--- +--- The highest undo sequence number used. +--- @field seq_last integer +--- +--- The sequence number of the current position in +--- the undo tree. This differs from "seq_last" +--- when some changes were undone. +--- @field seq_cur integer +--- +--- Time last used for |:earlier| and related +--- commands. Use |strftime()| to convert to +--- something readable. +--- @field time_cur integer +--- +--- Number of the last file write. Zero when no +--- write yet. +--- @field save_last integer +--- +--- Number of the current position in the undo +--- tree. +--- @field save_cur integer +--- +--- Non-zero when the last undo block was synced. +--- This happens when waiting from input from the +--- user. See |undo-blocks|. +--- @field synced integer +--- +--- A list of dictionaries with information about +--- undo blocks. +--- @field entries vim.fn.undotree.entry[] diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 62f9e0e702..54ac60e272 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -10403,7 +10403,7 @@ function vim.fn.undofile(name) end --- item. --- --- @param buf? integer|string ---- @return any +--- @return vim.fn.undotree.ret function vim.fn.undotree(buf) end --- Remove second and succeeding copies of repeated adjacent diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 59ae3beae4..cbbe3a66b7 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1442,7 +1442,7 @@ end --- Computes size of float needed to show contents (with optional wrapping) --- ---@param contents table of lines to show in window ----@param opts table with optional fields +---@param opts? table with optional fields --- - height of floating window --- - width of floating window --- - wrap_at character to wrap at for computing height @@ -1821,7 +1821,7 @@ end --- Converts symbols to quickfix list items. --- ---@param symbols table DocumentSymbol[] or SymbolInformation[] ----@param bufnr integer +---@param bufnr? integer function M.symbols_to_items(symbols, bufnr) local function _symbols_to_items(_symbols, _items, _bufnr) for _, symbol in ipairs(_symbols) do -- cgit From 65a703e06063c85c3dd5fdb3ad4e1207a622ef30 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 12 Aug 2024 01:03:48 -0600 Subject: fix(lua): ignore stdout and stderr for xdg-open Ref #19724 Fix #29932 --- runtime/lua/vim/ui.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 79638a044a..dccdbf32cc 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -140,6 +140,9 @@ function M.open(path) end local cmd --- @type string[] + local opts --- @type vim.SystemOpts + + opts = { text = true, detach = true } if vim.fn.has('mac') == 1 then cmd = { 'open', path } @@ -155,11 +158,13 @@ function M.open(path) cmd = { 'explorer.exe', path } elseif vim.fn.executable('xdg-open') == 1 then cmd = { 'xdg-open', path } + opts.stdout = false + opts.stderr = false else return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)' end - return vim.system(cmd, { text = true, detach = true }), nil + return vim.system(cmd, opts), nil end --- Gets the URL at cursor, if any. -- cgit From 67bb0cfa79bc7eea5103ce9a00fc6176077c135b Mon Sep 17 00:00:00 2001 From: futsuuu Date: Sat, 20 Jul 2024 14:46:27 +0900 Subject: fix(loader): follow the style of the error message for built-in loaders start the error message with '\n\t' instead of '\n' surround the module name by single quotes --- runtime/lua/vim/loader.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua index ea77a22416..2a881d1602 100644 --- a/runtime/lua/vim/loader.lua +++ b/runtime/lua/vim/loader.lua @@ -200,7 +200,7 @@ function Loader.loader(modname) return chunk or error(err) end Loader._hashes = nil - return '\ncache_loader: module ' .. modname .. ' not found' + return ("\n\tcache_loader: module '%s' not found"):format(modname) end --- The `package.loaders` loader for libs @@ -222,7 +222,7 @@ function Loader.loader_lib(modname) local chunk, err = package.loadlib(ret.modpath, 'luaopen_' .. funcname:gsub('%.', '_')) return chunk or error(err) end - return '\ncache_loader_lib: module ' .. modname .. ' not found' + return ("\n\tcache_loader_lib: module '%s' not found"):format(modname) end --- `loadfile` using the cache -- cgit From ee5aaba21560c3836f46d347c216832864f85668 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 15 Aug 2024 22:02:20 +0800 Subject: fix(man): avoid setting v:errmsg (#30052) --- runtime/lua/man.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index 348e502f34..b9213c8259 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -479,7 +479,13 @@ local function put_page(page) -- XXX: nroff justifies text by filling it with whitespace. That interacts -- badly with our use of $MANWIDTH=999. Hack around this by using a fixed -- size for those whitespace regions. - vim.cmd([[silent! keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g]]) + -- Use try/catch to avoid setting v:errmsg. + vim.cmd([[ + try + keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g + catch + endtry + ]]) vim.cmd('1') -- Move cursor to first line highlight_man_page() set_options() -- cgit From a901fb875f69ff4e3033f883d5b8665eb608a586 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Fri, 16 Aug 2024 08:36:23 -0700 Subject: fix(docs): add missing properties to hl_info #30032 --- runtime/lua/vim/_meta/api.lua | 2 +- runtime/lua/vim/_meta/api_keysets_extra.lua | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 1b70cc275f..7dace2f88a 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1321,7 +1321,7 @@ function vim.api.nvim_get_current_win() end --- of effective definition `:hi-link`. --- • create: (boolean, default true) When highlight group doesn't --- exist create it. ---- @return vim.api.keyset.hl_info +--- @return vim.api.keyset.get_hl_info function vim.api.nvim_get_hl(ns_id, opts) end --- @deprecated diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index e1f12868d0..6e95190692 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -96,20 +96,29 @@ error('Cannot require a meta file') --- @field strikethrough? true --- @field altfont? true --- @field nocombine? true - ---- @class vim.api.keyset.hl_info.cterm : vim.api.keyset.hl_info.base --- @field ctermfg? integer --- @field ctermbg? integer + +--- @class vim.api.keyset.hl_info.cterm : vim.api.keyset.hl_info.base --- @field foreground? integer --- @field background? integer ---- @class vim.api.keyset.hl_info : vim.api.keyset.hl_info.base +--- @class vim.api.keyset.get_hl_info : vim.api.keyset.hl_info.base --- @field fg? integer --- @field bg? integer --- @field sp? integer --- @field default? true +--- @field blend? integer +--- @field cterm? vim.api.keyset.hl_info.cterm + +--- @class vim.api.keyset.set_hl_info : vim.api.keyset.hl_info.base +--- @field fg? integer|string +--- @field bg? integer|string +--- @field sp? integer|string +--- @field default? true --- @field link? string --- @field blend? integer +--- @field force? true --- @field cterm? vim.api.keyset.hl_info.cterm --- @class vim.api.keyset.get_mode -- cgit From 33464189bc02b2555e26dc4e9f7b3fbbcdd02490 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 17 Aug 2024 22:28:03 -0500 Subject: fix(vim.text): handle very long strings (#30075) Lua's string.byte has a maximum (undocumented) allowable length, so vim.text.hencode fails on large strings with the error "string slice too long". Instead of converting the string to an array of bytes up front, convert each character to a byte one at a time. --- runtime/lua/vim/text.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/text.lua b/runtime/lua/vim/text.lua index 0be3396464..d45c8021c6 100644 --- a/runtime/lua/vim/text.lua +++ b/runtime/lua/vim/text.lua @@ -7,10 +7,9 @@ local M = {} --- @param str string String to encode --- @return string : Hex encoded string function M.hexencode(str) - local bytes = { str:byte(1, #str) } local enc = {} ---@type string[] - for i = 1, #bytes do - enc[i] = string.format('%02X', bytes[i]) + for i = 1, #str do + enc[i] = string.format('%02X', str:byte(i, i + 1)) end return table.concat(enc) end -- cgit From 766d5036275e871932893f8dfc8c5bc1eb7a3726 Mon Sep 17 00:00:00 2001 From: Ricardo Casía Date: Tue, 20 Aug 2024 14:52:14 +0200 Subject: docs(lsp): annotate with `vim.lsp.protocol.Methods` enum #29521 Added the enum type annotation `vim.lsp.protocol.Methods` to provide some intellisense support. --- runtime/lua/vim/lsp/_meta/protocol.lua | 2164 ++++++++++++++++++-------------- runtime/lua/vim/lsp/protocol.lua | 9 +- 2 files changed, 1212 insertions(+), 961 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index cbddd24630..d83c40a09f 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -134,7 +134,7 @@ error('Cannot require a meta file') ---The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. ---@field endCharacter? uinteger --- ----Describes the kind of the folding range such as `comment' or 'region'. The kind +---Describes the kind of the folding range such as 'comment' or 'region'. The kind ---is used to categorize folding ranges and used by commands like 'Fold all comments'. ---See {@link FoldingRangeKind} for an enumeration of standardized kinds. ---@field kind? lsp.FoldingRangeKind @@ -681,6 +681,11 @@ error('Cannot require a meta file') ---of a notebook cell. ---@field cellTextDocuments lsp.TextDocumentItem[] +---Registration options specific to a notebook. +--- +---@since 3.17.0 +---@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions + ---The params sent in a change notebook document notification. --- ---@since 3.17.0 @@ -789,7 +794,7 @@ error('Cannot require a meta file') ---Information about the server. --- ---@since 3.15.0 ----@field serverInfo? lsp._anonym1.serverInfo +---@field serverInfo? lsp.ServerInfo ---The data type of the ResponseError if the ---initialize request fails. @@ -1115,7 +1120,7 @@ error('Cannot require a meta file') ---capability. --- ---@since 3.17.0 ----@field itemDefaults? lsp._anonym2.itemDefaults +---@field itemDefaults? lsp.CompletionItemDefaults --- ---The completion items. ---@field items lsp.CompletionItem[] @@ -1171,7 +1176,7 @@ error('Cannot require a meta file') --- ---If `null`, no parameter of the signature is active (for example a named ---argument that does not match any declared parameters). This is only valid ----since 3.18.0 and if the client specifies the client capability +---if the client specifies the client capability ---`textDocument.signatureHelp.noActiveParameterSupport === true` --- ---If omitted or the value lies outside the range of @@ -1307,6 +1312,12 @@ error('Cannot require a meta file') ---Title of the command, like `save`. ---@field title string --- +---An optional tooltip. +--- +---@since 3.18.0 +---@proposed +---@field tooltip? string +--- ---The identifier of the actual command handler. ---@field command string --- @@ -1355,7 +1366,7 @@ error('Cannot require a meta file') --- error message with `reason` in the editor. --- ---@since 3.16.0 ----@field disabled? lsp._anonym4.disabled +---@field disabled? lsp.CodeActionDisabled --- ---The workspace edit this code action performs. ---@field edit? lsp.WorkspaceEdit @@ -1379,6 +1390,12 @@ error('Cannot require a meta file') --- ---A query string to filter symbols by. Clients may send an empty ---string here to request all symbols. +--- +---The `query`-parameter should be interpreted in a *relaxed way* as editors +---will apply their own highlighting and scoring on the results. A good rule +---of thumb is to match case-insensitive and to simply check that the +---characters of *query* appear in their order in a candidate symbol. +---Servers shouldn't use prefix, substring, or similar strict matching. ---@field query string ---A special workspace symbol that supports locations without a range. @@ -1393,7 +1410,7 @@ error('Cannot require a meta file') ---capability `workspace.symbol.resolveSupport`. --- ---See SymbolInformation#location for more details. ----@field location lsp.Location|lsp._anonym5.location +---@field location lsp.Location|lsp.LocationUriOnly --- ---A data entry field that is preserved on a workspace symbol between a ---workspace symbol request and a workspace symbol resolve request. @@ -1566,6 +1583,12 @@ error('Cannot require a meta file') --- ---The edits to apply. ---@field edit lsp.WorkspaceEdit +--- +---Additional data about the edit. +--- +---@since 3.18.0 +---@proposed +---@field metadata? lsp.WorkspaceEditMetadata ---The result returned from the apply workspace edit request. --- @@ -1650,7 +1673,7 @@ error('Cannot require a meta file') ---@class lsp.SetTraceParams --- ----@field value lsp.TraceValues +---@field value lsp.TraceValue ---@class lsp.LogTraceParams --- @@ -1848,10 +1871,10 @@ error('Cannot require a meta file') --- ---Server supports providing semantic tokens for a specific range ---of a document. ----@field range? boolean|lsp._anonym6.range +---@field range? boolean|lsp._anonym1.range --- ---Server supports providing semantic tokens for a full document. ----@field full? boolean|lsp._anonym7.full +---@field full? boolean|lsp.SemanticTokensFullDelta ---@since 3.16.0 ---@class lsp.SemanticTokensEdit @@ -1888,7 +1911,10 @@ error('Cannot require a meta file') --- ---@since 3.16.0 - support for AnnotatedTextEdit. This is guarded using a ---client capability. ----@field edits (lsp.TextEdit|lsp.AnnotatedTextEdit)[] +--- +---@since 3.18.0 - support for SnippetTextEdit. This is guarded using a +---client capability. +---@field edits (lsp.TextEdit|lsp.AnnotatedTextEdit|lsp.SnippetTextEdit)[] ---Create file operation. ---@class lsp.CreateFile: lsp.ResourceOperation @@ -2235,7 +2261,7 @@ error('Cannot require a meta file') ---@field uri lsp.DocumentUri --- ---The text document's language identifier. ----@field languageId string +---@field languageId lsp.LanguageKind --- ---The version number of this document (it will increase after each ---change, including undo/redo). @@ -2244,6 +2270,28 @@ error('Cannot require a meta file') ---The content of the opened text document. ---@field text string +---Options specific to a notebook plus its cells +---to be synced to the server. +--- +---If a selector provides a notebook document +---filter but no cell selector all cells of a +---matching notebook document will be synced. +--- +---If a selector provides no notebook document +---filter but only a cell selector all notebook +---document that contain at least one matching +---cell will be synced. +--- +---@since 3.17.0 +---@class lsp.NotebookDocumentSyncOptions +--- +---The notebooks to be synced +---@field notebookSelector (lsp.NotebookDocumentFilterWithNotebook|lsp.NotebookDocumentFilterWithCells)[] +--- +---Whether save notification should be forwarded to +---the server. Will only be honored if mode === `notebook`. +---@field save? boolean + ---A versioned notebook document identifier. --- ---@since 3.17.0 @@ -2266,7 +2314,7 @@ error('Cannot require a meta file') ---@field metadata? lsp.LSPObject --- ---Changes to cells ----@field cells? lsp._anonym8.cells +---@field cells? lsp.NotebookDocumentCellChanges ---A literal to identify a notebook document in the client. --- @@ -2348,7 +2396,7 @@ error('Cannot require a meta file') ---Information about the client --- ---@since 3.15.0 ----@field clientInfo? lsp._anonym11.clientInfo +---@field clientInfo? lsp.ClientInfo --- ---The locale the client is currently showing the user interface ---in. This must not necessarily be the locale of the operating @@ -2380,7 +2428,7 @@ error('Cannot require a meta file') ---@field initializationOptions? lsp.LSPAny --- ---The initial trace setting. If omitted trace is disabled ('off'). ----@field trace? lsp.TraceValues +---@field trace? lsp.TraceValue ---@class lsp.WorkspaceFoldersInitializeParams --- @@ -2534,18 +2582,24 @@ error('Cannot require a meta file') ---@proposed ---@field inlineCompletionProvider? boolean|lsp.InlineCompletionOptions --- ----Text document specific server capabilities. ---- ----@since 3.18.0 ----@proposed ----@field textDocument? lsp._anonym12.textDocument ---- ---Workspace specific server capabilities. ----@field workspace? lsp._anonym14.workspace +---@field workspace? lsp.WorkspaceOptions --- ---Experimental server capabilities. ---@field experimental? lsp.LSPAny +---Information about the server +--- +---@since 3.15.0 +---@since 3.18.0 ServerInfo type name added. +---@class lsp.ServerInfo +--- +---The name of the server as defined by the server. +---@field name string +--- +---The server's version as defined by the server. +---@field version? string + ---A text document identifier to denote a specific version of a text document. ---@class lsp.VersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier --- @@ -2586,8 +2640,9 @@ error('Cannot require a meta file') ---The range at which the message applies ---@field range lsp.Range --- ----The diagnostic's severity. Can be omitted. If omitted it is up to the ----client to interpret diagnostics as error, warning, info or hint. +---The diagnostic's severity. To avoid interpretation mismatches when a +---server is used with different clients it is highly recommended that servers +---always provide a severity value. ---@field severity? lsp.DiagnosticSeverity --- ---The diagnostic's code, which usually appear in the user interface. @@ -2604,10 +2659,8 @@ error('Cannot require a meta file') ---appears in the user interface. ---@field source? string --- ----The diagnostic's message. It usually appears in the user interface. ---- ----@since 3.18.0 - support for `MarkupContent`. This is guarded by the client capability `textDocument.diagnostic.markupMessageSupport`. ----@field message string|lsp.MarkupContent +---The diagnostic's message. It usually appears in the user interface +---@field message string --- ---Additional metadata about the diagnostic. --- @@ -2661,6 +2714,46 @@ error('Cannot require a meta file') ---The range if the replace is requested. ---@field replace lsp.Range +---In many cases the items of an actual completion result share the same +---value for properties like `commitCharacters` or the range of a text +---edit. A completion list can therefore define item defaults which will +---be used if a completion item itself doesn't specify the value. +--- +---If a completion list specifies a default value and a completion item +---also specifies a corresponding value the one from the item is used. +--- +---Servers are only allowed to return default values if the client +---signals support for this via the `completionList.itemDefaults` +---capability. +--- +---@since 3.17.0 +---@class lsp.CompletionItemDefaults +--- +---A default commit character set. +--- +---@since 3.17.0 +---@field commitCharacters? string[] +--- +---A default edit range. +--- +---@since 3.17.0 +---@field editRange? lsp.Range|lsp.EditRangeWithInsertReplace +--- +---A default insert text format. +--- +---@since 3.17.0 +---@field insertTextFormat? lsp.InsertTextFormat +--- +---A default insert text mode. +--- +---@since 3.17.0 +---@field insertTextMode? lsp.InsertTextMode +--- +---A default data value. +--- +---@since 3.17.0 +---@field data? lsp.LSPAny + ---Completion options. ---@class lsp.CompletionOptions: lsp.WorkDoneProgressOptions --- @@ -2692,7 +2785,7 @@ error('Cannot require a meta file') ---capabilities. --- ---@since 3.17.0 ----@field completionItem? lsp._anonym15.completionItem +---@field completionItem? lsp.ServerCompletionItemOptions ---Hover options. ---@class lsp.HoverOptions: lsp.WorkDoneProgressOptions @@ -2742,7 +2835,7 @@ error('Cannot require a meta file') --- ---If `null`, no parameter of the signature is active (for example a named ---argument that does not match any declared parameters). This is only valid ----since 3.18.0 and if the client specifies the client capability +---if the client specifies the client capability ---`textDocument.signatureHelp.noActiveParameterSupport === true` --- ---If provided (or `null`), this is used in place of @@ -2819,8 +2912,6 @@ error('Cannot require a meta file') ---errors are currently presented to the user for the given range. There is no guarantee ---that these accurately reflect the error state of the resource. The primary parameter ---to compute code actions is the provided range. ---- ----Note that the client should check the `textDocument.diagnostic.markupMessageSupport` server capability before sending diagnostics with markup messages to a server. ---@field diagnostics lsp.Diagnostic[] --- ---Requested kind of actions to return. @@ -2834,6 +2925,16 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field triggerKind? lsp.CodeActionTriggerKind +---Captures why the code action is currently disabled. +--- +---@since 3.18.0 +---@class lsp.CodeActionDisabled +--- +---Human readable description of why the code action is currently disabled. +--- +---This is displayed in the code actions UI. +---@field reason string + ---Provider options for a {@link CodeActionRequest}. ---@class lsp.CodeActionOptions: lsp.WorkDoneProgressOptions --- @@ -2843,12 +2944,36 @@ error('Cannot require a meta file') ---may list out every specific kind they provide. ---@field codeActionKinds? lsp.CodeActionKind[] --- +---Static documentation for a class of code actions. +--- +---Documentation from the provider should be shown in the code actions menu if either: +--- +---- Code actions of `kind` are requested by the editor. In this case, the editor will show the documentation that +--- most closely matches the requested code action kind. For example, if a provider has documentation for +--- both `Refactor` and `RefactorExtract`, when the user requests code actions for `RefactorExtract`, +--- the editor will use the documentation for `RefactorExtract` instead of the documentation for `Refactor`. +--- +---- Any code actions of `kind` are returned by the provider. +--- +---At most one documentation entry should be shown per provider. +--- +---@since 3.18.0 +---@proposed +---@field documentation? lsp.CodeActionKindDocumentation[] +--- ---The server provides support to resolve additional ---information for a code action. --- ---@since 3.16.0 ---@field resolveProvider? boolean +---Location with only uri and does not include range. +--- +---@since 3.18.0 +---@class lsp.LocationUriOnly +--- +---@field uri lsp.DocumentUri + ---Server capabilities for a {@link WorkspaceSymbolRequest}. ---@class lsp.WorkspaceSymbolOptions: lsp.WorkDoneProgressOptions --- @@ -2923,12 +3048,33 @@ error('Cannot require a meta file') ---@since version 3.12.0 ---@field prepareProvider? boolean +---@since 3.18.0 +---@class lsp.PrepareRenamePlaceholder +--- +---@field range lsp.Range +--- +---@field placeholder string + +---@since 3.18.0 +---@class lsp.PrepareRenameDefaultBehavior +--- +---@field defaultBehavior boolean + ---The server capabilities of a {@link ExecuteCommandRequest}. ---@class lsp.ExecuteCommandOptions: lsp.WorkDoneProgressOptions --- ---The commands to be executed on the server ---@field commands string[] +---Additional data about a workspace edit. +--- +---@since 3.18.0 +---@proposed +---@class lsp.WorkspaceEditMetadata +--- +---Signal to the editor that this edit is a refactoring. +---@field isRefactoring? boolean + ---@since 3.16.0 ---@class lsp.SemanticTokensLegend --- @@ -2938,6 +3084,14 @@ error('Cannot require a meta file') ---The token modifiers a server uses. ---@field tokenModifiers string[] +---Semantic tokens options to support deltas for full documents +--- +---@since 3.18.0 +---@class lsp.SemanticTokensFullDelta +--- +---The server supports deltas for full documents. +---@field delta? boolean + ---A text document identifier to optionally denote a specific version of a text document. ---@class lsp.OptionalVersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier --- @@ -2956,6 +3110,21 @@ error('Cannot require a meta file') ---The actual identifier of the change annotation ---@field annotationId lsp.ChangeAnnotationIdentifier +---An interactive text edit. +--- +---@since 3.18.0 +---@proposed +---@class lsp.SnippetTextEdit +--- +---The range of the text document to be manipulated. +---@field range lsp.Range +--- +---The snippet to be inserted. +---@field snippet lsp.StringValue +--- +---The actual identifier of the snippet edit. +---@field annotationId? lsp.ChangeAnnotationIdentifier + ---A generic resource operation. ---@class lsp.ResourceOperation --- @@ -3066,20 +3235,43 @@ error('Cannot require a meta file') ---if supported by the client. ---@field executionSummary? lsp.ExecutionSummary ----A change describing how to move a `NotebookCell` ----array from state S to S'. +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterWithNotebook --- ----@since 3.17.0 ----@class lsp.NotebookCellArrayChange +---The notebook to be synced If a string +---value is provided it matches against the +---notebook type. '*' matches every notebook. +---@field notebook string|lsp.NotebookDocumentFilter --- ----The start oftest of the cell that changed. ----@field start uinteger +---The cells of the matching notebook to be synced. +---@field cells? lsp.NotebookCellLanguage[] + +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterWithCells --- ----The deleted cells ----@field deleteCount uinteger +---The notebook to be synced If a string +---value is provided it matches against the +---notebook type. '*' matches every notebook. +---@field notebook? string|lsp.NotebookDocumentFilter --- ----The new cells, if any ----@field cells? lsp.NotebookCell[] +---The cells of the matching notebook to be synced. +---@field cells lsp.NotebookCellLanguage[] + +---Cell changes to a notebook document. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentCellChanges +--- +---Changes to the cell structure to add or +---remove cells. +---@field structure? lsp.NotebookDocumentCellChangeStructure +--- +---Changes to notebook cells properties like its +---kind, execution summary or metadata. +---@field data? lsp.NotebookCell[] +--- +---Changes to the text content of notebook cells. +---@field textContent? lsp.NotebookDocumentCellContentChanges[] ---Describes the currently selected completion item. --- @@ -3093,6 +3285,18 @@ error('Cannot require a meta file') ---The text the range will be replaced with if this completion is accepted. ---@field text string +---Information about the client +--- +---@since 3.15.0 +---@since 3.18.0 ClientInfo type name added. +---@class lsp.ClientInfo +--- +---The name of the client as defined by the client. +---@field name string +--- +---The client's version as defined by the client. +---@field version? string + ---Defines the capabilities provided by the client. ---@class lsp.ClientCapabilities --- @@ -3140,69 +3344,40 @@ error('Cannot require a meta file') ---sent. ---@field save? boolean|lsp.SaveOptions ----Options specific to a notebook plus its cells ----to be synced to the server. +---Defines workspace specific capabilities of the server. --- ----If a selector provides a notebook document ----filter but no cell selector all cells of a ----matching notebook document will be synced. +---@since 3.18.0 +---@class lsp.WorkspaceOptions --- ----If a selector provides no notebook document ----filter but only a cell selector all notebook ----document that contain at least one matching ----cell will be synced. +---The server supports workspace folder. --- ----@since 3.17.0 ----@class lsp.NotebookDocumentSyncOptions +---@since 3.6.0 +---@field workspaceFolders? lsp.WorkspaceFoldersServerCapabilities --- ----The notebooks to be synced ----@field notebookSelector (lsp._anonym16.notebookSelector|lsp._anonym18.notebookSelector)[] +---The server is interested in notifications/requests for operations on files. --- ----Whether save notification should be forwarded to ----the server. Will only be honored if mode === `notebook`. ----@field save? boolean +---@since 3.16.0 +---@field fileOperations? lsp.FileOperationOptions ----Registration options specific to a notebook. +---@since 3.18.0 +---@class lsp.TextDocumentContentChangePartial --- ----@since 3.17.0 ----@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions - ----@class lsp.WorkspaceFoldersServerCapabilities +---The range of the document that changed. +---@field range lsp.Range --- ----The server has support for workspace folders ----@field supported? boolean +---The optional length of the range that got replaced. --- ----Whether the server wants to receive workspace folder ----change notifications. +---@deprecated use range instead. +---@field rangeLength? uinteger --- ----If a string is provided the string is treated as an ID ----under which the notification is registered on the client ----side. The ID can be used to unregister for these events ----using the `client/unregisterCapability` request. ----@field changeNotifications? string|boolean +---The new text for the provided range. +---@field text string ----Options for notifications/requests for user operations on files. ---- ----@since 3.16.0 ----@class lsp.FileOperationOptions ---- ----The server is interested in receiving didCreateFiles notifications. ----@field didCreate? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving willCreateFiles requests. ----@field willCreate? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving didRenameFiles notifications. ----@field didRename? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving willRenameFiles requests. ----@field willRename? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving didDeleteFiles file notifications. ----@field didDelete? lsp.FileOperationRegistrationOptions +---@since 3.18.0 +---@class lsp.TextDocumentContentChangeWholeDocument --- ----The server is interested in receiving willDeleteFiles file requests. ----@field willDelete? lsp.FileOperationRegistrationOptions +---The new text of the whole document. +---@field text string ---Structure to capture a description for an error code. --- @@ -3223,6 +3398,33 @@ error('Cannot require a meta file') ---The message of this related diagnostic information. ---@field message string +---Edit range variant that includes ranges for insert and replace operations. +--- +---@since 3.18.0 +---@class lsp.EditRangeWithInsertReplace +--- +---@field insert lsp.Range +--- +---@field replace lsp.Range + +---@since 3.18.0 +---@class lsp.ServerCompletionItemOptions +--- +---The server has support for completion item label +---details (see also `CompletionItemLabelDetails`) when +---receiving a completion item in a resolve call. +--- +---@since 3.17.0 +---@field labelDetailsSupport? boolean + +---@since 3.18.0 +---@deprecated use MarkupContent instead. +---@class lsp.MarkedStringWithLanguage +--- +---@field language string +--- +---@field value string + ---Represents a parameter of a callable-signature. A parameter can ---have a label and a doc-comment. ---@class lsp.ParameterInformation @@ -3233,6 +3435,10 @@ error('Cannot require a meta file') ---signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 ---string representation as `Position` and `Range` does. --- +---To avoid ambiguities a server should use the [start, end] offset value instead of using +---a substring. Whether a client support this is controlled via `labelOffsetSupport` client +---capability. +--- ---*Note*: a label of type string should be a substring of its containing signature label. ---Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. ---@field label string|[uinteger, uinteger] @@ -3241,6 +3447,24 @@ error('Cannot require a meta file') ---in the UI but can be omitted. ---@field documentation? string|lsp.MarkupContent +---Documentation for a class of code actions. +--- +---@since 3.18.0 +---@proposed +---@class lsp.CodeActionKindDocumentation +--- +---The kind of the code action being documented. +--- +---If the kind is generic, such as `CodeActionKind.Refactor`, the documentation will be shown whenever any +---refactorings are returned. If the kind if more specific, such as `CodeActionKind.RefactorExtract`, the +---documentation will only be shown when extract refactoring code actions are returned. +---@field kind lsp.CodeActionKind +--- +---Command that is ued to display the documentation to the user. +--- +---The title of this documentation code action is taken from {@linkcode Command.title} +---@field command lsp.Command + ---A notebook cell text document filter denotes a cell text ---document by different properties. --- @@ -3278,6 +3502,34 @@ error('Cannot require a meta file') ---not if known by the client. ---@field success? boolean +---@since 3.18.0 +---@class lsp.NotebookCellLanguage +--- +---@field language string + +---Structural changes to cells in a notebook document. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentCellChangeStructure +--- +---The change to the cell array. +---@field array lsp.NotebookCellArrayChange +--- +---Additional opened cell text documents. +---@field didOpen? lsp.TextDocumentItem[] +--- +---Additional closed cell text documents. +---@field didClose? lsp.TextDocumentIdentifier[] + +---Content changes to a cell in a notebook document. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentCellContentChanges +--- +---@field document lsp.VersionedTextDocumentIdentifier +--- +---@field changes lsp.TextDocumentContentChangeEvent[] + ---Workspace specific client capabilities. ---@class lsp.WorkspaceClientCapabilities --- @@ -3524,7 +3776,7 @@ error('Cannot require a meta file') ---anymore since the information is outdated). --- ---@since 3.17.0 ----@field staleRequestSupport? lsp._anonym20.staleRequestSupport +---@field staleRequestSupport? lsp.StaleRequestSupportOptions --- ---Client capabilities specific to regular expressions. --- @@ -3556,6 +3808,43 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field positionEncodings? lsp.PositionEncodingKind[] +---@class lsp.WorkspaceFoldersServerCapabilities +--- +---The server has support for workspace folders +---@field supported? boolean +--- +---Whether the server wants to receive workspace folder +---change notifications. +--- +---If a string is provided the string is treated as an ID +---under which the notification is registered on the client +---side. The ID can be used to unregister for these events +---using the `client/unregisterCapability` request. +---@field changeNotifications? string|boolean + +---Options for notifications/requests for user operations on files. +--- +---@since 3.16.0 +---@class lsp.FileOperationOptions +--- +---The server is interested in receiving didCreateFiles notifications. +---@field didCreate? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving willCreateFiles requests. +---@field willCreate? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving didRenameFiles notifications. +---@field didRename? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving willRenameFiles requests. +---@field willRename? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving didDeleteFiles file notifications. +---@field didDelete? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving willDeleteFiles file requests. +---@field willDelete? lsp.FileOperationRegistrationOptions + ---A relative pattern is a helper to construct glob patterns that are matched ---relatively to a base URI. The common value for a `baseUri` is a workspace ---folder root, but it can be another absolute URI as well. @@ -3570,6 +3859,111 @@ error('Cannot require a meta file') ---The actual glob pattern; ---@field pattern lsp.Pattern +---A document filter where `language` is required field. +--- +---@since 3.18.0 +---@class lsp.TextDocumentFilterLanguage +--- +---A language id, like `typescript`. +---@field language string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. +--- +---@since 3.18.0 - support for relative patterns. +---@field pattern? lsp.GlobPattern + +---A document filter where `scheme` is required field. +--- +---@since 3.18.0 +---@class lsp.TextDocumentFilterScheme +--- +---A language id, like `typescript`. +---@field language? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme string +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. +--- +---@since 3.18.0 - support for relative patterns. +---@field pattern? lsp.GlobPattern + +---A document filter where `pattern` is required field. +--- +---@since 3.18.0 +---@class lsp.TextDocumentFilterPattern +--- +---A language id, like `typescript`. +---@field language? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. +--- +---@since 3.18.0 - support for relative patterns. +---@field pattern lsp.GlobPattern + +---A notebook document filter where `notebookType` is required field. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterNotebookType +--- +---The type of the enclosing notebook. +---@field notebookType string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern. +---@field pattern? lsp.GlobPattern + +---A notebook document filter where `scheme` is required field. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterScheme +--- +---The type of the enclosing notebook. +---@field notebookType? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme string +--- +---A glob pattern. +---@field pattern? lsp.GlobPattern + +---A notebook document filter where `pattern` is required field. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterPattern +--- +---The type of the enclosing notebook. +---@field notebookType? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern. +---@field pattern lsp.GlobPattern + +---A change describing how to move a `NotebookCell` +---array from state S to S'. +--- +---@since 3.17.0 +---@class lsp.NotebookCellArrayChange +--- +---The start oftest of the cell that changed. +---@field start uinteger +--- +---The deleted cells +---@field deleteCount uinteger +--- +---The new cells, if any +---@field cells? lsp.NotebookCell[] + ---@class lsp.WorkspaceEditClientCapabilities --- ---The client supports versioned document changes in `WorkspaceEdit`s @@ -3600,7 +3994,19 @@ error('Cannot require a meta file') ---create file, rename file and delete file changes. --- ---@since 3.16.0 ----@field changeAnnotationSupport? lsp._anonym21.changeAnnotationSupport +---@field changeAnnotationSupport? lsp.ChangeAnnotationsSupportOptions +--- +---Whether the client supports `WorkspaceEditMetadata` in `WorkspaceEdit`s. +--- +---@since 3.18.0 +---@proposed +---@field metadataSupport? boolean +--- +---Whether the client supports snippets as text edits. +--- +---@since 3.18.0 +---@proposed +---@field snippetEditSupport? boolean ---@class lsp.DidChangeConfigurationClientCapabilities --- @@ -3627,20 +4033,20 @@ error('Cannot require a meta file') ---@field dynamicRegistration? boolean --- ---Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. ----@field symbolKind? lsp._anonym22.symbolKind +---@field symbolKind? lsp.ClientSymbolKindOptions --- ---The client supports tags on `SymbolInformation`. ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.16.0 ----@field tagSupport? lsp._anonym23.tagSupport +---@field tagSupport? lsp.ClientSymbolTagOptions --- ---The client support partial workspace symbols. The client will send the ---request `workspaceSymbol/resolve` to the server to resolve additional ---properties. --- ---@since 3.17.0 ----@field resolveSupport? lsp._anonym24.resolveSupport +---@field resolveSupport? lsp.ClientSymbolResolveOptions ---The client capabilities of a {@link ExecuteCommandRequest}. ---@class lsp.ExecuteCommandClientCapabilities @@ -3785,9 +4191,9 @@ error('Cannot require a meta file') --- ---The client supports the following `CompletionItem` specific ---capabilities. ----@field completionItem? lsp._anonym25.completionItem +---@field completionItem? lsp.ClientCompletionItemOptions --- ----@field completionItemKind? lsp._anonym29.completionItemKind +---@field completionItemKind? lsp.ClientCompletionItemOptionsKind --- ---Defines how the client handles whitespace and indentation ---when accepting a completion item that uses multi line @@ -3804,7 +4210,7 @@ error('Cannot require a meta file') ---capabilities. --- ---@since 3.17.0 ----@field completionList? lsp._anonym30.completionList +---@field completionList? lsp.CompletionListCapabilities ---@class lsp.HoverClientCapabilities --- @@ -3823,7 +4229,7 @@ error('Cannot require a meta file') --- ---The client supports the following `SignatureInformation` ---specific properties. ----@field signatureInformation? lsp._anonym31.signatureInformation +---@field signatureInformation? lsp.ClientSignatureInformationOptions --- ---The client supports to send additional context information for a ---`textDocument/signatureHelp` request. A client that opts into @@ -3901,7 +4307,7 @@ error('Cannot require a meta file') --- ---Specific capabilities for the `SymbolKind` in the ---`textDocument/documentSymbol` request. ----@field symbolKind? lsp._anonym33.symbolKind +---@field symbolKind? lsp.ClientSymbolKindOptions --- ---The client supports hierarchical document symbols. ---@field hierarchicalDocumentSymbolSupport? boolean @@ -3911,7 +4317,7 @@ error('Cannot require a meta file') ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.16.0 ----@field tagSupport? lsp._anonym34.tagSupport +---@field tagSupport? lsp.ClientSymbolTagOptions --- ---The client supports an additional label presented in the UI when ---registering a document symbol provider. @@ -3930,7 +4336,7 @@ error('Cannot require a meta file') ---set the request can only return `Command` literals. --- ---@since 3.8.0 ----@field codeActionLiteralSupport? lsp._anonym35.codeActionLiteralSupport +---@field codeActionLiteralSupport? lsp.ClientCodeActionLiteralOptions --- ---Whether code action supports the `isPreferred` property. --- @@ -3953,7 +4359,7 @@ error('Cannot require a meta file') ---properties via a separate `codeAction/resolve` request. --- ---@since 3.16.0 ----@field resolveSupport? lsp._anonym37.resolveSupport +---@field resolveSupport? lsp.ClientCodeActionResolveOptions --- ---Whether the client honors the change annotations in ---text edits and resource operations returned via the @@ -3963,12 +4369,25 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@field honorsChangeAnnotations? boolean +--- +---Whether the client supports documentation for a class of +---code actions. +--- +---@since 3.18.0 +---@proposed +---@field documentationSupport? boolean ---The client capabilities of a {@link CodeLensRequest}. ---@class lsp.CodeLensClientCapabilities --- ---Whether code lens supports dynamic registration. ---@field dynamicRegistration? boolean +--- +---Whether the client supports resolving additional code lens +---properties via a separate `codeLens/resolve` request. +--- +---@since 3.18.0 +---@field resolveSupport? lsp.ClientCodeLensResolveOptions ---The client capabilities of a {@link DocumentLinkRequest}. ---@class lsp.DocumentLinkClientCapabilities @@ -4061,12 +4480,12 @@ error('Cannot require a meta file') ---Specific options for the folding range kind. --- ---@since 3.17.0 ----@field foldingRangeKind? lsp._anonym38.foldingRangeKind +---@field foldingRangeKind? lsp.ClientFoldingRangeKindOptions --- ---Specific options for the folding range. --- ---@since 3.17.0 ----@field foldingRange? lsp._anonym39.foldingRange +---@field foldingRange? lsp.ClientFoldingRangeOptions ---@class lsp.SelectionRangeClientCapabilities --- @@ -4076,34 +4495,13 @@ error('Cannot require a meta file') ---@field dynamicRegistration? boolean ---The publish diagnostic client capabilities. ----@class lsp.PublishDiagnosticsClientCapabilities ---- ----Whether the clients accepts diagnostics with related information. ----@field relatedInformation? boolean ---- ----Client supports the tag property to provide meta data about a diagnostic. ----Clients supporting tags have to handle unknown tags gracefully. ---- ----@since 3.15.0 ----@field tagSupport? lsp._anonym40.tagSupport +---@class lsp.PublishDiagnosticsClientCapabilities: lsp.DiagnosticsCapabilities --- ---Whether the client interprets the version property of the ---`textDocument/publishDiagnostics` notification's parameter. --- ---@since 3.15.0 ---@field versionSupport? boolean ---- ----Client supports a codeDescription property ---- ----@since 3.16.0 ----@field codeDescriptionSupport? boolean ---- ----Whether code action supports the `data` property which is ----preserved between a `textDocument/publishDiagnostics` and ----`textDocument/codeAction` request. ---- ----@since 3.16.0 ----@field dataSupport? boolean ---@since 3.16.0 ---@class lsp.CallHierarchyClientCapabilities @@ -4129,7 +4527,7 @@ error('Cannot require a meta file') ---`request.range` are both set to true but the server only provides a ---range provider the client might not render a minimap correctly or might ---even decide to not show any semantic tokens at all. ----@field requests lsp._anonym41.requests +---@field requests lsp.ClientSemanticTokensRequestOptions --- ---The token types that the client supports. ---@field tokenTypes string[] @@ -4212,12 +4610,12 @@ error('Cannot require a meta file') --- ---Indicates which properties a client can resolve lazily on an inlay ---hint. ----@field resolveSupport? lsp._anonym44.resolveSupport +---@field resolveSupport? lsp.ClientInlayHintResolveOptions ---Client capabilities specific to diagnostic pull requests. --- ---@since 3.17.0 ----@class lsp.DiagnosticClientCapabilities +---@class lsp.DiagnosticClientCapabilities: lsp.DiagnosticsCapabilities --- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` @@ -4226,9 +4624,6 @@ error('Cannot require a meta file') --- ---Whether the clients supports related documents for document diagnostic pulls. ---@field relatedDocumentSupport? boolean ---- ----Whether the client supports `MarkupContent` in diagnostic messages. ----@field markupMessageSupport? boolean ---Client capabilities specific to inline completions. --- @@ -4257,7 +4652,7 @@ error('Cannot require a meta file') ---@class lsp.ShowMessageRequestClientCapabilities --- ---Capabilities specific to the `MessageActionItem` type. ----@field messageActionItem? lsp._anonym45.messageActionItem +---@field messageActionItem? lsp.ClientShowMessageActionItemOptions ---Client capabilities for the showDocument request. --- @@ -4268,13 +4663,24 @@ error('Cannot require a meta file') ---request. ---@field support boolean +---@since 3.18.0 +---@class lsp.StaleRequestSupportOptions +--- +---The client will actively cancel the request. +---@field cancel boolean +--- +---The list of requests for which the client +---will retry the request if it receives a +---response with error code `ContentModified` +---@field retryOnContentModified string[] + ---Client capabilities specific to regular expressions. --- ---@since 3.16.0 ---@class lsp.RegularExpressionsClientCapabilities --- ---The engine's name. ----@field engine string +---@field engine lsp.RegularExpressionEngineKind --- ---The engine's version. ---@field version? string @@ -4296,988 +4702,832 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field allowedTags? string[] ----A set of predefined token types. This set is not fixed ----an clients can specify additional token types via the ----corresponding client capabilities. +---@since 3.18.0 +---@class lsp.ChangeAnnotationsSupportOptions --- ----@since 3.16.0 ----@alias lsp.SemanticTokenTypes ----| "namespace" # namespace ----| "type" # type ----| "class" # class ----| "enum" # enum ----| "interface" # interface ----| "struct" # struct ----| "typeParameter" # typeParameter ----| "parameter" # parameter ----| "variable" # variable ----| "property" # property ----| "enumMember" # enumMember ----| "event" # event ----| "function" # function ----| "method" # method ----| "macro" # macro ----| "keyword" # keyword ----| "modifier" # modifier ----| "comment" # comment ----| "string" # string ----| "number" # number ----| "regexp" # regexp ----| "operator" # operator ----| "decorator" # decorator +---Whether the client groups edits with equal labels into tree nodes, +---for instance all edits labelled with "Changes in Strings" would +---be a tree node. +---@field groupsOnLabel? boolean ----A set of predefined token modifiers. This set is not fixed ----an clients can specify additional token types via the ----corresponding client capabilities. ---- ----@since 3.16.0 ----@alias lsp.SemanticTokenModifiers ----| "declaration" # declaration ----| "definition" # definition ----| "readonly" # readonly ----| "static" # static ----| "deprecated" # deprecated ----| "abstract" # abstract ----| "async" # async ----| "modification" # modification ----| "documentation" # documentation ----| "defaultLibrary" # defaultLibrary - ----The document diagnostic report kinds. +---@since 3.18.0 +---@class lsp.ClientSymbolKindOptions --- ----@since 3.17.0 ----@alias lsp.DocumentDiagnosticReportKind ----| "full" # Full ----| "unchanged" # Unchanged - ----Predefined error codes. ----@alias lsp.ErrorCodes ----| -32700 # ParseError ----| -32600 # InvalidRequest ----| -32601 # MethodNotFound ----| -32602 # InvalidParams ----| -32603 # InternalError ----| -32002 # ServerNotInitialized ----| -32001 # UnknownErrorCode - ----@alias lsp.LSPErrorCodes ----| -32803 # RequestFailed ----| -32802 # ServerCancelled ----| -32801 # ContentModified ----| -32800 # RequestCancelled - ----A set of predefined range kinds. ----@alias lsp.FoldingRangeKind ----| "comment" # Comment ----| "imports" # Imports ----| "region" # Region - ----A symbol kind. ----@alias lsp.SymbolKind ----| 1 # File ----| 2 # Module ----| 3 # Namespace ----| 4 # Package ----| 5 # Class ----| 6 # Method ----| 7 # Property ----| 8 # Field ----| 9 # Constructor ----| 10 # Enum ----| 11 # Interface ----| 12 # Function ----| 13 # Variable ----| 14 # Constant ----| 15 # String ----| 16 # Number ----| 17 # Boolean ----| 18 # Array ----| 19 # Object ----| 20 # Key ----| 21 # Null ----| 22 # EnumMember ----| 23 # Struct ----| 24 # Event ----| 25 # Operator ----| 26 # TypeParameter - ----Symbol tags are extra annotations that tweak the rendering of a symbol. +---The symbol kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. --- ----@since 3.16 ----@alias lsp.SymbolTag ----| 1 # Deprecated +---If this property is not present the client only supports +---the symbol kinds from `File` to `Array` as defined in +---the initial version of the protocol. +---@field valueSet? lsp.SymbolKind[] ----Moniker uniqueness level to define scope of the moniker. +---@since 3.18.0 +---@class lsp.ClientSymbolTagOptions --- ----@since 3.16.0 ----@alias lsp.UniquenessLevel ----| "document" # document ----| "project" # project ----| "group" # group ----| "scheme" # scheme ----| "global" # global +---The tags supported by the client. +---@field valueSet lsp.SymbolTag[] ----The moniker kind. +---@since 3.18.0 +---@class lsp.ClientSymbolResolveOptions --- ----@since 3.16.0 ----@alias lsp.MonikerKind ----| "import" # import ----| "export" # export ----| "local" # local +---The properties that a client can resolve lazily. Usually +---`location.range` +---@field properties string[] ----Inlay hint kinds. +---@since 3.18.0 +---@class lsp.ClientCompletionItemOptions --- ----@since 3.17.0 ----@alias lsp.InlayHintKind ----| 1 # Type ----| 2 # Parameter - ----The message type ----@alias lsp.MessageType ----| 1 # Error ----| 2 # Warning ----| 3 # Info ----| 4 # Log ----| 5 # Debug - ----Defines how the host (editor) should sync ----document changes to the language server. ----@alias lsp.TextDocumentSyncKind ----| 0 # None ----| 1 # Full ----| 2 # Incremental - ----Represents reasons why a text document is saved. ----@alias lsp.TextDocumentSaveReason ----| 1 # Manual ----| 2 # AfterDelay ----| 3 # FocusOut - ----The kind of a completion entry. ----@alias lsp.CompletionItemKind ----| 1 # Text ----| 2 # Method ----| 3 # Function ----| 4 # Constructor ----| 5 # Field ----| 6 # Variable ----| 7 # Class ----| 8 # Interface ----| 9 # Module ----| 10 # Property ----| 11 # Unit ----| 12 # Value ----| 13 # Enum ----| 14 # Keyword ----| 15 # Snippet ----| 16 # Color ----| 17 # File ----| 18 # Reference ----| 19 # Folder ----| 20 # EnumMember ----| 21 # Constant ----| 22 # Struct ----| 23 # Event ----| 24 # Operator ----| 25 # TypeParameter - ----Completion item tags are extra annotations that tweak the rendering of a completion ----item. +---Client supports snippets as insert text. --- ----@since 3.15.0 ----@alias lsp.CompletionItemTag ----| 1 # Deprecated - ----Defines whether the insert text in a completion item should be interpreted as ----plain text or a snippet. ----@alias lsp.InsertTextFormat ----| 1 # PlainText ----| 2 # Snippet - ----How whitespace and indentation is handled during completion ----item insertion. +---A snippet can define tab stops and placeholders with `$1`, `$2` +---and `${3:foo}`. `$0` defines the final tab stop, it defaults to +---the end of the snippet. Placeholders with equal identifiers are linked, +---that is typing in one will update others too. +---@field snippetSupport? boolean --- ----@since 3.16.0 ----@alias lsp.InsertTextMode ----| 1 # asIs ----| 2 # adjustIndentation - ----A document highlight kind. ----@alias lsp.DocumentHighlightKind ----| 1 # Text ----| 2 # Read ----| 3 # Write - ----A set of predefined code action kinds ----@alias lsp.CodeActionKind ----| "" # Empty ----| "quickfix" # QuickFix ----| "refactor" # Refactor ----| "refactor.extract" # RefactorExtract ----| "refactor.inline" # RefactorInline ----| "refactor.rewrite" # RefactorRewrite ----| "source" # Source ----| "source.organizeImports" # SourceOrganizeImports ----| "source.fixAll" # SourceFixAll - ----@alias lsp.TraceValues ----| "off" # Off ----| "messages" # Messages ----| "verbose" # Verbose - ----Describes the content type that a client supports in various ----result literals like `Hover`, `ParameterInfo` or `CompletionItem`. +---Client supports commit characters on a completion item. +---@field commitCharactersSupport? boolean --- ----Please note that `MarkupKinds` must not start with a `$`. This kinds ----are reserved for internal usage. ----@alias lsp.MarkupKind ----| "plaintext" # PlainText ----| "markdown" # Markdown - ----Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. +---Client supports the following content formats for the documentation +---property. The order describes the preferred format of the client. +---@field documentationFormat? lsp.MarkupKind[] --- ----@since 3.18.0 ----@proposed ----@alias lsp.InlineCompletionTriggerKind ----| 0 # Invoked ----| 1 # Automatic - ----A set of predefined position encoding kinds. +---Client supports the deprecated property on a completion item. +---@field deprecatedSupport? boolean --- ----@since 3.17.0 ----@alias lsp.PositionEncodingKind ----| "utf-8" # UTF8 ----| "utf-16" # UTF16 ----| "utf-32" # UTF32 - ----The file event type ----@alias lsp.FileChangeType ----| 1 # Created ----| 2 # Changed ----| 3 # Deleted - ----@alias lsp.WatchKind ----| 1 # Create ----| 2 # Change ----| 4 # Delete - ----The diagnostic's severity. ----@alias lsp.DiagnosticSeverity ----| 1 # Error ----| 2 # Warning ----| 3 # Information ----| 4 # Hint - ----The diagnostic tags. +---Client supports the preselect property on a completion item. +---@field preselectSupport? boolean --- ----@since 3.15.0 ----@alias lsp.DiagnosticTag ----| 1 # Unnecessary ----| 2 # Deprecated - ----How a completion was triggered ----@alias lsp.CompletionTriggerKind ----| 1 # Invoked ----| 2 # TriggerCharacter ----| 3 # TriggerForIncompleteCompletions - ----How a signature help was triggered. +---Client supports the tag property on a completion item. Clients supporting +---tags have to handle unknown tags gracefully. Clients especially need to +---preserve unknown tags when sending a completion item back to the server in +---a resolve call. --- ---@since 3.15.0 ----@alias lsp.SignatureHelpTriggerKind ----| 1 # Invoked ----| 2 # TriggerCharacter ----| 3 # ContentChange - ----The reason why code actions were requested. +---@field tagSupport? lsp.CompletionItemTagOptions --- ----@since 3.17.0 ----@alias lsp.CodeActionTriggerKind ----| 1 # Invoked ----| 2 # Automatic - ----A pattern kind describing if a glob pattern matches a file a folder or ----both. +---Client support insert replace edit to control different behavior if a +---completion item is inserted in the text or should replace text. --- ---@since 3.16.0 ----@alias lsp.FileOperationPatternKind ----| "file" # file ----| "folder" # folder - ----A notebook cell kind. ---- ----@since 3.17.0 ----@alias lsp.NotebookCellKind ----| 1 # Markup ----| 2 # Code - ----@alias lsp.ResourceOperationKind ----| "create" # Create ----| "rename" # Rename ----| "delete" # Delete - ----@alias lsp.FailureHandlingKind ----| "abort" # Abort ----| "transactional" # Transactional ----| "textOnlyTransactional" # TextOnlyTransactional ----| "undo" # Undo - ----@alias lsp.PrepareSupportDefaultBehavior ----| 1 # Identifier - ----@alias lsp.TokenFormat ----| "relative" # Relative - ----The definition of a symbol represented as one or many {@link Location locations}. ----For most programming languages there is only one location at which a symbol is ----defined. +---@field insertReplaceSupport? boolean --- ----Servers should prefer returning `DefinitionLink` over `Definition` if supported ----by the client. ----@alias lsp.Definition lsp.Location|lsp.Location[] - ----Information about where a symbol is defined. +---Indicates which properties a client can resolve lazily on a completion +---item. Before version 3.16.0 only the predefined properties `documentation` +---and `details` could be resolved lazily. --- ----Provides additional metadata over normal {@link Location location} definitions, including the range of ----the defining symbol ----@alias lsp.DefinitionLink lsp.LocationLink - ----LSP arrays. ----@since 3.17.0 ----@alias lsp.LSPArray lsp.LSPAny[] - ----The LSP any type. ----Please note that strictly speaking a property with the value `undefined` ----can't be converted into JSON preserving the property name. However for ----convenience it is allowed and assumed that all these properties are ----optional as well. ----@since 3.17.0 ----@alias lsp.LSPAny lsp.LSPObject|lsp.LSPArray|string|integer|uinteger|decimal|boolean|lsp.null - ----The declaration of a symbol representation as one or many {@link Location locations}. ----@alias lsp.Declaration lsp.Location|lsp.Location[] - ----Information about where a symbol is declared. +---@since 3.16.0 +---@field resolveSupport? lsp.ClientCompletionItemResolveOptions --- ----Provides additional metadata over normal {@link Location location} declarations, including the range of ----the declaring symbol. +---The client supports the `insertTextMode` property on +---a completion item to override the whitespace handling mode +---as defined by the client (see `insertTextMode`). --- ----Servers should prefer returning `DeclarationLink` over `Declaration` if supported ----by the client. ----@alias lsp.DeclarationLink lsp.LocationLink - ----Inline value information can be provided by different means: ----- directly as a text value (class InlineValueText). ----- as a name to use for a variable lookup (class InlineValueVariableLookup) ----- as an evaluatable expression (class InlineValueEvaluatableExpression) ----The InlineValue types combines all inline value types into one type. +---@since 3.16.0 +---@field insertTextModeSupport? lsp.ClientCompletionItemInsertTextModeOptions --- ----@since 3.17.0 ----@alias lsp.InlineValue lsp.InlineValueText|lsp.InlineValueVariableLookup|lsp.InlineValueEvaluatableExpression - ----The result of a document diagnostic pull request. A report can ----either be a full report containing all diagnostics for the ----requested document or an unchanged report indicating that nothing ----has changed in terms of diagnostics in comparison to the last ----pull request. +---The client has support for completion item label +---details (see also `CompletionItemLabelDetails`). --- ---@since 3.17.0 ----@alias lsp.DocumentDiagnosticReport lsp.RelatedFullDocumentDiagnosticReport|lsp.RelatedUnchangedDocumentDiagnosticReport - ----@alias lsp.PrepareRenameResult lsp.Range|lsp._anonym46.PrepareRenameResult|lsp._anonym47.PrepareRenameResult +---@field labelDetailsSupport? boolean ----A document selector is the combination of one or many document filters. +---@since 3.18.0 +---@class lsp.ClientCompletionItemOptionsKind --- ----\@sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; +---The completion item kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. --- ----The use of a string as a document filter is deprecated @since 3.16.0. ----@alias lsp.DocumentSelector lsp.DocumentFilter[] - ----@alias lsp.ProgressToken integer|string - ----An identifier to refer to a change annotation stored with a workspace edit. ----@alias lsp.ChangeAnnotationIdentifier string +---If this property is not present the client only supports +---the completion items kinds from `Text` to `Reference` as defined in +---the initial version of the protocol. +---@field valueSet? lsp.CompletionItemKind[] ----A workspace diagnostic document report. +---The client supports the following `CompletionList` specific +---capabilities. --- ---@since 3.17.0 ----@alias lsp.WorkspaceDocumentDiagnosticReport lsp.WorkspaceFullDocumentDiagnosticReport|lsp.WorkspaceUnchangedDocumentDiagnosticReport - ----An event describing a change to a text document. If only a text is provided ----it is considered to be the full content of the document. ----@alias lsp.TextDocumentContentChangeEvent lsp._anonym48.TextDocumentContentChangeEvent|lsp._anonym49.TextDocumentContentChangeEvent - ----MarkedString can be used to render human readable text. It is either a markdown string ----or a code-block that provides a language and a code snippet. The language identifier ----is semantically equal to the optional language identifier in fenced code blocks in GitHub ----issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting +---@class lsp.CompletionListCapabilities --- ----The pair of a language and a value is an equivalent to markdown: ----```${language} ----${value} ----``` +---The client supports the following itemDefaults on +---a completion list. --- ----Note that markdown strings will be sanitized - that means html will be escaped. ----@deprecated use MarkupContent instead. ----@alias lsp.MarkedString string|lsp._anonym50.MarkedString - ----A document filter describes a top level text document or ----a notebook cell document. +---The value lists the supported property names of the +---`CompletionList.itemDefaults` object. If omitted +---no properties are supported. --- ----@since 3.17.0 - proposed support for NotebookCellTextDocumentFilter. ----@alias lsp.DocumentFilter lsp.TextDocumentFilter|lsp.NotebookCellTextDocumentFilter - ----LSP object definition. ---@since 3.17.0 ----@alias lsp.LSPObject table +---@field itemDefaults? string[] ----The glob pattern. Either a string pattern or a relative pattern. +---@since 3.18.0 +---@class lsp.ClientSignatureInformationOptions --- ----@since 3.17.0 ----@alias lsp.GlobPattern lsp.Pattern|lsp.RelativePattern - ----A document filter denotes a document by different properties like ----the {@link TextDocument.languageId language}, the {@link Uri.scheme scheme} of ----its resource, or a glob-pattern that is applied to the {@link TextDocument.fileName path}. +---Client supports the following content formats for the documentation +---property. The order describes the preferred format of the client. +---@field documentationFormat? lsp.MarkupKind[] --- ----Glob patterns can have the following syntax: ----- `*` to match one or more characters in a path segment ----- `?` to match on one character in a path segment ----- `**` to match any number of path segments, including none ----- `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) ----- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) ----- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) +---Client capabilities specific to parameter information. +---@field parameterInformation? lsp.ClientSignatureParameterInformationOptions --- ----\@sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` ----\@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` +---The client supports the `activeParameter` property on `SignatureInformation` +---literal. --- ----@since 3.17.0 ----@alias lsp.TextDocumentFilter lsp._anonym51.TextDocumentFilter|lsp._anonym52.TextDocumentFilter|lsp._anonym53.TextDocumentFilter - ----A notebook document filter denotes a notebook document by ----different properties. The properties will be match ----against the notebook's URI (same as with documents) +---@since 3.16.0 +---@field activeParameterSupport? boolean --- ----@since 3.17.0 ----@alias lsp.NotebookDocumentFilter lsp._anonym54.NotebookDocumentFilter|lsp._anonym55.NotebookDocumentFilter|lsp._anonym56.NotebookDocumentFilter +---The client supports the `activeParameter` property on +---`SignatureHelp`/`SignatureInformation` being set to `null` to +---indicate that no parameter should be active. +--- +---@since 3.18.0 +---@proposed +---@field noActiveParameterSupport? boolean ----The glob pattern to watch relative to the base path. Glob patterns can have the following syntax: ----- `*` to match one or more characters in a path segment ----- `?` to match on one character in a path segment ----- `**` to match any number of path segments, including none ----- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) ----- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) ----- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) +---@since 3.18.0 +---@class lsp.ClientCodeActionLiteralOptions --- ----@since 3.17.0 ----@alias lsp.Pattern string +---The code action kind is support with the following value +---set. +---@field codeActionKind lsp.ClientCodeActionKindOptions ----@class lsp._anonym1.serverInfo +---@since 3.18.0 +---@class lsp.ClientCodeActionResolveOptions --- ----The name of the server as defined by the server. ----@field name string +---The properties that a client can resolve lazily. +---@field properties string[] + +---@since 3.18.0 +---@class lsp.ClientCodeLensResolveOptions --- ----The server's version as defined by the server. ----@field version? string +---The properties that a client can resolve lazily. +---@field properties string[] ----@class lsp._anonym3.itemDefaults.editRange ---- ----@field insert lsp.Range +---@since 3.18.0 +---@class lsp.ClientFoldingRangeKindOptions --- ----@field replace lsp.Range +---The folding range kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. +---@field valueSet? lsp.FoldingRangeKind[] ----@class lsp._anonym2.itemDefaults +---@since 3.18.0 +---@class lsp.ClientFoldingRangeOptions --- ----A default commit character set. +---If set, the client signals that it supports setting collapsedText on +---folding ranges to display custom labels instead of the default text. --- ---@since 3.17.0 ----@field commitCharacters? string[] ---- ----A default edit range. +---@field collapsedText? boolean + +---General diagnostics capabilities for pull and push model. +---@class lsp.DiagnosticsCapabilities --- ----@since 3.17.0 ----@field editRange? lsp.Range|lsp._anonym3.itemDefaults.editRange +---Whether the clients accepts diagnostics with related information. +---@field relatedInformation? boolean --- ----A default insert text format. +---Client supports the tag property to provide meta data about a diagnostic. +---Clients supporting tags have to handle unknown tags gracefully. --- ----@since 3.17.0 ----@field insertTextFormat? lsp.InsertTextFormat +---@since 3.15.0 +---@field tagSupport? lsp.ClientDiagnosticsTagOptions --- ----A default insert text mode. +---Client supports a codeDescription property --- ----@since 3.17.0 ----@field insertTextMode? lsp.InsertTextMode +---@since 3.16.0 +---@field codeDescriptionSupport? boolean --- ----A default data value. +---Whether code action supports the `data` property which is +---preserved between a `textDocument/publishDiagnostics` and +---`textDocument/codeAction` request. --- ----@since 3.17.0 ----@field data? lsp.LSPAny +---@since 3.16.0 +---@field dataSupport? boolean ----@class lsp._anonym4.disabled +---@since 3.18.0 +---@class lsp.ClientSemanticTokensRequestOptions --- ----Human readable description of why the code action is currently disabled. +---The client will send the `textDocument/semanticTokens/range` request if +---the server provides a corresponding handler. +---@field range? boolean|lsp._anonym2.range --- ----This is displayed in the code actions UI. ----@field reason string +---The client will send the `textDocument/semanticTokens/full` request if +---the server provides a corresponding handler. +---@field full? boolean|lsp.ClientSemanticTokensRequestFullDelta ----@class lsp._anonym5.location +---@since 3.18.0 +---@class lsp.ClientInlayHintResolveOptions --- ----@field uri lsp.DocumentUri - ----@class lsp._anonym6.range +---The properties that a client can resolve lazily. +---@field properties string[] ----@class lsp._anonym7.full +---@since 3.18.0 +---@class lsp.ClientShowMessageActionItemOptions --- ----The server supports deltas for full documents. ----@field delta? boolean +---Whether the client supports additional attributes which +---are preserved and send back to the server in the +---request's response. +---@field additionalPropertiesSupport? boolean ----@class lsp._anonym9.cells.structure ---- ----The change to the cell array. ----@field array lsp.NotebookCellArrayChange ---- ----Additional opened cell text documents. ----@field didOpen? lsp.TextDocumentItem[] +---@since 3.18.0 +---@class lsp.CompletionItemTagOptions --- ----Additional closed cell text documents. ----@field didClose? lsp.TextDocumentIdentifier[] +---The tags supported by the client. +---@field valueSet lsp.CompletionItemTag[] ----@class lsp._anonym10.cells.textContent ---- ----@field document lsp.VersionedTextDocumentIdentifier +---@since 3.18.0 +---@class lsp.ClientCompletionItemResolveOptions --- ----@field changes lsp.TextDocumentContentChangeEvent[] +---The properties that a client can resolve lazily. +---@field properties string[] ----@class lsp._anonym8.cells ---- ----Changes to the cell structure to add or ----remove cells. ----@field structure? lsp._anonym9.cells.structure ---- ----Changes to notebook cells properties like its ----kind, execution summary or metadata. ----@field data? lsp.NotebookCell[] +---@since 3.18.0 +---@class lsp.ClientCompletionItemInsertTextModeOptions --- ----Changes to the text content of notebook cells. ----@field textContent? lsp._anonym10.cells.textContent[] +---@field valueSet lsp.InsertTextMode[] ----@class lsp._anonym11.clientInfo +---@since 3.18.0 +---@class lsp.ClientSignatureParameterInformationOptions --- ----The name of the client as defined by the client. ----@field name string +---The client supports processing label offsets instead of a +---simple label string. --- ----The client's version as defined by the client. ----@field version? string +---@since 3.14.0 +---@field labelOffsetSupport? boolean ----@class lsp._anonym13.textDocument.diagnostic +---@since 3.18.0 +---@class lsp.ClientCodeActionKindOptions --- ----Whether the server supports `MarkupContent` in diagnostic messages. ----@field markupMessageSupport? boolean +---The code action kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. +---@field valueSet lsp.CodeActionKind[] ----@class lsp._anonym12.textDocument ---- ----Capabilities specific to the diagnostic pull model. ---- ---@since 3.18.0 ----@field diagnostic? lsp._anonym13.textDocument.diagnostic - ----@class lsp._anonym14.workspace ---- ----The server supports workspace folder. ---- ----@since 3.6.0 ----@field workspaceFolders? lsp.WorkspaceFoldersServerCapabilities ---- ----The server is interested in notifications/requests for operations on files. +---@class lsp.ClientDiagnosticsTagOptions --- ----@since 3.16.0 ----@field fileOperations? lsp.FileOperationOptions +---The tags supported by the client. +---@field valueSet lsp.DiagnosticTag[] ----@class lsp._anonym15.completionItem ---- ----The server has support for completion item label ----details (see also `CompletionItemLabelDetails`) when ----receiving a completion item in a resolve call. +---@since 3.18.0 +---@class lsp.ClientSemanticTokensRequestFullDelta --- ----@since 3.17.0 ----@field labelDetailsSupport? boolean +---The client will send the `textDocument/semanticTokens/full/delta` request if +---the server provides a corresponding handler. +---@field delta? boolean ----@class lsp._anonym17.notebookSelector.cells +---A set of predefined token types. This set is not fixed +---an clients can specify additional token types via the +---corresponding client capabilities. --- ----@field language string +---@since 3.16.0 +---@alias lsp.SemanticTokenTypes +---| "namespace" # namespace +---| "type" # type +---| "class" # class +---| "enum" # enum +---| "interface" # interface +---| "struct" # struct +---| "typeParameter" # typeParameter +---| "parameter" # parameter +---| "variable" # variable +---| "property" # property +---| "enumMember" # enumMember +---| "event" # event +---| "function" # function +---| "method" # method +---| "macro" # macro +---| "keyword" # keyword +---| "modifier" # modifier +---| "comment" # comment +---| "string" # string +---| "number" # number +---| "regexp" # regexp +---| "operator" # operator +---| "decorator" # decorator +---| "label" # label ----@class lsp._anonym16.notebookSelector ---- ----The notebook to be synced If a string ----value is provided it matches against the ----notebook type. '*' matches every notebook. ----@field notebook string|lsp.NotebookDocumentFilter +---A set of predefined token modifiers. This set is not fixed +---an clients can specify additional token types via the +---corresponding client capabilities. --- ----The cells of the matching notebook to be synced. ----@field cells? lsp._anonym17.notebookSelector.cells[] +---@since 3.16.0 +---@alias lsp.SemanticTokenModifiers +---| "declaration" # declaration +---| "definition" # definition +---| "readonly" # readonly +---| "static" # static +---| "deprecated" # deprecated +---| "abstract" # abstract +---| "async" # async +---| "modification" # modification +---| "documentation" # documentation +---| "defaultLibrary" # defaultLibrary ----@class lsp._anonym19.notebookSelector.cells +---The document diagnostic report kinds. --- ----@field language string +---@since 3.17.0 +---@alias lsp.DocumentDiagnosticReportKind +---| "full" # Full +---| "unchanged" # Unchanged ----@class lsp._anonym18.notebookSelector ---- ----The notebook to be synced If a string ----value is provided it matches against the ----notebook type. '*' matches every notebook. ----@field notebook? string|lsp.NotebookDocumentFilter ---- ----The cells of the matching notebook to be synced. ----@field cells lsp._anonym19.notebookSelector.cells[] +---Predefined error codes. +---@alias lsp.ErrorCodes +---| -32700 # ParseError +---| -32600 # InvalidRequest +---| -32601 # MethodNotFound +---| -32602 # InvalidParams +---| -32603 # InternalError +---| -32002 # ServerNotInitialized +---| -32001 # UnknownErrorCode ----@class lsp._anonym20.staleRequestSupport ---- ----The client will actively cancel the request. ----@field cancel boolean ---- ----The list of requests for which the client ----will retry the request if it receives a ----response with error code `ContentModified` ----@field retryOnContentModified string[] +---@alias lsp.LSPErrorCodes +---| -32803 # RequestFailed +---| -32802 # ServerCancelled +---| -32801 # ContentModified +---| -32800 # RequestCancelled ----@class lsp._anonym21.changeAnnotationSupport ---- ----Whether the client groups edits with equal labels into tree nodes, ----for instance all edits labelled with "Changes in Strings" would ----be a tree node. ----@field groupsOnLabel? boolean +---A set of predefined range kinds. +---@alias lsp.FoldingRangeKind +---| "comment" # Comment +---| "imports" # Imports +---| "region" # Region ----@class lsp._anonym22.symbolKind ---- ----The symbol kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ---- ----If this property is not present the client only supports ----the symbol kinds from `File` to `Array` as defined in ----the initial version of the protocol. ----@field valueSet? lsp.SymbolKind[] +---A symbol kind. +---@alias lsp.SymbolKind +---| 1 # File +---| 2 # Module +---| 3 # Namespace +---| 4 # Package +---| 5 # Class +---| 6 # Method +---| 7 # Property +---| 8 # Field +---| 9 # Constructor +---| 10 # Enum +---| 11 # Interface +---| 12 # Function +---| 13 # Variable +---| 14 # Constant +---| 15 # String +---| 16 # Number +---| 17 # Boolean +---| 18 # Array +---| 19 # Object +---| 20 # Key +---| 21 # Null +---| 22 # EnumMember +---| 23 # Struct +---| 24 # Event +---| 25 # Operator +---| 26 # TypeParameter ----@class lsp._anonym23.tagSupport +---Symbol tags are extra annotations that tweak the rendering of a symbol. --- ----The tags supported by the client. ----@field valueSet lsp.SymbolTag[] +---@since 3.16 +---@alias lsp.SymbolTag +---| 1 # Deprecated ----@class lsp._anonym24.resolveSupport +---Moniker uniqueness level to define scope of the moniker. --- ----The properties that a client can resolve lazily. Usually ----`location.range` ----@field properties string[] +---@since 3.16.0 +---@alias lsp.UniquenessLevel +---| "document" # document +---| "project" # project +---| "group" # group +---| "scheme" # scheme +---| "global" # global ----@class lsp._anonym26.completionItem.tagSupport +---The moniker kind. --- ----The tags supported by the client. ----@field valueSet lsp.CompletionItemTag[] +---@since 3.16.0 +---@alias lsp.MonikerKind +---| "import" # import +---| "export" # export +---| "local" # local ----@class lsp._anonym27.completionItem.resolveSupport +---Inlay hint kinds. --- ----The properties that a client can resolve lazily. ----@field properties string[] +---@since 3.17.0 +---@alias lsp.InlayHintKind +---| 1 # Type +---| 2 # Parameter ----@class lsp._anonym28.completionItem.insertTextModeSupport ---- ----@field valueSet lsp.InsertTextMode[] +---The message type +---@alias lsp.MessageType +---| 1 # Error +---| 2 # Warning +---| 3 # Info +---| 4 # Log +---| 5 # Debug ----@class lsp._anonym25.completionItem ---- ----Client supports snippets as insert text. ---- ----A snippet can define tab stops and placeholders with `$1`, `$2` ----and `${3:foo}`. `$0` defines the final tab stop, it defaults to ----the end of the snippet. Placeholders with equal identifiers are linked, ----that is typing in one will update others too. ----@field snippetSupport? boolean ---- ----Client supports commit characters on a completion item. ----@field commitCharactersSupport? boolean ---- ----Client supports the following content formats for the documentation ----property. The order describes the preferred format of the client. ----@field documentationFormat? lsp.MarkupKind[] ---- ----Client supports the deprecated property on a completion item. ----@field deprecatedSupport? boolean ---- ----Client supports the preselect property on a completion item. ----@field preselectSupport? boolean ---- ----Client supports the tag property on a completion item. Clients supporting ----tags have to handle unknown tags gracefully. Clients especially need to ----preserve unknown tags when sending a completion item back to the server in ----a resolve call. +---Defines how the host (editor) should sync +---document changes to the language server. +---@alias lsp.TextDocumentSyncKind +---| 0 # None +---| 1 # Full +---| 2 # Incremental + +---Represents reasons why a text document is saved. +---@alias lsp.TextDocumentSaveReason +---| 1 # Manual +---| 2 # AfterDelay +---| 3 # FocusOut + +---The kind of a completion entry. +---@alias lsp.CompletionItemKind +---| 1 # Text +---| 2 # Method +---| 3 # Function +---| 4 # Constructor +---| 5 # Field +---| 6 # Variable +---| 7 # Class +---| 8 # Interface +---| 9 # Module +---| 10 # Property +---| 11 # Unit +---| 12 # Value +---| 13 # Enum +---| 14 # Keyword +---| 15 # Snippet +---| 16 # Color +---| 17 # File +---| 18 # Reference +---| 19 # Folder +---| 20 # EnumMember +---| 21 # Constant +---| 22 # Struct +---| 23 # Event +---| 24 # Operator +---| 25 # TypeParameter + +---Completion item tags are extra annotations that tweak the rendering of a completion +---item. --- ---@since 3.15.0 ----@field tagSupport? lsp._anonym26.completionItem.tagSupport ---- ----Client support insert replace edit to control different behavior if a ----completion item is inserted in the text or should replace text. ---- ----@since 3.16.0 ----@field insertReplaceSupport? boolean ---- ----Indicates which properties a client can resolve lazily on a completion ----item. Before version 3.16.0 only the predefined properties `documentation` ----and `details` could be resolved lazily. ---- ----@since 3.16.0 ----@field resolveSupport? lsp._anonym27.completionItem.resolveSupport ---- ----The client supports the `insertTextMode` property on ----a completion item to override the whitespace handling mode ----as defined by the client (see `insertTextMode`). +---@alias lsp.CompletionItemTag +---| 1 # Deprecated + +---Defines whether the insert text in a completion item should be interpreted as +---plain text or a snippet. +---@alias lsp.InsertTextFormat +---| 1 # PlainText +---| 2 # Snippet + +---How whitespace and indentation is handled during completion +---item insertion. --- ---@since 3.16.0 ----@field insertTextModeSupport? lsp._anonym28.completionItem.insertTextModeSupport ---- ----The client has support for completion item label ----details (see also `CompletionItemLabelDetails`). ---- ----@since 3.17.0 ----@field labelDetailsSupport? boolean +---@alias lsp.InsertTextMode +---| 1 # asIs +---| 2 # adjustIndentation ----@class lsp._anonym29.completionItemKind ---- ----The completion item kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ---- ----If this property is not present the client only supports ----the completion items kinds from `Text` to `Reference` as defined in ----the initial version of the protocol. ----@field valueSet? lsp.CompletionItemKind[] +---A document highlight kind. +---@alias lsp.DocumentHighlightKind +---| 1 # Text +---| 2 # Read +---| 3 # Write ----@class lsp._anonym30.completionList ---- ----The client supports the following itemDefaults on ----a completion list. ---- ----The value lists the supported property names of the ----`CompletionList.itemDefaults` object. If omitted ----no properties are supported. ---- ----@since 3.17.0 ----@field itemDefaults? string[] +---A set of predefined code action kinds +---@alias lsp.CodeActionKind +---| "" # Empty +---| "quickfix" # QuickFix +---| "refactor" # Refactor +---| "refactor.extract" # RefactorExtract +---| "refactor.inline" # RefactorInline +---| "refactor.move" # RefactorMove +---| "refactor.rewrite" # RefactorRewrite +---| "source" # Source +---| "source.organizeImports" # SourceOrganizeImports +---| "source.fixAll" # SourceFixAll +---| "notebook" # Notebook ----@class lsp._anonym32.signatureInformation.parameterInformation ---- ----The client supports processing label offsets instead of a ----simple label string. ---- ----@since 3.14.0 ----@field labelOffsetSupport? boolean +---@alias lsp.TraceValue +---| "off" # Off +---| "messages" # Messages +---| "verbose" # Verbose ----@class lsp._anonym31.signatureInformation ---- ----Client supports the following content formats for the documentation ----property. The order describes the preferred format of the client. ----@field documentationFormat? lsp.MarkupKind[] ---- ----Client capabilities specific to parameter information. ----@field parameterInformation? lsp._anonym32.signatureInformation.parameterInformation ---- ----The client supports the `activeParameter` property on `SignatureInformation` ----literal. ---- ----@since 3.16.0 ----@field activeParameterSupport? boolean ---- ----The client supports the `activeParameter` property on ----`SignatureInformation` being set to `null` to indicate that no ----parameter should be active. +---Describes the content type that a client supports in various +---result literals like `Hover`, `ParameterInfo` or `CompletionItem`. --- +---Please note that `MarkupKinds` must not start with a `$`. This kinds +---are reserved for internal usage. +---@alias lsp.MarkupKind +---| "plaintext" # PlainText +---| "markdown" # Markdown + +---Predefined Language kinds ---@since 3.18.0 ----@field noActiveParameterSupport? boolean +---@proposed +---@alias lsp.LanguageKind +---| "abap" # ABAP +---| "bat" # WindowsBat +---| "bibtex" # BibTeX +---| "clojure" # Clojure +---| "coffeescript" # Coffeescript +---| "c" # C +---| "cpp" # CPP +---| "csharp" # CSharp +---| "css" # CSS +---| "d" # D +---| "pascal" # Delphi +---| "diff" # Diff +---| "dart" # Dart +---| "dockerfile" # Dockerfile +---| "elixir" # Elixir +---| "erlang" # Erlang +---| "fsharp" # FSharp +---| "git-commit" # GitCommit +---| "rebase" # GitRebase +---| "go" # Go +---| "groovy" # Groovy +---| "handlebars" # Handlebars +---| "haskell" # Haskell +---| "html" # HTML +---| "ini" # Ini +---| "java" # Java +---| "javascript" # JavaScript +---| "javascriptreact" # JavaScriptReact +---| "json" # JSON +---| "latex" # LaTeX +---| "less" # Less +---| "lua" # Lua +---| "makefile" # Makefile +---| "markdown" # Markdown +---| "objective-c" # ObjectiveC +---| "objective-cpp" # ObjectiveCPP +---| "pascal" # Pascal +---| "perl" # Perl +---| "perl6" # Perl6 +---| "php" # PHP +---| "powershell" # Powershell +---| "jade" # Pug +---| "python" # Python +---| "r" # R +---| "razor" # Razor +---| "ruby" # Ruby +---| "rust" # Rust +---| "scss" # SCSS +---| "sass" # SASS +---| "scala" # Scala +---| "shaderlab" # ShaderLab +---| "shellscript" # ShellScript +---| "sql" # SQL +---| "swift" # Swift +---| "typescript" # TypeScript +---| "typescriptreact" # TypeScriptReact +---| "tex" # TeX +---| "vb" # VisualBasic +---| "xml" # XML +---| "xsl" # XSL +---| "yaml" # YAML ----@class lsp._anonym33.symbolKind +---Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. --- ----The symbol kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. +---@since 3.18.0 +---@proposed +---@alias lsp.InlineCompletionTriggerKind +---| 1 # Invoked +---| 2 # Automatic + +---A set of predefined position encoding kinds. --- ----If this property is not present the client only supports ----the symbol kinds from `File` to `Array` as defined in ----the initial version of the protocol. ----@field valueSet? lsp.SymbolKind[] +---@since 3.17.0 +---@alias lsp.PositionEncodingKind +---| "utf-8" # UTF8 +---| "utf-16" # UTF16 +---| "utf-32" # UTF32 + +---The file event type +---@alias lsp.FileChangeType +---| 1 # Created +---| 2 # Changed +---| 3 # Deleted + +---@alias lsp.WatchKind +---| 1 # Create +---| 2 # Change +---| 4 # Delete + +---The diagnostic's severity. +---@alias lsp.DiagnosticSeverity +---| 1 # Error +---| 2 # Warning +---| 3 # Information +---| 4 # Hint ----@class lsp._anonym34.tagSupport +---The diagnostic tags. --- ----The tags supported by the client. ----@field valueSet lsp.SymbolTag[] +---@since 3.15.0 +---@alias lsp.DiagnosticTag +---| 1 # Unnecessary +---| 2 # Deprecated ----@class lsp._anonym36.codeActionLiteralSupport.codeActionKind ---- ----The code action kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ----@field valueSet lsp.CodeActionKind[] +---How a completion was triggered +---@alias lsp.CompletionTriggerKind +---| 1 # Invoked +---| 2 # TriggerCharacter +---| 3 # TriggerForIncompleteCompletions ----@class lsp._anonym35.codeActionLiteralSupport +---How a signature help was triggered. --- ----The code action kind is support with the following value ----set. ----@field codeActionKind lsp._anonym36.codeActionLiteralSupport.codeActionKind +---@since 3.15.0 +---@alias lsp.SignatureHelpTriggerKind +---| 1 # Invoked +---| 2 # TriggerCharacter +---| 3 # ContentChange ----@class lsp._anonym37.resolveSupport +---The reason why code actions were requested. --- ----The properties that a client can resolve lazily. ----@field properties string[] +---@since 3.17.0 +---@alias lsp.CodeActionTriggerKind +---| 1 # Invoked +---| 2 # Automatic ----@class lsp._anonym38.foldingRangeKind +---A pattern kind describing if a glob pattern matches a file a folder or +---both. --- ----The folding range kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ----@field valueSet? lsp.FoldingRangeKind[] +---@since 3.16.0 +---@alias lsp.FileOperationPatternKind +---| "file" # file +---| "folder" # folder ----@class lsp._anonym39.foldingRange ---- ----If set, the client signals that it supports setting collapsedText on ----folding ranges to display custom labels instead of the default text. +---A notebook cell kind. --- ---@since 3.17.0 ----@field collapsedText? boolean +---@alias lsp.NotebookCellKind +---| 1 # Markup +---| 2 # Code ----@class lsp._anonym40.tagSupport ---- ----The tags supported by the client. ----@field valueSet lsp.DiagnosticTag[] +---@alias lsp.ResourceOperationKind +---| "create" # Create +---| "rename" # Rename +---| "delete" # Delete ----@class lsp._anonym42.requests.range +---@alias lsp.FailureHandlingKind +---| "abort" # Abort +---| "transactional" # Transactional +---| "textOnlyTransactional" # TextOnlyTransactional +---| "undo" # Undo ----@class lsp._anonym43.requests.full ---- ----The client will send the `textDocument/semanticTokens/full/delta` request if ----the server provides a corresponding handler. ----@field delta? boolean +---@alias lsp.PrepareSupportDefaultBehavior +---| 1 # Identifier ----@class lsp._anonym41.requests ---- ----The client will send the `textDocument/semanticTokens/range` request if ----the server provides a corresponding handler. ----@field range? boolean|lsp._anonym42.requests.range ---- ----The client will send the `textDocument/semanticTokens/full` request if ----the server provides a corresponding handler. ----@field full? boolean|lsp._anonym43.requests.full +---@alias lsp.TokenFormat +---| "relative" # Relative ----@class lsp._anonym44.resolveSupport +---The definition of a symbol represented as one or many {@link Location locations}. +---For most programming languages there is only one location at which a symbol is +---defined. --- ----The properties that a client can resolve lazily. ----@field properties string[] +---Servers should prefer returning `DefinitionLink` over `Definition` if supported +---by the client. +---@alias lsp.Definition lsp.Location|lsp.Location[] ----@class lsp._anonym45.messageActionItem +---Information about where a symbol is defined. --- ----Whether the client supports additional attributes which ----are preserved and send back to the server in the ----request's response. ----@field additionalPropertiesSupport? boolean +---Provides additional metadata over normal {@link Location location} definitions, including the range of +---the defining symbol +---@alias lsp.DefinitionLink lsp.LocationLink ----@class lsp._anonym46.PrepareRenameResult ---- ----@field range lsp.Range ---- ----@field placeholder string +---LSP arrays. +---@since 3.17.0 +---@alias lsp.LSPArray lsp.LSPAny[] ----@class lsp._anonym47.PrepareRenameResult ---- ----@field defaultBehavior boolean +---The LSP any type. +---Please note that strictly speaking a property with the value `undefined` +---can't be converted into JSON preserving the property name. However for +---convenience it is allowed and assumed that all these properties are +---optional as well. +---@since 3.17.0 +---@alias lsp.LSPAny lsp.LSPObject|lsp.LSPArray|string|integer|uinteger|decimal|boolean|lsp.null ----@class lsp._anonym48.TextDocumentContentChangeEvent ---- ----The range of the document that changed. ----@field range lsp.Range ---- ----The optional length of the range that got replaced. +---The declaration of a symbol representation as one or many {@link Location locations}. +---@alias lsp.Declaration lsp.Location|lsp.Location[] + +---Information about where a symbol is declared. --- ----@deprecated use range instead. ----@field rangeLength? uinteger +---Provides additional metadata over normal {@link Location location} declarations, including the range of +---the declaring symbol. --- ----The new text for the provided range. ----@field text string +---Servers should prefer returning `DeclarationLink` over `Declaration` if supported +---by the client. +---@alias lsp.DeclarationLink lsp.LocationLink ----@class lsp._anonym49.TextDocumentContentChangeEvent +---Inline value information can be provided by different means: +---- directly as a text value (class InlineValueText). +---- as a name to use for a variable lookup (class InlineValueVariableLookup) +---- as an evaluatable expression (class InlineValueEvaluatableExpression) +---The InlineValue types combines all inline value types into one type. --- ----The new text of the whole document. ----@field text string +---@since 3.17.0 +---@alias lsp.InlineValue lsp.InlineValueText|lsp.InlineValueVariableLookup|lsp.InlineValueEvaluatableExpression ----@class lsp._anonym50.MarkedString ---- ----@field language string +---The result of a document diagnostic pull request. A report can +---either be a full report containing all diagnostics for the +---requested document or an unchanged report indicating that nothing +---has changed in terms of diagnostics in comparison to the last +---pull request. --- ----@field value string +---@since 3.17.0 +---@alias lsp.DocumentDiagnosticReport lsp.RelatedFullDocumentDiagnosticReport|lsp.RelatedUnchangedDocumentDiagnosticReport ----@class lsp._anonym51.TextDocumentFilter ---- ----A language id, like `typescript`. ----@field language string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string ---- ----A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ----@field pattern? string +---@alias lsp.PrepareRenameResult lsp.Range|lsp.PrepareRenamePlaceholder|lsp.PrepareRenameDefaultBehavior ----@class lsp._anonym52.TextDocumentFilter ---- ----A language id, like `typescript`. ----@field language? string +---A document selector is the combination of one or many document filters. --- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme string +---\@sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; --- ----A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ----@field pattern? string +---The use of a string as a document filter is deprecated @since 3.16.0. +---@alias lsp.DocumentSelector lsp.DocumentFilter[] + +---@alias lsp.ProgressToken integer|string ----@class lsp._anonym53.TextDocumentFilter +---An identifier to refer to a change annotation stored with a workspace edit. +---@alias lsp.ChangeAnnotationIdentifier string + +---A workspace diagnostic document report. --- ----A language id, like `typescript`. ----@field language? string +---@since 3.17.0 +---@alias lsp.WorkspaceDocumentDiagnosticReport lsp.WorkspaceFullDocumentDiagnosticReport|lsp.WorkspaceUnchangedDocumentDiagnosticReport + +---An event describing a change to a text document. If only a text is provided +---it is considered to be the full content of the document. +---@alias lsp.TextDocumentContentChangeEvent lsp.TextDocumentContentChangePartial|lsp.TextDocumentContentChangeWholeDocument + +---MarkedString can be used to render human readable text. It is either a markdown string +---or a code-block that provides a language and a code snippet. The language identifier +---is semantically equal to the optional language identifier in fenced code blocks in GitHub +---issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting --- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string +---The pair of a language and a value is an equivalent to markdown: +---```${language} +---${value} +---``` --- ----A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ----@field pattern string +---Note that markdown strings will be sanitized - that means html will be escaped. +---@deprecated use MarkupContent instead. +---@alias lsp.MarkedString string|lsp.MarkedStringWithLanguage ----@class lsp._anonym54.NotebookDocumentFilter ---- ----The type of the enclosing notebook. ----@field notebookType string +---A document filter describes a top level text document or +---a notebook cell document. --- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string +---@since 3.17.0 - proposed support for NotebookCellTextDocumentFilter. +---@alias lsp.DocumentFilter lsp.TextDocumentFilter|lsp.NotebookCellTextDocumentFilter + +---LSP object definition. +---@since 3.17.0 +---@alias lsp.LSPObject table + +---The glob pattern. Either a string pattern or a relative pattern. --- ----A glob pattern. ----@field pattern? string +---@since 3.17.0 +---@alias lsp.GlobPattern lsp.Pattern|lsp.RelativePattern ----@class lsp._anonym55.NotebookDocumentFilter +---A document filter denotes a document by different properties like +---the {@link TextDocument.languageId language}, the {@link Uri.scheme scheme} of +---its resource, or a glob-pattern that is applied to the {@link TextDocument.fileName path}. --- ----The type of the enclosing notebook. ----@field notebookType? string +---Glob patterns can have the following syntax: +---- `*` to match one or more characters in a path segment +---- `?` to match on one character in a path segment +---- `**` to match any number of path segments, including none +---- `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) +---- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) +---- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) --- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme string +---\@sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` +---\@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` --- ----A glob pattern. ----@field pattern? string +---@since 3.17.0 +---@alias lsp.TextDocumentFilter lsp.TextDocumentFilterLanguage|lsp.TextDocumentFilterScheme|lsp.TextDocumentFilterPattern ----@class lsp._anonym56.NotebookDocumentFilter ---- ----The type of the enclosing notebook. ----@field notebookType? string +---A notebook document filter denotes a notebook document by +---different properties. The properties will be match +---against the notebook's URI (same as with documents) --- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string +---@since 3.17.0 +---@alias lsp.NotebookDocumentFilter lsp.NotebookDocumentFilterNotebookType|lsp.NotebookDocumentFilterScheme|lsp.NotebookDocumentFilterPattern + +---The glob pattern to watch relative to the base path. Glob patterns can have the following syntax: +---- `*` to match one or more characters in a path segment +---- `?` to match on one character in a path segment +---- `**` to match any number of path segments, including none +---- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) +---- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) +---- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) --- ----A glob pattern. ----@field pattern string +---@since 3.17.0 +---@alias lsp.Pattern string + +---@alias lsp.RegularExpressionEngineKind string + +---@class lsp._anonym1.range + +---@class lsp._anonym2.range diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 2514a62f89..0eb10af1ea 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -615,9 +615,10 @@ function protocol.resolve_capabilities(server_capabilities) end -- Generated by gen_lsp.lua, keep at end of file. ---- LSP method names. --- +---@enum vim.lsp.protocol.Methods ---@see https://microsoft.github.io/language-server-protocol/specification/#metaModel +--- LSP method names. protocol.Methods = { --- A request to resolve the incoming calls for a given `CallHierarchyItem`. --- @since 3.16.0 @@ -880,14 +881,14 @@ protocol.Methods = { --- symbol's location. --- @since 3.17.0 workspaceSymbol_resolve = 'workspaceSymbol/resolve', - --- A request sent from the server to the client to modify certain resources. + --- A request sent from the server to the client to modified certain resources. workspace_applyEdit = 'workspace/applyEdit', --- A request to refresh all code actions --- @since 3.16.0 workspace_codeLens_refresh = 'workspace/codeLens/refresh', --- The 'workspace/configuration' request is sent from the server to the client to fetch a certain --- configuration setting. - --- This pull model replaces the old push model where the client signaled configuration change via an + --- This pull model replaces the old push model were the client signaled configuration change via an --- event. If the server still needs to react to configuration changes (since the server caches the --- result of `workspace/configuration` requests) the server should register for an empty configuration --- change event and empty the cache if such an event is received. @@ -920,7 +921,7 @@ protocol.Methods = { --- files were renamed from within the client. --- @since 3.16.0 workspace_didRenameFiles = 'workspace/didRenameFiles', - --- A request sent from the client to the server to execute a command. The request might return + --- A request send from the client to the server to execute a command. The request might return --- a workspace edit which the client will apply to the workspace. workspace_executeCommand = 'workspace/executeCommand', --- @since 3.18.0 -- cgit From fe5ae88b20f570b904ba8ca77dd8895e0d3627e4 Mon Sep 17 00:00:00 2001 From: atusy <30277794+atusy@users.noreply.github.com> Date: Tue, 20 Aug 2024 22:37:03 +0900 Subject: fix(lsp): update request name to capability map #30098 Add items based on specifications () - textDocument/documentColor - textDocument/inlineValue - textDocument/linkedEditingRange - textDocument/moniker - textDocument/onTypeFormatting - textDocument/selectionRange --- runtime/lua/vim/lsp.lua | 64 +++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 168172f345..97f78d3009 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -33,44 +33,50 @@ lsp.rpc_response_error = lsp.rpc.rpc_response_error -- maps request name to the required server_capability in the client. lsp._request_name_to_capability = { - [ms.textDocument_hover] = { 'hoverProvider' }, - [ms.textDocument_signatureHelp] = { 'signatureHelpProvider' }, - [ms.textDocument_definition] = { 'definitionProvider' }, - [ms.textDocument_implementation] = { 'implementationProvider' }, - [ms.textDocument_declaration] = { 'declarationProvider' }, - [ms.textDocument_typeDefinition] = { 'typeDefinitionProvider' }, - [ms.textDocument_documentSymbol] = { 'documentSymbolProvider' }, - [ms.textDocument_prepareCallHierarchy] = { 'callHierarchyProvider' }, [ms.callHierarchy_incomingCalls] = { 'callHierarchyProvider' }, [ms.callHierarchy_outgoingCalls] = { 'callHierarchyProvider' }, - [ms.textDocument_prepareTypeHierarchy] = { 'typeHierarchyProvider' }, - [ms.typeHierarchy_subtypes] = { 'typeHierarchyProvider' }, - [ms.typeHierarchy_supertypes] = { 'typeHierarchyProvider' }, - [ms.textDocument_rename] = { 'renameProvider' }, - [ms.textDocument_prepareRename] = { 'renameProvider', 'prepareProvider' }, + [ms.codeAction_resolve] = { 'codeActionProvider', 'resolveProvider' }, + [ms.codeLens_resolve] = { 'codeLensProvider', 'resolveProvider' }, + [ms.documentLink_resolve] = { 'documentLinkProvider', 'resolveProvider' }, + [ms.inlayHint_resolve] = { 'inlayHintProvider', 'resolveProvider' }, [ms.textDocument_codeAction] = { 'codeActionProvider' }, [ms.textDocument_codeLens] = { 'codeLensProvider' }, - [ms.codeLens_resolve] = { 'codeLensProvider', 'resolveProvider' }, - [ms.codeAction_resolve] = { 'codeActionProvider', 'resolveProvider' }, - [ms.workspace_executeCommand] = { 'executeCommandProvider' }, - [ms.workspace_symbol] = { 'workspaceSymbolProvider' }, - [ms.textDocument_references] = { 'referencesProvider' }, - [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' }, - [ms.textDocument_rangesFormatting] = { 'documentRangeFormattingProvider', 'rangesSupport' }, - [ms.textDocument_formatting] = { 'documentFormattingProvider' }, [ms.textDocument_completion] = { 'completionProvider' }, - [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' }, - [ms.textDocument_semanticTokens_full] = { 'semanticTokensProvider' }, - [ms.textDocument_semanticTokens_full_delta] = { 'semanticTokensProvider' }, - [ms.textDocument_inlayHint] = { 'inlayHintProvider' }, + [ms.textDocument_declaration] = { 'declarationProvider' }, + [ms.textDocument_definition] = { 'definitionProvider' }, [ms.textDocument_diagnostic] = { 'diagnosticProvider' }, - [ms.inlayHint_resolve] = { 'inlayHintProvider', 'resolveProvider' }, - [ms.textDocument_documentLink] = { 'documentLinkProvider' }, - [ms.documentLink_resolve] = { 'documentLinkProvider', 'resolveProvider' }, [ms.textDocument_didClose] = { 'textDocumentSync', 'openClose' }, [ms.textDocument_didOpen] = { 'textDocumentSync', 'openClose' }, - [ms.textDocument_willSave] = { 'textDocumentSync', 'willSave' }, + [ms.textDocument_documentColor] = { 'colorProvider' }, + [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' }, + [ms.textDocument_documentLink] = { 'documentLinkProvider' }, + [ms.textDocument_documentSymbol] = { 'documentSymbolProvider' }, + [ms.textDocument_formatting] = { 'documentFormattingProvider' }, + [ms.textDocument_hover] = { 'hoverProvider' }, + [ms.textDocument_implementation] = { 'implementationProvider' }, + [ms.textDocument_inlayHint] = { 'inlayHintProvider' }, + [ms.textDocument_inlineValue] = { 'inlineValueProvider' }, + [ms.textDocument_linkedEditingRange] = { 'linkedEditingRangeProvider' }, + [ms.textDocument_moniker] = { 'monikerProvider' }, + [ms.textDocument_onTypeFormatting] = { 'documentOnTypeFormattingProvider' }, + [ms.textDocument_prepareCallHierarchy] = { 'callHierarchyProvider' }, + [ms.textDocument_prepareRename] = { 'renameProvider', 'prepareProvider' }, + [ms.textDocument_prepareTypeHierarchy] = { 'typeHierarchyProvider' }, + [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' }, + [ms.textDocument_rangesFormatting] = { 'documentRangeFormattingProvider', 'rangesSupport' }, + [ms.textDocument_references] = { 'referencesProvider' }, + [ms.textDocument_rename] = { 'renameProvider' }, + [ms.textDocument_selectionRange] = { 'selectionRangeProvider' }, + [ms.textDocument_semanticTokens_full] = { 'semanticTokensProvider' }, + [ms.textDocument_semanticTokens_full_delta] = { 'semanticTokensProvider' }, + [ms.textDocument_signatureHelp] = { 'signatureHelpProvider' }, + [ms.textDocument_typeDefinition] = { 'typeDefinitionProvider' }, [ms.textDocument_willSaveWaitUntil] = { 'textDocumentSync', 'willSaveWaitUntil' }, + [ms.textDocument_willSave] = { 'textDocumentSync', 'willSave' }, + [ms.typeHierarchy_subtypes] = { 'typeHierarchyProvider' }, + [ms.typeHierarchy_supertypes] = { 'typeHierarchyProvider' }, + [ms.workspace_executeCommand] = { 'executeCommandProvider' }, + [ms.workspace_symbol] = { 'workspaceSymbolProvider' }, } -- TODO improve handling of scratch buffers with LSP attached. -- cgit From e48179f31e6503bfa86bf08538e64456e96446a8 Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 22 Aug 2024 15:51:44 +0800 Subject: fix(lsp): suppress completion request if completion is active (#30028) Problem: the autotrigger mechanism could fire completion requests despite completion already being active from another completion mechanism or manual trigger Solution: add a condition to avoid an additional request. --- runtime/lua/vim/lsp/completion.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 6a6659fd25..022edf5fab 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -403,6 +403,10 @@ local function trigger(bufnr, clients) reset_timer() Context:cancel_pending() + if tonumber(vim.fn.pumvisible()) == 1 and Context.isIncomplete then + return + end + local win = api.nvim_get_current_win() local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer local line = api.nvim_get_current_line() -- cgit From 1f5bcc7c4ed7a68ae4e23933aee04c50b4df8bb5 Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 23 Aug 2024 03:42:27 +0800 Subject: feat(lsp): completion opts support custom item conversion (#30060) Problem: Some items of completion results include function signatures that can cause the pum to be very long when a function has many params, because pum scales with the longest word/abbr. Solution: add custom covert function that can customise abbr to remove params. --- runtime/lua/vim/lsp/completion.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 022edf5fab..89d9a0e9b1 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -23,6 +23,7 @@ local ns_to_ms = 0.000001 --- @class vim.lsp.completion.BufHandle --- @field clients table --- @field triggers table +--- @field convert? fun(item: lsp.CompletionItem): table --- @type table local buf_handles = {} @@ -250,6 +251,8 @@ function M._lsp_to_complete_items(result, prefix, client_id) end local candidates = {} + local bufnr = api.nvim_get_current_buf() + local user_convert = vim.tbl_get(buf_handles, bufnr, 'convert') for _, item in ipairs(items) do if matches(item) then local word = get_completion_word(item) @@ -260,7 +263,7 @@ function M._lsp_to_complete_items(result, prefix, client_id) then hl_group = 'DiagnosticDeprecated' end - table.insert(candidates, { + local completion_item = { word = word, abbr = item.label, kind = protocol.CompletionItemKind[item.kind] or 'Unknown', @@ -278,7 +281,11 @@ function M._lsp_to_complete_items(result, prefix, client_id) }, }, }, - }) + } + if user_convert then + completion_item = vim.tbl_extend('keep', user_convert(item), completion_item) + end + table.insert(candidates, completion_item) end end ---@diagnostic disable-next-line: no-unknown @@ -590,14 +597,15 @@ end --- @class vim.lsp.completion.BufferOpts --- @field autotrigger? boolean Whether to trigger completion automatically. Default: false +--- @field convert? fun(item: lsp.CompletionItem): table An optional function used to customize the transformation of an LSP CompletionItem to |complete-items|. ---- @param client_id integer +---@param client_id integer ---@param bufnr integer ---@param opts vim.lsp.completion.BufferOpts local function enable_completions(client_id, bufnr, opts) local buf_handle = buf_handles[bufnr] if not buf_handle then - buf_handle = { clients = {}, triggers = {} } + buf_handle = { clients = {}, triggers = {}, convert = opts.convert } buf_handles[bufnr] = buf_handle -- Attach to buffer events. -- cgit From b8135a76b71f1af0d708e3dc58ccb58abad59f7c Mon Sep 17 00:00:00 2001 From: JonnyKong Date: Sun, 25 Aug 2024 03:57:02 +0000 Subject: fix(docs): wrong return value annotation for `nvim_buf_get_extmarks` --- runtime/lua/vim/_meta/api.lua | 2 +- runtime/lua/vim/_meta/api_keysets_extra.lua | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 7dace2f88a..871521db43 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -378,7 +378,7 @@ function vim.api.nvim_buf_get_commands(buffer, opts) end --- • details: Whether to include the details dict --- • hl_name: Whether to include highlight group name instead of --- id, true if omitted ---- @return vim.api.keyset.get_extmark_item +--- @return vim.api.keyset.get_extmark_item_by_id function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end --- Gets `extmarks` in "traversal order" from a `charwise` region defined by diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index 6e95190692..8faf5f49aa 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -43,11 +43,17 @@ error('Cannot require a meta file') --- @field line_hl_group? string --- @field cursorline_hl_group? string ---- @class vim.api.keyset.get_extmark_item +--- @class vim.api.keyset.get_extmark_item_by_id --- @field [1] integer row --- @field [2] integer col --- @field [3] vim.api.keyset.extmark_details? +--- @class vim.api.keyset.get_extmark_item +--- @field [1] integer extmark_id +--- @field [2] integer row +--- @field [3] integer col +--- @field [4] vim.api.keyset.extmark_details? + --- @class vim.api.keyset.get_mark --- @field [1] integer row --- @field [2] integer col -- cgit From 688b961d13bd54a14836f08c3ded3121d3fb15a0 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 19 Apr 2024 16:04:57 +0100 Subject: feat(treesitter): add support for wasm parsers Problem: Installing treesitter parser is hard (harder than climbing to heaven). Solution: Add optional support for wasm parsers with `wasmtime`. Notes: * Needs to be enabled by setting `ENABLE_WASMTIME` for tree-sitter and Neovim. Build with `make CMAKE_EXTRA_FLAGS=-DENABLE_WASMTIME=ON DEPS_CMAKE_FLAGS=-DENABLE_WASMTIME=ON` * Adds optional Rust (obviously) and C11 dependencies. * Wasmtime comes with a lot of features that can negatively affect Neovim performance due to library and symbol table size. Make sure to build with minimal features and full LTO. * To reduce re-compilation times, install `sccache` and build with `RUSTC_WRAPPER= make ...` --- runtime/lua/vim/treesitter/_meta.lua | 6 +++++- runtime/lua/vim/treesitter/health.lua | 3 +++ runtime/lua/vim/treesitter/language.lua | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua index 2aedf5754e..39d1f1f5f8 100644 --- a/runtime/lua/vim/treesitter/_meta.lua +++ b/runtime/lua/vim/treesitter/_meta.lua @@ -72,7 +72,11 @@ vim._ts_get_language_version = function() end --- @param path string --- @param lang string --- @param symbol_name? string -vim._ts_add_language = function(path, lang, symbol_name) end +vim._ts_add_language_from_object = function(path, lang, symbol_name) end + +--- @param path string +--- @param lang string +vim._ts_add_language_from_wasm = function(path, lang) end ---@return integer vim._ts_get_minimum_language_version = function() end diff --git a/runtime/lua/vim/treesitter/health.lua b/runtime/lua/vim/treesitter/health.lua index ed3616ef46..637f9ea543 100644 --- a/runtime/lua/vim/treesitter/health.lua +++ b/runtime/lua/vim/treesitter/health.lua @@ -28,6 +28,9 @@ function M.check() ) end end + + local can_wasm = vim._ts_add_language_from_wasm ~= nil + health.info(string.format('Can load WASM parsers: %s', tostring(can_wasm))) end return M diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index d0a74daa6c..e31ce6cb59 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -109,7 +109,14 @@ function M.add(lang, opts) path = paths[1] end - vim._ts_add_language(path, lang, symbol_name) + if vim.endswith(path, '.wasm') then + if not vim._ts_add_language_from_wasm then + error(string.format("Unable to load wasm parser '%s': not built with ENABLE_WASMTIME ", path)) + end + vim._ts_add_language_from_wasm(path, lang) + else + vim._ts_add_language_from_object(path, lang, symbol_name) + end M.register(lang, filetype) end -- cgit From 983953858e5610b104d35725c7da1e9025f60421 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Mon, 26 Aug 2024 17:34:54 +0200 Subject: fix(lsp): fix isIncomplete condition in completion trigger (#30130) Follow up to https://github.com/neovim/neovim/pull/30028#discussion_r1726539370 --- runtime/lua/vim/lsp/completion.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 89d9a0e9b1..e28fec5e25 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -410,7 +410,7 @@ local function trigger(bufnr, clients) reset_timer() Context:cancel_pending() - if tonumber(vim.fn.pumvisible()) == 1 and Context.isIncomplete then + if tonumber(vim.fn.pumvisible()) == 1 and not Context.isIncomplete then return end -- cgit From 0e394f136fcb030358dbc1e94a0a38a03b4b7dbf Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 26 Aug 2024 08:35:43 -0700 Subject: fix(lsp): log when receiving markup messages (#30065) --- runtime/lua/vim/lsp/diagnostic.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 5ed42700e3..ff52b40d60 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -110,6 +110,14 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) return vim.tbl_map(function(diagnostic) local start = diagnostic.range.start local _end = diagnostic.range['end'] + local message = diagnostic.message + if type(message) ~= 'string' then + vim.notify_once( + string.format('Unsupported Markup message from LSP client %d', client_id), + vim.lsp.log_levels.ERROR + ) + message = diagnostic.message.value + end --- @type vim.Diagnostic return { lnum = start.line, @@ -117,7 +125,7 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) end_lnum = _end.line, end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding), severity = severity_lsp_to_vim(diagnostic.severity), - message = diagnostic.message, + message = message, source = diagnostic.source, code = diagnostic.code, _tags = tags_lsp_to_vim(diagnostic, client_id), -- cgit From d9ccd828b0d46754b9bcb9b17f47c2a51968db05 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 26 Aug 2024 08:37:36 -0700 Subject: fix(lsp): return call hierarchy item, not the index (#30145) --- runtime/lua/vim/lsp/buf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index d7463d74f8..e51727ef13 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -464,7 +464,7 @@ local function pick_call_hierarchy_item(call_hierarchy_items) if choice < 1 or choice > #items then return end - return choice + return call_hierarchy_items[choice] end --- @param method string -- cgit From f8e1ebd6f62662129fdb54574b305189e4a0b7af Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Mon, 26 Aug 2024 20:40:37 -0700 Subject: fix(treesitter): escape things like `"` in omnifunc results --- runtime/lua/vim/treesitter/_query_linter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index 6b8c3a17f2..8654b89c9b 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -241,7 +241,7 @@ function M.omnifunc(findstart, base) end end for _, s in pairs(parser_info.symbols) do - local text = s[2] and s[1] or '"' .. s[1]:gsub([[\]], [[\\]]) .. '"' ---@type string + local text = s[2] and s[1] or string.format('%q', s[1]):gsub('\n', 'n') ---@type string if text:find(base, 1, true) then table.insert(items, text) end -- cgit From dad55f5e763f3f2f436a2ae4f4bb1f6c6442bb45 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Tue, 27 Aug 2024 11:16:33 -0700 Subject: feat(lsp): export diagnostic conversion functions (#30064) --- runtime/lua/vim/lsp/diagnostic.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index ff52b40d60..c10312484b 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -153,9 +153,10 @@ local function tags_vim_to_lsp(diagnostic) return tags end +--- Converts the input `vim.Diagnostic`s to LSP diagnostics. --- @param diagnostics vim.Diagnostic[] --- @return lsp.Diagnostic[] -local function diagnostic_vim_to_lsp(diagnostics) +function M.from(diagnostics) ---@param diagnostic vim.Diagnostic ---@return lsp.Diagnostic return vim.tbl_map(function(diagnostic) @@ -385,7 +386,7 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) diag_opts.lnum = line_nr or (api.nvim_win_get_cursor(0)[1] - 1) - return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, diag_opts)) + return M.from(vim.diagnostic.get(bufnr, diag_opts)) end --- Clear diagnostics from pull based clients -- cgit From cd05a72fec49bfaa3911c141ac605b67b6e2270a Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Thu, 29 Aug 2024 00:11:32 +0200 Subject: docs: misc (#29719) Co-authored-by: Evgeni Chasnovski Co-authored-by: Lauri Heiskanen Co-authored-by: Piotr Doroszewski <5605596+Doroszewski@users.noreply.github.com> Co-authored-by: Tobiasz Laskowski Co-authored-by: ariel-lindemann <41641978+ariel-lindemann@users.noreply.github.com> Co-authored-by: glepnir Co-authored-by: zeertzjq --- runtime/lua/vim/_meta/vimfn.lua | 2 +- runtime/lua/vim/filetype.lua | 2 +- runtime/lua/vim/lsp.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 54ac60e272..a4a6df8633 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1593,7 +1593,7 @@ function vim.fn.eventhandler() end --- On MS-Windows the ".exe", ".bat", etc. can optionally be --- included. Then the extensions in $PATHEXT are tried. Thus if --- "foo.exe" does not exist, "foo.exe.bat" can be found. If ---- $PATHEXT is not set then ".exe;.com;.bat;.cmd" is used. A dot +--- $PATHEXT is not set then ".com;.exe;.bat;.cmd" is used. A dot --- by itself can be used in $PATHEXT to try using the name --- without an extension. When 'shell' looks like a Unix shell, --- then the name is also tried without adding an extension. diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 71a49445de..d3c33c9564 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -2518,7 +2518,7 @@ end --- ['.*/etc/foo/.*%.conf'] = { 'dosini', { priority = 10 } }, --- -- A pattern containing an environment variable --- ['${XDG_CONFIG_HOME}/foo/git'] = 'git', ---- ['README.(%a+)$'] = function(path, bufnr, ext) +--- ['.*README.(%a+)'] = function(path, bufnr, ext) --- if ext == 'md' then --- return 'markdown' --- elseif ext == 'rst' then diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 97f78d3009..60677554ce 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1031,7 +1031,7 @@ end --- Provides an interface between the built-in client and a `formatexpr` function. --- --- Currently only supports a single client. This can be set via ---- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach` +--- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` or (more typically) in `on_attach` --- via `vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})'`. --- ---@param opts? vim.lsp.formatexpr.Opts -- cgit From 6c2186a998acb4a25ffa0b1b176be5119d1517aa Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 29 Aug 2024 18:02:23 +0800 Subject: docs(eval): fix wrong return type of getcharsearch() (#30176) --- runtime/lua/vim/_meta/vimfn.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index a4a6df8633..05b9fc2bbf 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -2861,7 +2861,7 @@ function vim.fn.getcharpos(expr) end --- nnoremap , getcharsearch().forward ? ',' : ';' --- Date: Thu, 29 Aug 2024 19:53:48 +0800 Subject: fix(man): check if buffer is valid before restoring 'tagfunc' (#30180) --- runtime/lua/man.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index b9213c8259..fce8f89be8 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -723,7 +723,7 @@ function M.open_page(count, smods, args) end sect, name = extract_sect_and_name_path(path) - local buf = fn.bufnr() + local buf = api.nvim_get_current_buf() local save_tfu = vim.bo[buf].tagfunc vim.bo[buf].tagfunc = "v:lua.require'man'.goto_tag" @@ -739,7 +739,9 @@ function M.open_page(count, smods, args) end end) - vim.bo[buf].tagfunc = save_tfu + if api.nvim_buf_is_valid(buf) then + vim.bo[buf].tagfunc = save_tfu + end if not ok then error(ret) -- cgit From 59baa5e8a1f9e71b82f28c2723ccc558370b6fc0 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 29 Aug 2024 09:36:33 -0700 Subject: fix(tohtml): apply sp color if present #30110 Problem: Things like underlines are always given a default foreground highlight regardless of the value of `sp`. Solution: Check for `sp` first, and apply that color to the text decoration color if it exists. Limitations: If there is no value of `sp`, vim applies a text decoration color that matches the foreground of the text. This is still not implemented (and seems like a much more complex problem): in TOhtml, the underline will still be given a default foreground highlight. --- runtime/lua/tohtml.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index a4b5a741bc..6a5bd6de9d 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -1003,6 +1003,7 @@ local function extend_style(out, state) --TODO(altermo) use local namespace (instead of global 0) local fg = vim.fn.synIDattr(hlid, 'fg#') local bg = vim.fn.synIDattr(hlid, 'bg#') + local sp = vim.fn.synIDattr(hlid, 'sp#') local decor_line = {} if vim.fn.synIDattr(hlid, 'underline') ~= '' then table.insert(decor_line, 'underline') @@ -1020,6 +1021,8 @@ local function extend_style(out, state) ['font-weight'] = vim.fn.synIDattr(hlid, 'bold') ~= '' and 'bold' or nil, ['text-decoration-line'] = not vim.tbl_isempty(decor_line) and table.concat(decor_line, ' ') or nil, + -- TODO(ribru17): fallback to displayed text color if sp not set + ['text-decoration-color'] = sp ~= '' and cterm_to_hex(sp) or nil, --TODO(altermo) if strikethrough and undercurl then the strikethrough becomes wavy ['text-decoration-style'] = vim.fn.synIDattr(hlid, 'undercurl') ~= '' and 'wavy' or nil, } -- cgit From cfdf68a7acde16597fbd896674af68c42361102c Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 8 Aug 2024 10:42:08 +0200 Subject: feat(mbyte): support extended grapheme clusters including more emoji Use the grapheme break algorithm from utf8proc to support grapheme clusters from recent unicode versions. Handle variant selector VS16 turning some codepoints into double-width emoji. This means we need to use ptr2cells rather than char2cells when possible. --- runtime/lua/vim/_meta/options.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index b4ac478b61..05c9b89d77 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -1829,9 +1829,12 @@ vim.go.ead = vim.go.eadirection --- When on all Unicode emoji characters are considered to be full width. --- This excludes "text emoji" characters, which are normally displayed as ---- single width. Unfortunately there is no good specification for this ---- and it has been determined on trial-and-error basis. Use the ---- `setcellwidths()` function to change the behavior. +--- single width. However, such "text emoji" are treated as full-width +--- emoji if they are followed by the U+FE0F variant selector. +--- +--- Unfortunately there is no good specification for this and it has been +--- determined on trial-and-error basis. Use the `setcellwidths()` +--- function to change the behavior. --- --- @type boolean vim.o.emoji = true -- cgit From 42ed0ffad9851f3794a9dff080a2789c87c6d7c8 Mon Sep 17 00:00:00 2001 From: glepnir Date: Sat, 31 Aug 2024 02:23:49 +0800 Subject: fix(lsp): when prefix is non word add all result into matches (#30044) Problem: prefix can be a symbol like period, the fuzzy matching can't handle it correctly. Solution: when prefix is empty or a symbol add all lsp completion result into matches. --- runtime/lua/vim/lsp/completion.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index e28fec5e25..89d6d0e8b9 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -238,7 +238,7 @@ function M._lsp_to_complete_items(result, prefix, client_id) ---@type fun(item: lsp.CompletionItem):boolean local matches - if prefix == '' then + if not prefix:find('%w') then matches = function(_) return true end -- cgit From 9762c5e3406cab8152d8dd161c0178965d841676 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 31 Aug 2024 19:56:20 -0500 Subject: feat(ui): gx: use url extmark attribute and tree-sitter directive (#30192) Use the "url" extmark attribute as well as the "url" tree-sitter metadata key to determine if the cursor is over something Nvim considers a URL. --- runtime/lua/vim/_defaults.lua | 8 +++-- runtime/lua/vim/ui.lua | 70 ++++++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 21 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 630f2219c7..38cfdbdd32 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -113,9 +113,11 @@ do local gx_desc = 'Opens filepath or URI under cursor with the system handler (file explorer, web browser, …)' vim.keymap.set({ 'n' }, 'gx', function() - local err = do_open(require('vim.ui')._get_url()) - if err then - vim.notify(err, vim.log.levels.ERROR) + for _, url in ipairs(require('vim.ui')._get_urls()) do + local err = do_open(url) + if err then + vim.notify(err, vim.log.levels.ERROR) + end end end, { desc = gx_desc }) vim.keymap.set({ 'x' }, 'gx', function() diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index dccdbf32cc..b831a4f23e 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -167,29 +167,63 @@ function M.open(path) return vim.system(cmd, opts), nil end ---- Gets the URL at cursor, if any. -function M._get_url() - if vim.bo.filetype == 'markdown' then - local range = vim.api.nvim_win_get_cursor(0) - vim.treesitter.get_parser():parse(range) - -- marking the node as `markdown_inline` is required. Setting it to `markdown` does not - -- work. - local current_node = vim.treesitter.get_node { lang = 'markdown_inline' } - while current_node do - local type = current_node:type() - if type == 'inline_link' or type == 'image' then - local child = assert(current_node:named_child(1)) - return vim.treesitter.get_node_text(child, 0) +--- Returns all URLs at cursor, if any. +--- @return string[] +function M._get_urls() + local urls = {} + + local bufnr = vim.api.nvim_get_current_buf() + local cursor = vim.api.nvim_win_get_cursor(0) + local row = cursor[1] - 1 + local col = cursor[2] + local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, -1, { row, col }, { row, col }, { + details = true, + type = 'highlight', + overlap = true, + }) + for _, v in ipairs(extmarks) do + local details = v[4] + if details.url then + urls[#urls + 1] = details.url + end + end + + local highlighter = vim.treesitter.highlighter.active[bufnr] + if highlighter then + local range = { row, col, row, col } + local ltree = highlighter.tree:language_for_range(range) + local lang = ltree:lang() + local query = vim.treesitter.query.get(lang, 'highlights') + if query then + local tree = ltree:tree_for_range(range) + for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1, { all = true }) do + for id, nodes in pairs(match) do + for _, node in ipairs(nodes) do + if vim.treesitter.node_contains(node, range) then + local url = metadata[id] and metadata[id].url + if url and match[url] then + for _, n in ipairs(match[url]) do + urls[#urls + 1] = vim.treesitter.get_node_text(n, bufnr, metadata[url]) + end + end + end + end + end end - current_node = current_node:parent() end end - local url = vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function() - return vim.fn.expand('') - end) + if #urls == 0 then + -- If all else fails, use the filename under the cursor + table.insert( + urls, + vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function() + return vim.fn.expand('') + end) + ) + end - return url + return urls end return M -- cgit From 9b983e5f6cbfeaaf491ad57912518042be650b6d Mon Sep 17 00:00:00 2001 From: Yi Ming Date: Sun, 1 Sep 2024 12:07:07 +0800 Subject: docs(treesitter): annotate some tables as `TSMetadata` --- runtime/lua/vim/treesitter/query.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index ef5c2143a7..8e21353154 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -487,8 +487,8 @@ predicate_handlers['any-vim-match?'] = predicate_handlers['any-match?'] ---@class vim.treesitter.query.TSMetadata ---@field range? Range ---@field conceal? string ----@field [integer] vim.treesitter.query.TSMetadata ----@field [string] integer|string +---@field [integer]? vim.treesitter.query.TSMetadata +---@field [string]? integer|string ---@alias TSDirective fun(match: table, _, _, predicate: (string|integer)[], metadata: vim.treesitter.query.TSMetadata) @@ -627,7 +627,7 @@ local directive_handlers = { --- Adds a new predicate to be used in queries --- ---@param name string Name of the predicate, without leading # ----@param handler fun(match: table, pattern: integer, source: integer|string, predicate: any[], metadata: table) +---@param handler fun(match: table, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata) --- - see |vim.treesitter.query.add_directive()| for argument meanings ---@param opts vim.treesitter.query.add_predicate.Opts function M.add_predicate(name, handler, opts) @@ -667,7 +667,7 @@ end --- metadata table `metadata[capture_id].key = value` --- ---@param name string Name of the directive, without leading # ----@param handler fun(match: table, pattern: integer, source: integer|string, predicate: any[], metadata: table) +---@param handler fun(match: table, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata) --- - match: A table mapping capture IDs to a list of captured nodes --- - pattern: the index of the matching pattern in the query file --- - predicate: list of strings containing the full directive being called, e.g. @@ -929,7 +929,7 @@ end --- Older versions of iter_matches incorrectly mapped capture IDs to a single node, which is --- incorrect behavior. This option will eventually become the default and removed. --- ----@return (fun(): integer, table, table): pattern id, match, metadata +---@return (fun(): integer, table, vim.treesitter.query.TSMetadata): pattern id, match, metadata function Query:iter_matches(node, source, start, stop, opts) opts = opts or {} opts.match_limit = opts.match_limit or 256 -- cgit From 318c0415d5b10b44fee4afa06994734f1beb7e71 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:15:02 -0500 Subject: fix(ui): correctly pass metadata to get_node_text #30222 Fixes: #30220 --- runtime/lua/vim/_meta/api_keysets_extra.lua | 2 +- runtime/lua/vim/ui.lua | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index 8faf5f49aa..81bce50746 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -23,7 +23,7 @@ error('Cannot require a meta file') --- @field conceal? boolean --- @field spell? boolean --- @field ui_watched? boolean ---- @field url? boolean +--- @field url? string --- @field hl_mode? string --- --- @field virt_text? [string, string][] diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index b831a4f23e..c2b19e92c0 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -170,7 +170,7 @@ end --- Returns all URLs at cursor, if any. --- @return string[] function M._get_urls() - local urls = {} + local urls = {} ---@type string[] local bufnr = vim.api.nvim_get_current_buf() local cursor = vim.api.nvim_win_get_cursor(0) @@ -183,7 +183,7 @@ function M._get_urls() }) for _, v in ipairs(extmarks) do local details = v[4] - if details.url then + if details and details.url then urls[#urls + 1] = details.url end end @@ -195,7 +195,7 @@ function M._get_urls() local lang = ltree:lang() local query = vim.treesitter.query.get(lang, 'highlights') if query then - local tree = ltree:tree_for_range(range) + local tree = assert(ltree:tree_for_range(range)) for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1, { all = true }) do for id, nodes in pairs(match) do for _, node in ipairs(nodes) do @@ -203,7 +203,8 @@ function M._get_urls() local url = metadata[id] and metadata[id].url if url and match[url] then for _, n in ipairs(match[url]) do - urls[#urls + 1] = vim.treesitter.get_node_text(n, bufnr, metadata[url]) + urls[#urls + 1] = + vim.treesitter.get_node_text(n, bufnr, { metadata = metadata[url] }) end end end -- cgit From 6913c5e1d975a11262d08b3339d50b579e6b6bb8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:01:53 -0500 Subject: feat(treesitter)!: default to correct behavior for quantified captures (#30193) For context, see https://github.com/neovim/neovim/pull/24738. Before that PR, Nvim did not correctly handle captures with quantifiers. That PR made the correct behavior opt-in to minimize breaking changes, with the intention that the correct behavior would eventually become the default. Users can still opt-in to the old (incorrect) behavior for now, but this option will eventually be removed completely. BREAKING CHANGE: Any plugin which uses `Query:iter_matches()` must update their call sites to expect an array of nodes in the `match` table, rather than a single node. --- runtime/lua/vim/treesitter/_fold.lua | 4 +--- runtime/lua/vim/treesitter/_query_linter.lua | 2 +- runtime/lua/vim/treesitter/languagetree.lua | 8 +------- runtime/lua/vim/treesitter/query.lua | 28 +++++++++++----------------- runtime/lua/vim/ui.lua | 2 +- 5 files changed, 15 insertions(+), 29 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua index 27590eff5d..7375beaf9d 100644 --- a/runtime/lua/vim/treesitter/_fold.lua +++ b/runtime/lua/vim/treesitter/_fold.lua @@ -131,9 +131,7 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections) -- Collect folds starting from srow - 1, because we should first subtract the folds that end at -- srow - 1 from the level of srow - 1 to get accurate level of srow. - for _, match, metadata in - query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow, { all = true }) - do + for _, match, metadata in query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow) do for id, nodes in pairs(match) do if query.captures[id] == 'fold' then local range = ts.get_range(nodes[1], bufnr, metadata[id]) diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index 8654b89c9b..ea1ae5416a 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -176,7 +176,7 @@ function M.lint(buf, opts) parser:parse() parser:for_each_tree(function(tree, ltree) if ltree:lang() == 'query' then - for _, match, _ in query:iter_matches(tree:root(), buf, 0, -1, { all = true }) do + for _, match, _ in query:iter_matches(tree:root(), buf, 0, -1) do local lang_context = { lang = lang, parser_info = parser_info, diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index d43a0a5d0b..cc9ffeaa29 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -833,13 +833,7 @@ function LanguageTree:_get_injections() local start_line, _, end_line, _ = root_node:range() for pattern, match, metadata in - self._injection_query:iter_matches( - root_node, - self._source, - start_line, - end_line + 1, - { all = true } - ) + self._injection_query:iter_matches(root_node, self._source, start_line, end_line + 1) do local lang, combined, ranges = self:_get_injection(match, metadata) if lang then diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 8e21353154..bd0574b8b7 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -620,8 +620,8 @@ local directive_handlers = { --- @field force? boolean --- --- Use the correct implementation of the match table where capture IDs map to ---- a list of nodes instead of a single node. Defaults to false (for backward ---- compatibility). This option will eventually become the default and removed. +--- a list of nodes instead of a single node. Defaults to true. This option will +--- be removed in a future release. --- @field all? boolean --- Adds a new predicate to be used in queries @@ -629,7 +629,7 @@ local directive_handlers = { ---@param name string Name of the predicate, without leading # ---@param handler fun(match: table, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata) --- - see |vim.treesitter.query.add_directive()| for argument meanings ----@param opts vim.treesitter.query.add_predicate.Opts +---@param opts? vim.treesitter.query.add_predicate.Opts function M.add_predicate(name, handler, opts) -- Backward compatibility: old signature had "force" as boolean argument if type(opts) == 'boolean' then @@ -642,7 +642,7 @@ function M.add_predicate(name, handler, opts) error(string.format('Overriding existing predicate %s', name)) end - if opts.all then + if opts.all ~= false then predicate_handlers[name] = handler else --- @param match table @@ -894,16 +894,10 @@ end --- index of the pattern in the query, a table mapping capture indices to a list --- of nodes, and metadata from any directives processing the match. --- ---- WARNING: Set `all=true` to ensure all matching nodes in a match are ---- returned, otherwise only the last node in a match is returned, breaking captures ---- involving quantifiers such as `(comment)+ @comment`. The default option ---- `all=false` is only provided for backward compatibility and will be removed ---- after Nvim 0.10. ---- --- Example: --- --- ```lua ---- for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, 0, -1, { all = true }) do +--- for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, 0, -1) do --- for id, nodes in pairs(match) do --- local name = query.captures[id] --- for _, node in ipairs(nodes) do @@ -925,9 +919,9 @@ end --- - max_start_depth (integer) if non-zero, sets the maximum start depth --- for each match. This is used to prevent traversing too deep into a tree. --- - match_limit (integer) Set the maximum number of in-progress matches (Default: 256). ---- - all (boolean) When set, the returned match table maps capture IDs to a list of nodes. ---- Older versions of iter_matches incorrectly mapped capture IDs to a single node, which is ---- incorrect behavior. This option will eventually become the default and removed. +--- - all (boolean) When `false` (default `true`), the returned table maps capture IDs to a single +--- (last) node instead of the full list of matching nodes. This option is only for backward +--- compatibility and will be removed in a future release. --- ---@return (fun(): integer, table, vim.treesitter.query.TSMetadata): pattern id, match, metadata function Query:iter_matches(node, source, start, stop, opts) @@ -960,10 +954,10 @@ function Query:iter_matches(node, source, start, stop, opts) local captures = match:captures() - if not opts.all then + if opts.all == false then -- Convert the match table into the old buggy version for backward - -- compatibility. This is slow. Plugin authors, if you're reading this, set the "all" - -- option! + -- compatibility. This is slow, but we only do it when the caller explicitly opted into it by + -- setting `all` to `false`. local old_match = {} ---@type table for k, v in pairs(captures or {}) do old_match[k] = v[#v] diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index c2b19e92c0..2d3b828ea1 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -196,7 +196,7 @@ function M._get_urls() local query = vim.treesitter.query.get(lang, 'highlights') if query then local tree = assert(ltree:tree_for_range(range)) - for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1, { all = true }) do + for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1) do for id, nodes in pairs(match) do for _, node in ipairs(nodes) do if vim.treesitter.node_contains(node, range) then -- cgit From 61e9137394fc5229e582a64316c2ffef55d8d7af Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Sep 2024 13:01:24 -0700 Subject: docs: misc #28970 --- runtime/lua/vim/_editor.lua | 26 +++++++++++++------------- runtime/lua/vim/_meta/vimfn.lua | 1 + runtime/lua/vim/health.lua | 4 ++-- runtime/lua/vim/iter.lua | 10 ++++++---- runtime/lua/vim/lsp/completion.lua | 2 +- 5 files changed, 23 insertions(+), 20 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index c7c8362bfb..7b5570cc99 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -1,17 +1,19 @@ -- Nvim-Lua stdlib: the `vim` module (:help lua-stdlib) -- --- Lua code lives in one of three places: --- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the --- `inspect` and `lpeg` modules. --- 2. runtime/lua/vim/shared.lua: pure Lua functions which always --- are available. Used in the test runner, as well as worker threads --- and processes launched from Nvim. --- 3. runtime/lua/vim/_editor.lua: Code which directly interacts with --- the Nvim editor state. Only available in the main thread. +-- Lua code lives in one of four places: +-- 1. Plugins! Not everything needs to live on "vim.*". Plugins are the correct model for +-- non-essential features which the user may want to disable or replace with a third-party +-- plugin. Examples: "editorconfig", "comment". +-- - "opt-out": runtime/plugin/*.lua +-- - "opt-in": runtime/pack/dist/opt/ +-- 2. runtime/lua/vim/ (the runtime): Lazy-loaded modules. Examples: `inspect`, `lpeg`. +-- 3. runtime/lua/vim/shared.lua: pure Lua functions which always are available. Used in the test +-- runner, as well as worker threads and processes launched from Nvim. +-- 4. runtime/lua/vim/_editor.lua: Eager-loaded code which directly interacts with the Nvim +-- editor state. Only available in the main thread. -- --- Guideline: "If in doubt, put it in the runtime". --- --- Most functions should live directly in `vim.`, not in submodules. +-- The top level "vim.*" namespace is for fundamental Lua and editor features. Use submodules for +-- everything else (but avoid excessive "nesting"), or plugins (see above). -- -- Compatibility with Vim's `if_lua` is explicitly a non-goal. -- @@ -19,9 +21,7 @@ -- - https://github.com/luafun/luafun -- - https://github.com/rxi/lume -- - http://leafo.net/lapis/reference/utilities.html --- - https://github.com/torch/paths -- - https://github.com/bakpakin/Fennel (pretty print, repl) --- - https://github.com/howl-editor/howl/tree/master/lib/howl/util -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 05b9fc2bbf..10b09333a8 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -5262,6 +5262,7 @@ function vim.fn.map(expr1, expr2) end --- "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate --- form, only present when it differs from "lhsraw" --- "rhs" The {rhs} of the mapping as typed. +--- "callback" Lua function, if RHS was defined as such. --- "silent" 1 for a |:map-silent| mapping, else 0. --- "noremap" 1 if the {rhs} of the mapping is not remappable. --- "script" 1 if mapping was defined with