diff --git a/.emmyrc.json b/.emmyrc.json new file mode 100644 index 0000000000..04aa9d3724 --- /dev/null +++ b/.emmyrc.json @@ -0,0 +1,14 @@ +{ + "diagnostics" : { + "disable" : [ + "unnecessary-if" + ] + }, + "codeAction": { + "insertSpace": true + }, + "strict": { + "typeCall": true, + "arrayIndex": true + } +} diff --git a/Makefile b/Makefile index 29b2644bb8..39b07ee3c6 100644 --- a/Makefile +++ b/Makefile @@ -182,3 +182,9 @@ appimage-%: bash scripts/genappimage.sh $* .PHONY: test clean distclean nvim libnvim cmake deps install appimage checkprefix benchmark $(FORMAT) $(LINT) $(TEST) + +.PHONY: emmylua-check +emmylua-check: + -emmylua_check runtime/lua \ + --config .luarc.json \ + --config .emmyrc.json diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index e0b2b678b0..fa684c246f 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -430,6 +430,8 @@ Example: >lua Lua module: vim.diagnostic *diagnostic-api* *vim.Diagnostic* + Extends: |vim.Diagnostic.Set| + *diagnostic-structure* Diagnostics use the same indexing as the rest of the Nvim API (i.e. @@ -437,8 +439,6 @@ Lua module: vim.diagnostic *diagnostic-api* Fields: ~ • {bufnr} (`integer`) Buffer number - • {lnum} (`integer`) The starting line of the diagnostic - (0-indexed) • {end_lnum} (`integer`) The final line of the diagnostic (0-indexed) • {col} (`integer`) The starting column of the diagnostic (0-indexed) @@ -446,29 +446,27 @@ Lua module: vim.diagnostic *diagnostic-api* (0-indexed) • {severity} (`vim.diagnostic.Severity`) The severity of the diagnostic |vim.diagnostic.severity| + • {namespace}? (`integer`) + +*vim.Diagnostic.Set* + Diagnostics use the same indexing as the rest of the Nvim API (i.e. + 0-based rows and columns). |api-indexing| + + Fields: ~ + • {lnum} (`integer`) The starting line of the diagnostic + (0-indexed) + • {col}? (`integer`, default: `0`) The starting column of the + diagnostic (0-indexed) + • {end_lnum}? (`integer`, default: `lnum`) The final line of the + diagnostic (0-indexed) + • {end_col}? (`integer`, default: `col`) The final column of the + diagnostic (0-indexed) + • {severity}? (`vim.diagnostic.Severity`, default: `vim.diagnostic.severity.ERROR`) + The severity of the diagnostic |vim.diagnostic.severity| • {message} (`string`) The diagnostic text • {source}? (`string`) The source of the diagnostic • {code}? (`string|integer`) The diagnostic code • {user_data}? (`any`) arbitrary data plugins can add - • {namespace}? (`integer`) - -*vim.Diagnostic.Set* - Extends: |vim.Diagnostic| - - - Fields: ~ - • {bufnr} (`nil`) Do not set. Will be overridden by - `vim.diagnostic.set()`. - • {namespace} (`nil`) Do not set. Will be overridden by - `vim.diagnostic.set()`. - • {col}? (`integer`, default: `0`) The starting column of the - diagnostic in bytes (0-indexed) - • {end_lnum}? (`integer`, default: same as `lnum`) The final line of - the diagnostic (0-indexed) - • {end_col}? (`integer`, default: same as `col`) The final column of - the diagnostic (0-indexed) - • {severity}? (`vim.diagnostic.Severity`, default: `vim.diagnostic.severity.ERROR`) - The severity of the diagnostic |vim.diagnostic.severity| *vim.diagnostic.GetOpts* A table with the following keys: diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 22657fa91c..62d2da07c9 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1069,7 +1069,7 @@ get_client_by_id({client_id}) *vim.lsp.get_client_by_id()* • {client_id} (`integer`) client id Return: ~ - (`vim.lsp.Client?`) client rpc object + (`vim.lsp.Client?`) client rpc object. See |vim.lsp.Client|. get_clients({filter}) *vim.lsp.get_clients()* Get active clients. @@ -1279,7 +1279,8 @@ Lua module: vim.lsp.client *lsp-client* • {id} (`integer`) The id allocated to the client. • {initialized} (`true?`) • {name} (`string`) See |vim.lsp.ClientConfig|. - • {offset_encoding} (`string`) See |vim.lsp.ClientConfig|. + • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) See + |vim.lsp.ClientConfig|. • {progress} (`vim.lsp.Client.Progress`) A ring buffer (|vim.ringbuf()|) containing progress messages sent by the server. See @@ -2546,7 +2547,7 @@ make_workspace_params({added}, {removed}) • {removed} (`lsp.WorkspaceFolder[]`) Return: ~ - (`lsp.WorkspaceFoldersChangeEvent`) + (`lsp.DidChangeWorkspaceFoldersParams`) *vim.lsp.util.open_floating_preview()* open_floating_preview({contents}, {syntax}, {opts}) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 26b591d077..7867492151 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -626,10 +626,10 @@ vim.hl.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts}) • {bufnr} (`integer`) Buffer number to apply highlighting to • {ns} (`integer`) Namespace to add highlight to • {higroup} (`string`) Highlight group to use for highlighting - • {start} (`integer[]|string`) Start of region as a (line, column) - tuple or string accepted by |getpos()| - • {finish} (`integer[]|string`) End of region as a (line, column) - tuple or string accepted by |getpos()| + • {start} (`[integer,integer]|string`) Start of region as a (line, + column) tuple or string accepted by |getpos()| + • {finish} (`[integer,integer]|string`) End of region as a (line, + column) tuple or string accepted by |getpos()| • {opts} (`table?`) A table with the following fields: • {regtype}? (`string`, default: `'v'` i.e. charwise) Type of range. See |getregtype()| @@ -4684,7 +4684,7 @@ vim.text.indent({size}, {text}, {opts}) *vim.text.indent()* Parameters: ~ • {size} (`integer`) Number of spaces. • {text} (`string`) Text to indent. - • {opts} (`{ expandtab?: number }?`) + • {opts} (`{ expandtab?: integer }?`) Return (multiple): ~ (`string`) Indented text. diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt index d64779af8c..c1436c0d92 100644 --- a/runtime/doc/vimfn.txt +++ b/runtime/doc/vimfn.txt @@ -3537,7 +3537,7 @@ getcurpos([{winid}]) *getcurpos()* • {winid} (`integer?`) Return: ~ - (`any`) + (`[integer, integer, integer, integer, integer]`) getcursorcharpos([{winid}]) *getcursorcharpos()* Same as |getcurpos()| but the column number in the returned @@ -3846,7 +3846,7 @@ getmatches([{win}]) *getmatches()* • {win} (`integer?`) Return: ~ - (`any`) + (`vim.fn.getmatches.ret.item[]`) getmousepos() *getmousepos()* Returns a |Dictionary| with the last known position of the @@ -3952,7 +3952,7 @@ getpos({expr}) *getpos()* • {expr} (`string`) Return: ~ - (`integer[]`) + (`[integer, integer, integer, integer]`) getqflist([{what}]) *getqflist()* Returns a |List| with all the current quickfix errors. Each @@ -4181,9 +4181,9 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()* < Parameters: ~ - • {pos1} (`table`) - • {pos2} (`table`) - • {opts} (`table?`) + • {pos1} (`[integer, integer, integer, integer]`) + • {pos2} (`[integer, integer, integer, integer]`) + • {opts} (`{type?:string, exclusive?:boolean}?`) Return: ~ (`string[]`) @@ -4221,12 +4221,13 @@ getregionpos({pos1}, {pos2} [, {opts}]) *getregionpos()* (default: |FALSE|) Parameters: ~ - • {pos1} (`table`) - • {pos2} (`table`) - • {opts} (`table?`) + • {pos1} (`[integer, integer, integer, integer]`) + • {pos2} (`[integer, integer, integer, integer]`) + • {opts} + (`{type?:string, exclusive?:boolean, eol?:boolean}?`) Return: ~ - (`integer[][][]`) + (`[ [integer, integer, integer, integer], [integer, integer, integer, integer] ][]`) getregtype([{regname}]) *getregtype()* The result is a String, which is type of register {regname}. @@ -7852,7 +7853,7 @@ readfile({fname} [, {type} [, {max}]]) *readfile()* • {max} (`integer?`) Return: ~ - (`any`) + (`string[]`) reduce({object}, {func} [, {initial}]) *reduce()* *E998* {func} is called for every item in {object}, which can be a @@ -9063,7 +9064,7 @@ setmatches({list} [, {win}]) *setmatches()* window ID instead of the current window. Parameters: ~ - • {list} (`any`) + • {list} (`vim.fn.getmatches.ret.item[]`) • {win} (`integer?`) Return: ~ @@ -11742,7 +11743,7 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()* • {winid} (`integer?`) Return: ~ - (`any`) + (`integer|[integer, integer]`) virtcol2col({winid}, {lnum}, {col}) *virtcol2col()* The result is a Number, which is the byte index of the diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 80892f5c60..019fab6286 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -48,7 +48,7 @@ --- @class (private) vim.tohtml.line --- @field virt_lines {[integer]:[string,integer][]} ---- @field pre_text string[][] +--- @field pre_text [string, integer?][] --- @field hide? boolean --- @field [integer] vim.tohtml.cell? (integer: (1-index, exclusive)) @@ -229,7 +229,7 @@ local function cterm_to_hex(colorstr) return colorstr end assert(colorstr ~= '') - local color = tonumber(colorstr) + local color = tonumber(colorstr) --[[@as integer]] assert(color and 0 <= color and color <= 255) if cterm_color_cache[color] then return cterm_color_cache[color] @@ -398,7 +398,7 @@ end local function styletable_syntax(state) for row = state.start, state.end_ do local prev_id = 0 - local prev_col = nil + local prev_col --- @type integer? for col = 1, #vim.fn.getline(row) + 1 do local hlid = vim.fn.synID(row, col, 1) hlid = hlid == 0 and 0 or assert(register_hl(state, hlid)) @@ -430,7 +430,7 @@ local function styletable_diff(state) break end local prev_id = 0 - local prev_col = nil + local prev_col --- @type integer? for col = 1, #vim.fn.getline(row) do local hlid = vim.fn.diff_hlID(row, col) hlid = hlid == 0 and 0 or assert(register_hl(state, hlid)) @@ -486,7 +486,7 @@ local function styletable_treesitter(state) end --- @param state vim.tohtml.state ---- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] +--- @param extmark [integer, integer, integer, vim.api.keyset.extmark_details] --- @param namespaces table local function _styletable_extmarks_highlight(state, extmark, namespaces) if not extmark[4].hl_group then @@ -548,7 +548,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 + len(i[1]) + virt_text_len = virt_text_len + len(assert(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) @@ -588,7 +588,7 @@ local function _styletable_extmarks_virt_lines(state, extmark) end --- @param state vim.tohtml.state ---- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] +--- @param extmark [integer, integer, integer, vim.api.keyset.extmark_details] local function _styletable_extmarks_conceal(state, extmark) if not extmark[4].conceal or state.opt.conceallevel == 0 then return @@ -611,6 +611,8 @@ local function styletable_extmarks(state) --TODO(altermo) extmarks may have col/row which is outside of the buffer, which could cause an error local bufnr = state.bufnr local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, -1, 0, -1, { details = true }) + --- @cast extmarks [integer,integer,integer,vim.api.keyset.extmark_details][] + local namespaces = {} --- @type table for ns, ns_id in pairs(vim.api.nvim_get_namespaces()) do namespaces[ns_id] = ns @@ -662,12 +664,12 @@ local function styletable_conceal(state) for col = 1, line_len_exclusive do --- @type integer,string,integer local is_concealed, conceal, hlid = unpack(vim.fn.synconcealed(row, col) --[[@as table]]) - if is_concealed == 0 then - assert(true) - elseif not conceals[hlid] then - conceals[hlid] = { col, math.min(col + 1, line_len_exclusive), conceal } - else - conceals[hlid][2] = math.min(col + 1, line_len_exclusive) + if is_concealed ~= 0 then + if not conceals[hlid] then + conceals[hlid] = { col, math.min(col + 1, line_len_exclusive), conceal } + else + conceals[hlid][2] = math.min(col + 1, line_len_exclusive) + end end end for _, v in pairs(conceals) do @@ -679,9 +681,7 @@ end --- @param state vim.tohtml.state local function styletable_match(state) - for _, match in - ipairs(vim.fn.getmatches(state.winid) --[[@as (table[])]]) - do + for _, match in ipairs(vim.fn.getmatches(state.winid)) do local hlid = register_hl(state, match.group) local function range(srow, scol, erow, ecol) if match.group == 'Conceal' and state.opt.conceallevel ~= 0 then @@ -692,19 +692,19 @@ local function styletable_match(state) end if match.pos1 then for key, v in - pairs(match --[[@as (table)]]) + pairs(match --[[@as table]]) do - if not key:match('^pos(%d+)$') then - assert(true) - elseif #v == 1 then - range(v[1], 1, v[1], #vim.fn.getline(v[1]) + 1) - else - range(v[1], v[2], v[1], v[3] + v[2]) + if key:match('^pos(%d+)$') then + if #v == 1 then + range(v[1], 1, v[1], #vim.fn.getline(v[1]) + 1) + else + range(v[1], v[2], v[1], v[3] + v[2]) + end end end else for _, v in - ipairs(vim.fn.matchbufline(state.bufnr, match.pattern, 1, '$') --[[@as (table[])]]) + ipairs(vim.fn.matchbufline(state.bufnr, assert(match.pattern), 1, '$') --[[@as (table[])]]) do range(v.lnum, v.byteidx + 1, v.lnum, v.byteidx + 1 + #v.text) end @@ -744,13 +744,15 @@ local function styletable_statuscolumn(state) signcolumn = 'auto' end if signcolumn ~= 'no' then - local max = tonumber(signcolumn:match('^%w-:(%d)')) or 1 + local max = tonumber(signcolumn:match('^%w-:(%d)')) --[[@as integer?]] + or 1 if signcolumn:match('^auto') then --- @type table local signcount = {} for _, extmark in ipairs(vim.api.nvim_buf_get_extmarks(state.bufnr, -1, 0, -1, { details = true })) do + --- @cast extmark [integer, integer, integer, vim.api.keyset.extmark_details] if extmark[4].sign_text then signcount[extmark[2]] = (signcount[extmark[2]] or 0) + 1 end @@ -770,7 +772,8 @@ local function styletable_statuscolumn(state) local foldcolumn = state.opt.foldcolumn if foldcolumn ~= '0' then if foldcolumn:match('^auto') then - local max = tonumber(foldcolumn:match('^%w-:(%d)')) or 1 + local max = tonumber(foldcolumn:match('^%w-:(%d)')) --[[@as integer?]] + or 1 local maxfold = 0 vim._with({ buf = state.bufnr }, function() for row = state.start, state.end_ do @@ -782,11 +785,11 @@ local function styletable_statuscolumn(state) end) minwidth = minwidth + math.min(maxfold, max) else - minwidth = minwidth + tonumber(foldcolumn) + minwidth = minwidth + tonumber(foldcolumn) --[[@as integer]] end end - --- @type table + --- @type table local statuses = {} for row = state.start, state.end_ do local status = vim.api.nvim_eval_statusline( @@ -798,15 +801,13 @@ local function styletable_statuscolumn(state) minwidth = width end table.insert(statuses, status) - --- @type string end for row, status in pairs(statuses) do - --- @type string local str = status.str - --- @type table[] local hls = status.highlights for k, v in ipairs(hls) do - local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil) + local hlsk1 = hls[k + 1] + local text = str:sub(v.start + 1, hlsk1 and hlsk1.start or nil) if k == #hls then text = text .. (' '):rep(minwidth - len(str)) end @@ -852,11 +853,9 @@ local function styletable_listchars(state) for _, match in ipairs(vim.fn.matchbufline(state.bufnr, '\t', 1, '$') --[[@as (table[])]]) do - --- @type integer - local tablen = #state.tabstop - - ((vim.fn.virtcol({ match.lnum, match.byteidx }, false, state.winid)) % #state.tabstop) - --- @type string? - local text + local vcol = vim.fn.virtcol({ match.lnum, match.byteidx }, false, state.winid) --[[@as integer]] + local tablen = #state.tabstop - (vcol % #state.tabstop) + local text --- @type string if len(listchars.tab) == 3 then if tablen == 1 then text = utf8_sub(listchars.tab, 3, 3) @@ -1142,6 +1141,7 @@ local function extend_pre(out, state) local before = '' local after = '' + --- @param row integer local function loop(row) local inside = row <= state.end_ and row >= state.start local style_line = styletable[row] @@ -1168,7 +1168,7 @@ local function extend_pre(out, state) pairs(style_line --[[@as table]]) do if type(k) == 'number' and k > true_line_len then - true_line_len = k + true_line_len = k --[[@as integer]] end end for col = 1, true_line_len do @@ -1305,7 +1305,7 @@ local function opt_to_global_state(opt, title) -- Input: "Font,Escape\,comma, Ignore space after comma" -- Output: { "Font","Escape,comma","Ignore space after comma" } local prev = '' - for name in vim.gsplit(vim.o.guifont:match('^[^:]+'), ',', { trimempty = true }) do + for name in vim.gsplit(assert(vim.o.guifont:match('^[^:]+')), ',', { trimempty = true }) do if vim.endswith(name, '\\') then prev = prev .. vim.trim(name:sub(1, -2) .. ',') elseif vim.trim(name) ~= '' then diff --git a/runtime/lua/vim/F.lua b/runtime/lua/vim/F.lua index 8eb17a4c95..681a92d35c 100644 --- a/runtime/lua/vim/F.lua +++ b/runtime/lua/vim/F.lua @@ -37,6 +37,10 @@ function F.ok_or_nil(status, ...) end -- Nil pcall. +--- @generic T +--- @param fn fun(...):T +--- @param ... T? +--- @return T function F.npcall(fn, ...) return F.ok_or_nil(pcall(fn, ...)) end diff --git a/runtime/lua/vim/_comment.lua b/runtime/lua/vim/_comment.lua index c8f7b13659..378d0e2584 100644 --- a/runtime/lua/vim/_comment.lua +++ b/runtime/lua/vim/_comment.lua @@ -3,7 +3,7 @@ ---@field right string Right part of comment --- Get 'commentstring' at cursor ----@param ref_position integer[] +---@param ref_position [integer,integer] ---@return string local function get_commentstring(ref_position) local buf_cs = vim.bo.commentstring @@ -62,7 +62,7 @@ local function get_commentstring(ref_position) end --- Compute comment parts from 'commentstring' ----@param ref_position integer[] +---@param ref_position [integer,integer] ---@return vim._comment.Parts local function get_comment_parts(ref_position) local cs = get_commentstring(ref_position) @@ -78,6 +78,7 @@ local function get_comment_parts(ref_position) -- Structure of 'commentstring': <%s> local left, right = cs:match('^(.-)%%s(.-)$') + assert(left and right) return { left = left, right = right } end @@ -112,6 +113,7 @@ local function get_lines_info(lines, parts) for _, l in ipairs(lines) do -- Update lines indent: minimum of all indents except blank lines local _, indent_width_cur, indent_cur = l:find('^(%s*)') + assert(indent_width_cur and indent_cur) -- Ignore blank lines completely when making a decision if indent_width_cur < l:len() then @@ -188,7 +190,7 @@ end --- Comment/uncomment buffer range ---@param line_start integer ---@param line_end integer ----@param ref_position? integer[] +---@param ref_position? [integer, integer] local function toggle_lines(line_start, line_end, ref_position) ref_position = ref_position or { line_start, 0 } local parts = get_comment_parts(ref_position) diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 52fdfd0aef..7d17c928c3 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -26,7 +26,7 @@ do end, { desc = 'Edit treesitter query', nargs = '?' }) vim.api.nvim_create_user_command('Open', function(cmd) - vim.ui.open(cmd.fargs[1]) + vim.ui.open(assert(cmd.fargs[1])) end, { desc = 'Open file with system default handler. See :help vim.ui.open()', nargs = 1, @@ -253,11 +253,11 @@ do 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 }) + vim.diagnostic.jump({ count = vim._maxint, 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 }) + vim.diagnostic.jump({ count = -vim._maxint, wrap = false }) end, { desc = 'Jump to the first diagnostic in the current buffer' }) vim.keymap.set('n', 'd', function() @@ -466,8 +466,8 @@ do amenu disable PopUp.Configure\ Diagnostics ]]) - local urls = require('vim.ui')._get_urls() - if vim.startswith(urls[1], 'http') then + local url = require('vim.ui')._get_urls()[1] + if url and vim.startswith(url, 'http') then vim.cmd([[amenu enable PopUp.Open\ in\ web\ browser]]) elseif vim.lsp.get_clients({ bufnr = 0 })[1] then vim.cmd([[anoremenu enable PopUp.Go\ to\ definition]]) @@ -595,7 +595,7 @@ do { limit = math.abs(count) } ) if #extmarks > 0 then - local extmark = extmarks[math.min(#extmarks, math.abs(count))] + local extmark = assert(extmarks[math.min(#extmarks, math.abs(count))]) vim.api.nvim_win_set_cursor(win, { extmark[2] + 1, extmark[3] }) end end @@ -733,7 +733,7 @@ do return nil end - local max = tonumber(string.rep('f', #c), 16) + local max = assert(tonumber(string.rep('f', #c), 16)) return val / max end @@ -876,7 +876,7 @@ do end -- The returned SGR sequence should begin with 48:2 - local sgr = attrs[#attrs]:match('^48:2:([%d:]+)$') + local sgr = assert(attrs[#attrs]):match('^48:2:([%d:]+)$') if not sgr then return false end @@ -938,13 +938,13 @@ do upward = true, limit = math.huge, -- exrc in cwd already handled from C, thus start in parent directory. - path = vim.fs.dirname(vim.uv.cwd()), + path = vim.fs.dirname((vim.uv.cwd())), }) for _, file in ipairs(files) do local trusted = vim.secure.read(file) --[[@as string|nil]] if trusted then if vim.endswith(file, '.lua') then - loadstring(trusted)() + assert(loadstring(trusted))() else vim.api.nvim_exec2(trusted, {}) end diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua index d0bb91114e..21e97c65fe 100644 --- a/runtime/lua/vim/_init_packages.lua +++ b/runtime/lua/vim/_init_packages.lua @@ -86,7 +86,7 @@ setmetatable(vim, { }) --- ----@private +---@nodoc --- TODO: should be in vim.shared when vim.shared always uses nvim-lua --- @diagnostic disable-next-line:duplicate-set-field function vim.empty_dict() diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 01f5d08562..a86d52e620 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1135,7 +1135,7 @@ function vim.api.nvim_eval(expr) end --- - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} --- is ignored. Mutually exclusive with {use_winbar}. --- - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline. ---- @return table # Dict containing statusline information, with these keys: +--- @return vim.api.keyset.eval_statusline_ret # Dict containing statusline information, with these keys: --- - str: (string) Characters that will be displayed on the statusline. --- - width: (number) Display width of the statusline. --- - highlights: Array containing highlight information of the statusline. Only included when @@ -2538,7 +2538,7 @@ function vim.api.nvim_win_set_width(window, width) end --- to find out how many buffer lines beyond "start_row" take --- up a certain number of logical lines (returned in --- "end_row" and "end_vcol"). ---- @return table # Dict containing text height information, with these keys: +--- @return vim.api.keyset.win_text_height_ret # Dict containing text height information, with these keys: --- - all: The total number of screen lines occupied by the range. --- - fill: The number of diff filler or virtual lines among them. --- - end_row: The row on which the returned height is reached (first row of diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index fbef6fa3bc..ed93345a2b 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -20,7 +20,7 @@ error('Cannot require a meta file') --- @field hl_group? string --- @field hl_eol? boolean --- ---- @field conceal? boolean +--- @field conceal? string --- @field spell? boolean --- @field ui_watched? boolean --- @field url? string @@ -246,3 +246,19 @@ error('Cannot require a meta file') --- @field range? integer[] --- @field count? integer --- @field reg? string + +--- @class vim.api.keyset.eval_statusline_ret.highlight +--- @field start integer +--- @field group string +--- @field groups string[] + +--- @class vim.api.keyset.eval_statusline_ret +--- @field str string +--- @field width integer +--- @field highlights vim.api.keyset.eval_statusline_ret.highlight[] + +--- @class vim.api.keyset.win_text_height_ret +--- @field all integer +--- @field fill integer +--- @field end_row integer +--- @field end_vcol integer diff --git a/runtime/lua/vim/_meta/base64.lua b/runtime/lua/vim/_meta/base64.lua index 8ba59e1703..895ac3334b 100644 --- a/runtime/lua/vim/_meta/base64.lua +++ b/runtime/lua/vim/_meta/base64.lua @@ -1,5 +1,7 @@ --- @meta +vim.base64 = {} + --- Encode {str} using Base64. --- --- @param str string String to encode diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua index 6886cd6bb7..9c8f2ef603 100644 --- a/runtime/lua/vim/_meta/builtin_types.lua +++ b/runtime/lua/vim/_meta/builtin_types.lua @@ -39,6 +39,14 @@ --- @field pos [integer, integer, integer, integer] --- @field file string +--- @class vim.fn.getmatches.ret.item +--- @field id integer +--- @field group string +--- @field pattern? string +--- @field priority integer +--- @field conceal? string +--- @field [string] [integer, integer, integer] all strings of format 'pos%d' + --- @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 2d38a5585e..baffe928b0 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3175,7 +3175,7 @@ function vim.fn.getcompletion(pat, type, filtered) end --- |winrestview()| for restoring more state. --- --- @param winid? integer ---- @return any +--- @return [integer, integer, integer, integer, integer] function vim.fn.getcurpos(winid) end --- Same as |getcurpos()| but the column number in the returned @@ -3450,7 +3450,7 @@ function vim.fn.getmarklist(buf) end --- < --- --- @param win? integer ---- @return any +--- @return vim.fn.getmatches.ret.item[] function vim.fn.getmatches(win) end --- Returns a |Dictionary| with the last known position of the @@ -3551,7 +3551,7 @@ function vim.fn.getpid() end --- Also see |getcharpos()|, |getcurpos()| and |setpos()|. --- --- @param expr string ---- @return integer[] +--- @return [integer, integer, integer, integer] function vim.fn.getpos(expr) end --- Returns a |List| with all the current quickfix errors. Each @@ -3776,9 +3776,9 @@ function vim.fn.getreginfo(regname) end --- \ getpos('v'), getpos('.'), #{ type: mode() }) --- < --- ---- @param pos1 table ---- @param pos2 table ---- @param opts? table +--- @param pos1 [integer, integer, integer, integer] +--- @param pos2 [integer, integer, integer, integer] +--- @param opts? {type?:string, exclusive?:boolean} --- @return string[] function vim.fn.getregion(pos1, pos2, opts) end @@ -3813,10 +3813,10 @@ function vim.fn.getregion(pos1, pos2, opts) end --- value of 0 is used for both positions. --- (default: |FALSE|) --- ---- @param pos1 table ---- @param pos2 table ---- @param opts? table ---- @return integer[][][] +--- @param pos1 [integer, integer, integer, integer] +--- @param pos2 [integer, integer, integer, integer] +--- @param opts? {type?:string, exclusive?:boolean, eol?:boolean} +--- @return [ [integer, integer, integer, integer], [integer, integer, integer, integer] ][] function vim.fn.getregionpos(pos1, pos2, opts) end --- The result is a String, which is type of register {regname}. @@ -7133,7 +7133,7 @@ function vim.fn.readdir(directory, expr) end --- @param fname string --- @param type? string --- @param max? integer ---- @return any +--- @return string[] function vim.fn.readfile(fname, type, max) end --- {func} is called for every item in {object}, which can be a @@ -8256,7 +8256,7 @@ function vim.fn.setloclist(nr, list, action, what) end --- If {win} is specified, use the window with this number or --- window ID instead of the current window. --- ---- @param list any +--- @param list vim.fn.getmatches.ret.item[] --- @param win? integer --- @return any function vim.fn.setmatches(list, win) end @@ -10693,7 +10693,7 @@ function vim.fn.values(dict) end --- @param expr string|any[] --- @param list? boolean --- @param winid? integer ---- @return any +--- @return integer|[integer, integer] function vim.fn.virtcol(expr, list, winid) end --- The result is a Number, which is the byte index of the diff --git a/runtime/lua/vim/_system.lua b/runtime/lua/vim/_system.lua index e40229de63..23a32fbd49 100644 --- a/runtime/lua/vim/_system.lua +++ b/runtime/lua/vim/_system.lua @@ -79,22 +79,19 @@ function SystemObj:_timeout(signal) self:kill(signal or SIG.TERM) end --- Use max 32-bit signed int value to avoid overflow on 32-bit systems. #31633 -local MAX_TIMEOUT = 2 ^ 31 - 1 - --- @param timeout? integer --- @return vim.SystemCompleted function SystemObj:wait(timeout) local state = self._state - local done = vim.wait(timeout or state.timeout or MAX_TIMEOUT, function() + local done = vim.wait(timeout or state.timeout or vim._maxint, function() return state.result ~= nil end, nil, true) if not done then -- Send sigkill since this cannot be caught self:_timeout(SIG.KILL) - vim.wait(timeout or state.timeout or MAX_TIMEOUT, function() + vim.wait(timeout or state.timeout or vim._maxint, function() return state.result ~= nil end, nil, true) end diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index e01b1f2daa..1d395e8c8f 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -16,29 +16,28 @@ local function get_qf_id_for_title(title) return nil end ---- [diagnostic-structure]() ---- --- Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based --- rows and columns). |api-indexing| ---- @class vim.Diagnostic ---- ---- Buffer number ---- @field bufnr integer +--- @class vim.Diagnostic.Set --- --- The starting line of the diagnostic (0-indexed) --- @field lnum integer --- ---- The final line of the diagnostic (0-indexed) ---- @field end_lnum integer ---- --- The starting column of the diagnostic (0-indexed) ---- @field col integer +--- (default: `0`) +--- @field col? integer +--- +--- The final line of the diagnostic (0-indexed) +--- (default: `lnum`) +--- @field end_lnum? integer --- --- The final column of the diagnostic (0-indexed) ---- @field end_col integer +--- (default: `col`) +--- @field end_col? integer --- --- The severity of the diagnostic |vim.diagnostic.severity| ---- @field severity vim.diagnostic.Severity +--- (default: `vim.diagnostic.severity.ERROR`) +--- @field severity? vim.diagnostic.Severity --- --- The diagnostic text --- @field message string @@ -53,32 +52,18 @@ end --- --- Arbitrary data plugins or users can add --- @field user_data? any arbitrary data plugins can add ---- ---- @field namespace? integer ---- @class vim.Diagnostic.Set : vim.Diagnostic +--- [diagnostic-structure]() --- ---- Do not set. Will be overridden by `vim.diagnostic.set()`. ---- @field bufnr nil ---- ---- Do not set. Will be overridden by `vim.diagnostic.set()`. ---- @field namespace nil ---- ---- The starting column of the diagnostic in bytes (0-indexed) ---- (default: `0`) ---- @field col? integer ---- ---- The final line of the diagnostic (0-indexed) ---- (default: same as `lnum`) ---- @field end_lnum? integer ---- ---- The final column of the diagnostic (0-indexed) ---- (default: same as `col`) ---- @field end_col? integer ---- ---- The severity of the diagnostic |vim.diagnostic.severity| ---- (default: `vim.diagnostic.severity.ERROR`) ---- @field severity? vim.diagnostic.Severity +--- Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based +--- rows and columns). |api-indexing| +--- @class vim.Diagnostic : vim.Diagnostic.Set +--- @field bufnr integer Buffer number +--- @field end_lnum integer The final line of the diagnostic (0-indexed) +--- @field col integer The starting column of the diagnostic (0-indexed) +--- @field end_col integer The final column of the diagnostic (0-indexed) +--- @field severity vim.diagnostic.Severity The severity of the diagnostic |vim.diagnostic.severity| +--- @field namespace? integer --- Many of the configuration options below accept one of the following: --- - `false`: Disable this feature diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 276691b080..05f2689813 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -40,7 +40,6 @@ local function starsetf(ft, priority) } end ----@private --- Get a line range from the buffer. ---@param bufnr integer The buffer to get the lines from ---@param start_lnum integer|nil The line number of the first line (inclusive, 1-based) @@ -55,7 +54,6 @@ function M._getlines(bufnr, start_lnum, end_lnum) return api.nvim_buf_get_lines(bufnr, 0, -1, false) end ----@private --- Get a single line from the buffer. ---@param bufnr integer The buffer to get the lines from ---@param start_lnum integer The line number of the first line (inclusive, 1-based) @@ -65,7 +63,6 @@ function M._getline(bufnr, start_lnum) return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or '' end ----@private --- Check whether a string matches any of the given Lua patterns. --- ---@param s string? The string to check @@ -83,7 +80,6 @@ function M._findany(s, patterns) return false end ----@private --- Get the next non-whitespace line in the buffer. --- ---@param bufnr integer The buffer to get the line from @@ -102,7 +98,6 @@ do --- @type table local regex_cache = {} - ---@private --- Check whether the given string matches the Vim regex pattern. --- @param s string? --- @param pattern string @@ -215,7 +210,7 @@ local extension = { art = 'art', asciidoc = 'asciidoc', adoc = 'asciidoc', - asa = function(path, bufnr) + asa = function(_path, _bufnr) if vim.g.filetype_asa then return vim.g.filetype_asa end @@ -266,7 +261,7 @@ local extension = { bsd = 'bsdl', bsdl = 'bsdl', bst = 'bst', - btm = function(path, bufnr) + btm = function(_path, _bufnr) return (vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0) and 'dosbatch' or 'btm' end, @@ -319,7 +314,7 @@ local extension = { atg = 'coco', recipe = 'conaryrecipe', ctags = 'conf', - hook = function(path, bufnr) + hook = function(_path, bufnr) return M._getline(bufnr, 1) == '[Trigger]' and 'confini' or nil end, nmconnection = 'confini', @@ -735,7 +730,7 @@ local extension = { at = 'm4', mc = detect.mc, quake = 'm3quake', - m4 = function(path, bufnr) + m4 = function(path, _bufnr) local pathl = path:lower() return not (pathl:find('html%.m4$') or pathl:find('fvwm2rc')) and 'm4' or nil end, @@ -1783,12 +1778,12 @@ local filename = { ['/etc/pinforc'] = 'pinfo', ['/.pinforc'] = 'pinfo', ['.povrayrc'] = 'povini', - printcap = function(path, bufnr) + printcap = function(_path, _bufnr) return 'ptcap', function(b) vim.b[b].ptcap_type = 'print' end end, - termcap = function(path, bufnr) + termcap = function(_path, _bufnr) return 'ptcap', function(b) vim.b[b].ptcap_type = 'term' end @@ -2029,7 +2024,7 @@ local pattern = { ['/etc/modprobe%.'] = starsetf('modconf'), ['/etc/modules%.conf$'] = 'modconf', ['/etc/modules$'] = 'modconf', - ['/etc/modutils/'] = starsetf(function(path, bufnr) + ['/etc/modutils/'] = starsetf(function(path, _bufnr) if fn.executable(fn.expand(path)) ~= 1 then return 'modconf' end @@ -2508,17 +2503,17 @@ local pattern = { ['/octave/history$'] = 'octave', ['%.opam%.locked$'] = 'opam', ['%.opam%.template$'] = 'opam', - ['^pacman%.log'] = starsetf(function(path, bufnr) + ['^pacman%.log'] = starsetf(function(path, _bufnr) return vim.uv.fs_stat(path) and 'pacmanlog' or nil end), - ['printcap'] = starsetf(function(path, bufnr) + ['printcap'] = starsetf(function(_path, _bufnr) return require('vim.filetype.detect').printcap('print') end), ['/queries/.*%.scm$'] = 'query', -- treesitter queries (Neovim only) [',v$'] = 'rcs', ['^svn%-commit.*%.tmp$'] = 'svn', ['%.swift%.gyb$'] = 'swiftgyb', - ['termcap'] = starsetf(function(path, bufnr) + ['termcap'] = starsetf(function(_path, _bufnr) return require('vim.filetype.detect').printcap('term') end), ['%.t%.html$'] = 'tilde', @@ -2928,49 +2923,54 @@ function M.match(args) name = api.nvim_buf_get_name(bufnr) end - --- @type string?, fun(b: integer)? - local ft, on_detect - if name then name = normalize_path(name) - -- First check for the simple case where the full path exists as a key local path = abspath(name) - ft, on_detect = dispatch(filename[path], path, bufnr) - if ft then - return ft, on_detect + do -- First check for the simple case where the full path exists as a key + local ft, on_detect = dispatch(filename[path], path, bufnr) + if ft then + return ft, on_detect + end end - -- Next check against just the file name local tail = fn.fnamemodify(name, ':t') - ft, on_detect = dispatch(filename[tail], path, bufnr) - if ft then - return ft, on_detect + + do -- Next check against just the file name + local ft, on_detect = dispatch(filename[tail], path, bufnr) + if ft then + return ft, on_detect + end end -- Next, check the file path against available patterns with non-negative priority -- 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 + do + local ft, on_detect = + match_pattern_sorted(name, path, tail, pattern_sorted_pos, parent_matches, bufnr) + if ft then + return ft, on_detect + end end -- Next, check file extension -- Don't use fnamemodify() with :e modifier here, -- as that's empty when there is only an extension. - local ext = name:match('%.([^.]-)$') or '' - ft, on_detect = dispatch(extension[ext], path, bufnr) - if ft then - return ft, on_detect + do + local ext = name:match('%.([^.]-)$') or '' + local ft, on_detect = dispatch(extension[ext], path, bufnr) + if ft then + return ft, on_detect + end end - -- Next, check patterns with negative priority - ft, on_detect = - match_pattern_sorted(name, path, tail, pattern_sorted_neg, parent_matches, bufnr) - if ft then - return ft, on_detect + do -- Next, check patterns with negative priority + local ft, on_detect = + match_pattern_sorted(name, path, tail, pattern_sorted_neg, parent_matches, bufnr) + if ft then + return ft, on_detect + end end end @@ -2992,8 +2992,7 @@ function M.match(args) -- 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( + local ok, ft, on_detect = pcall( require('vim.filetype.detect').match_contents, contents, name, diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index c78945ef04..45244af64c 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -1013,7 +1013,7 @@ local function m4(contents) return 'm4' end end - if vim.env.TERM == 'amiga' and findany(contents[1]:lower(), { '^;', '^%.bra' }) then + if vim.env.TERM == 'amiga' and findany(assert(contents[1]):lower(), { '^;', '^%.bra' }) then -- AmigaDos scripts return 'amiga' end @@ -1429,10 +1429,10 @@ function M.rules(path) return 'javascript' else local ok, config_lines = pcall(fn.readfile, '/etc/udev/udev.conf') - --- @cast config_lines +string[] if not ok then return 'hog' end + --- @cast config_lines -string local dir = fn.fnamemodify(path, ':h') for _, line in ipairs(config_lines) do local match = line:match(udev_rules_pattern) @@ -1678,7 +1678,7 @@ end --- @type vim.filetype.mapfn function M.tex(path, bufnr) local matched, _, format = getline(bufnr, 1):find('^%%&%s*(%a+)') - if matched then + if matched and format then --- @type string format = format:lower():gsub('pdf', '', 1) elseif path:lower():find('tex/context/.*/.*%.tex') then @@ -1954,7 +1954,7 @@ local patterns_hashbang = { --- @return string? --- @return fun(b: integer)? local function match_from_hashbang(contents, path, dispatch_extension) - local first_line = contents[1] + local first_line = assert(contents[1]) -- Check for a line like "#!/usr/bin/env {options} bash". Turn it into -- "#!/usr/bin/bash" to make matching easier. -- Recognize only a few {options} that are commonly used. @@ -2012,6 +2012,13 @@ local function match_from_hashbang(contents, path, dispatch_extension) return dispatch_extension(name) end +--- @class vim.filetype.detect.PatternOpts +--- @field vim_regex? true? use Vim regexes instead of Lua patterns. +--- @field start_lnum? integer? Start line number for matching, defaults to 1. +--- @field end_lnum? integer? End line number for matching, defaults to -1 (last line). +--- @field ignore_case? true ignore case when matching. + +-- TODO(lewis6991): split this table into two tables, one for patterns and one for functions. local patterns_text = { ['^#compdef\\>'] = { 'zsh', { vim_regex = true } }, ['^#autoload\\>'] = { 'zsh', { vim_regex = true } }, @@ -2144,7 +2151,7 @@ local patterns_text = { --- @return string? --- @return fun(b: integer)? local function match_from_text(contents, path) - if contents[1]:find('^:$') then + if assert(contents[1]):find('^:$') then -- Bourne-like shell scripts: sh ksh bash bash2 return sh(path, contents) elseif @@ -2160,7 +2167,7 @@ local function match_from_text(contents, path) for k, v in pairs(patterns_text) do if type(v) == 'string' then -- Check the first line only - if contents[1]:find(k) then + if assert(contents[1]):find(k) then return v end elseif type(v) == 'function' then @@ -2172,22 +2179,25 @@ local function match_from_text(contents, path) else --- @cast k string local opts = type(v) == 'table' and v[2] or {} + --- @cast opts vim.filetype.detect.PatternOpts if opts.start_lnum and opts.end_lnum then assert( not opts.ignore_case, 'ignore_case=true is ignored when start_lnum is also present, needs refactor' ) for i = opts.start_lnum, opts.end_lnum do - if not contents[i] then + local line = contents[i] + if not line then break - elseif contents[i]:find(k) then + elseif line:find(k) then return v[1] end end else local line_nr = opts.start_lnum == -1 and #contents or opts.start_lnum or 1 - if contents[line_nr] then - local line = opts.ignore_case and contents[line_nr]:lower() or contents[line_nr] + local contents_line_nr = contents[line_nr] + if contents_line_nr then + local line = opts.ignore_case and contents_line_nr:lower() or contents_line_nr if opts.vim_regex and matchregex(line, k) or line:find(k) then return v[1] end @@ -2204,7 +2214,7 @@ end --- @return string? --- @return fun(b: integer)? function M.match_contents(contents, path, dispatch_extension) - local first_line = contents[1] + local first_line = assert(contents[1]) if first_line:find('^#!') then return match_from_hashbang(contents, path, dispatch_extension) else diff --git a/runtime/lua/vim/filetype/options.lua b/runtime/lua/vim/filetype/options.lua index 2a28b5a8e3..4a396a1b60 100644 --- a/runtime/lua/vim/filetype/options.lua +++ b/runtime/lua/vim/filetype/options.lua @@ -70,7 +70,7 @@ local function update_ft_option_cache(filetype) end end ---- @private +--- @nodoc --- @param filetype string Filetype --- @param option string Option name --- @return string|integer|boolean diff --git a/runtime/lua/vim/hl.lua b/runtime/lua/vim/hl.lua index 50345d1dc7..d486984b7c 100644 --- a/runtime/lua/vim/hl.lua +++ b/runtime/lua/vim/hl.lua @@ -41,8 +41,8 @@ M.priorities = { ---@param bufnr integer Buffer number to apply highlighting to ---@param ns integer Namespace to add highlight to ---@param higroup string Highlight group to use for highlighting ----@param start integer[]|string Start of region as a (line, column) tuple or string accepted by |getpos()| ----@param finish integer[]|string End of region as a (line, column) tuple or string accepted by |getpos()| +---@param start [integer,integer]|string Start of region as a (line, column) tuple or string accepted by |getpos()| +---@param finish [integer,integer]|string End of region as a (line, column) tuple or string accepted by |getpos()| ---@param opts? vim.hl.range.Opts --- @return uv.uv_timer_t? range_timer A timer which manages how much time the --- highlight has left @@ -98,14 +98,16 @@ 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] } } + --- @type [ [integer, integer, integer, integer], [integer, integer, integer, integer]][] + region = { { assert(region[1])[1], assert(region[#region])[2] } } + local region1 = assert(region[1]) 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 + or region1[2][2] == pos1[2] and pos1[3] == v_maxcol + or region1[2][2] == pos2[2] and pos2[3] == v_maxcol then - region[1][2][2] = region[1][2][2] + 1 - region[1][2][3] = 0 + region1[2][2] = region1[2][2] + 1 + region1[2][3] = 0 end end diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua index c7158673fe..d6945f3f02 100644 --- a/runtime/lua/vim/loader.lua +++ b/runtime/lua/vim/loader.lua @@ -66,7 +66,7 @@ local indexed = {} --- @return uv.fs_stat.result? local function fs_stat_cached(path) if not fs_stat_cache then - return uv.fs_stat(path) + return (uv.fs_stat(path)) end if not fs_stat_cache[path] then diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index a3bbf24937..450452157a 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -41,7 +41,6 @@ lsp._resolve_to_request = { -- TODO improve handling of scratch buffers with LSP attached. ----@private --- Called by the client when trying to call a method that's not --- supported in any of the servers registered for the current buffer. ---@param method (vim.lsp.protocol.Method.ClientToServer) name of the method @@ -54,7 +53,6 @@ function lsp._unsupported_method(method) return msg end ----@private ---@param workspace_folders string|lsp.WorkspaceFolder[]? ---@return lsp.WorkspaceFolder[]? function lsp._get_workspace_folders(workspace_folders) @@ -78,8 +76,7 @@ local format_line_ending = { ['mac'] = '\r', } ----@private ----@param bufnr (number) +---@param bufnr integer ---@return string function lsp._buf_get_line_ending(bufnr) return format_line_ending[vim.bo[bufnr].fileformat] or '\n' @@ -110,10 +107,9 @@ lsp.client_errors = vim.tbl_extend( client_error('ON_EXIT_CALLBACK_ERROR') ) ----@private --- Returns full text of buffer {bufnr} as a string. --- ----@param bufnr (number) Buffer handle, or 0 for current. +---@param bufnr integer Buffer handle, or 0 for current. ---@return string # Buffer text as string. function lsp._buf_get_full_text(bufnr) local line_ending = lsp._buf_get_line_ending(bufnr) @@ -284,7 +280,7 @@ end --- --- Predicate which decides 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 # --- --- [lsp-root_dir()]() --- Decides the workspace root: the directory where the LSP server will base its workspaceFolders, @@ -832,7 +828,6 @@ local function is_empty_or_default(bufnr, option) return vim.startswith(scriptinfo[1].name, vim.fn.expand('$VIMRUNTIME')) end ----@private ---@param client vim.lsp.Client ---@param bufnr integer function lsp._set_defaults(client, bufnr) @@ -1101,8 +1096,8 @@ end --- Checks if a buffer is attached for a particular client. --- ----@param bufnr (integer) Buffer handle, or 0 for current ----@param client_id (integer) the client id +---@param bufnr integer Buffer handle, or 0 for current +---@param client_id integer the client id function lsp.buf_is_attached(bufnr, client_id) return lsp.get_clients({ bufnr = bufnr, id = client_id, _uninitialized = true })[1] ~= nil end @@ -1112,7 +1107,7 @@ end --- ---@param client_id integer client id --- ----@return (nil|vim.lsp.Client) client rpc object +---@return vim.lsp.Client? client rpc object function lsp.get_client_by_id(client_id) return all_clients[client_id] end @@ -1207,7 +1202,6 @@ function lsp.get_clients(filter) return clients end ----@private ---@deprecated function lsp.get_active_clients(filter) vim.deprecate('vim.lsp.get_active_clients()', 'vim.lsp.get_clients()', '0.12') @@ -1263,7 +1257,7 @@ api.nvim_create_autocmd('VimLeavePre', { end, }) ----@private +---@nodoc --- Sends an async request for all active clients attached to the --- buffer. --- @@ -1401,9 +1395,9 @@ end --- ---@since 7 --- ----@param bufnr (integer|nil) The number of the buffer ----@param method (vim.lsp.protocol.Method.ClientToServer.Notification) Name of the request method ----@param params (any) Arguments to send to the server +---@param bufnr integer? The number of the buffer +---@param method vim.lsp.protocol.Method.ClientToServer.Notification Name of the request method +---@param params any Arguments to send to the server --- ---@return boolean success true if any client returns true; false otherwise function lsp.buf_notify(bufnr, method, params) @@ -1573,7 +1567,7 @@ end ---@deprecated Use |vim.lsp.get_client_by_id()| instead. ---Checks whether a client is stopped. --- ----@param client_id (integer) +---@param client_id integer ---@return boolean stopped true if client is stopped, false otherwise. function lsp.client_is_stopped(client_id) vim.deprecate('vim.lsp.client_is_stopped()', 'vim.lsp.get_client_by_id()', '0.14') @@ -1584,7 +1578,7 @@ end --- Gets a map of client_id:client pairs for the given buffer, where each value --- is a |vim.lsp.Client| object. --- ----@param bufnr (integer|nil): Buffer handle, or 0 for current +---@param bufnr integer? Buffer handle, or 0 for current ---@return table result is table of (client_id, client) pairs ---@deprecated Use |vim.lsp.get_clients()| instead. function lsp.buf_get_clients(bufnr) @@ -1630,7 +1624,7 @@ function lsp.get_log_path() return log.get_filename() end ----@private +---@nodoc --- Invokes a function for each LSP client attached to a buffer. --- ---@param bufnr integer Buffer number diff --git a/runtime/lua/vim/lsp/_tagfunc.lua b/runtime/lua/vim/lsp/_tagfunc.lua index 554f0cb991..3122eeee2e 100644 --- a/runtime/lua/vim/lsp/_tagfunc.lua +++ b/runtime/lua/vim/lsp/_tagfunc.lua @@ -6,7 +6,7 @@ local ms = lsp.protocol.Methods ---@param name string ---@param range lsp.Range ---@param uri string ----@param position_encoding string +---@param position_encoding 'utf-8'|'utf-16'|'utf-32' ---@return {name: string, filename: string, cmd: string, kind?: string} local function mk_tag_item(name, range, uri, position_encoding) local bufnr = vim.uri_to_bufnr(uri) @@ -32,7 +32,7 @@ local function query_definition(pattern) --- @param range lsp.Range --- @param uri string - --- @param position_encoding string + ---@param position_encoding 'utf-8'|'utf-16'|'utf-32' local add = function(range, uri, position_encoding) table.insert(results, mk_tag_item(pattern, range, uri, position_encoding)) end diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index aac9965f42..ca70789506 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -545,7 +545,7 @@ function M.format(opts) end local passed_multiple_ranges = (range and #range ~= 0 and type(range[1]) == 'table') - local method ---@type string + local method ---@type vim.lsp.protocol.Method.ClientToServer if passed_multiple_ranges then method = ms.textDocument_rangesFormatting elseif range then @@ -579,10 +579,11 @@ function M.format(opts) local ret = params --[[@as lsp.DocumentFormattingParams|lsp.DocumentRangeFormattingParams|lsp.DocumentRangesFormattingParams]] if passed_multiple_ranges then + --- @cast range {start:[integer,integer],end:[integer, integer]}[] ret = params --[[@as lsp.DocumentRangesFormattingParams]] - --- @cast range {start:[integer,integer],end:[integer, integer]} ret.ranges = vim.tbl_map(to_lsp_range, range) elseif range then + --- @cast range {start:[integer,integer],end:[integer, integer]} ret = params --[[@as lsp.DocumentRangeFormattingParams]] ret.range = to_lsp_range(range) end @@ -660,7 +661,7 @@ function M.rename(new_name, opts) local cword = vim.fn.expand('') --- @param range lsp.Range - --- @param position_encoding string + --- @param position_encoding 'utf-8'|'utf-16'|'utf-32' local function get_text_at_range(range, position_encoding) return api.nvim_buf_get_text( bufnr, @@ -1199,7 +1200,7 @@ local function on_code_action_results(results, opts) return title end - local source = lsp.get_client_by_id(item.ctx.client_id).name + local source = assert(lsp.get_client_by_id(item.ctx.client_id)).name return ('%s [%s]'):format(title, source) end diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 00fece8985..47b6e5c145 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -176,7 +176,7 @@ local validate = vim.validate --- @field name string --- --- See [vim.lsp.ClientConfig]. ---- @field offset_encoding string +--- @field offset_encoding 'utf-8'|'utf-16'|'utf-32' --- --- A ring buffer (|vim.ringbuf()|) containing progress messages --- sent by the server. @@ -440,16 +440,16 @@ function Client.create(config) --- @type vim.lsp.rpc.Dispatchers local dispatchers = { notification = function(...) - return self:_notification(...) + self:_notification(...) end, server_request = function(...) return self:_server_request(...) end, on_error = function(...) - return self:_on_error(...) + self:_on_error(...) end, on_exit = function(...) - return self:_on_exit(...) + self:_on_exit(...) end, } @@ -597,7 +597,7 @@ end --- @private --- @param id integer ---- @param req_type 'pending'|'complete'|'cancel'| +--- @param req_type 'pending'|'complete'|'cancel' --- @param bufnr? integer (only required for req_type='pending') --- @param method? string (only required for req_type='pending') function Client:_process_request(id, req_type, bufnr, method) diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index e36d8fee27..02da7fc367 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -258,20 +258,22 @@ end ---@param result lsp.CodeLens[] ---@param ctx lsp.HandlerContext function M.on_codelens(err, result, ctx) + local bufnr = assert(ctx.bufnr) + if err then - active_refreshes[assert(ctx.bufnr)] = nil + active_refreshes[bufnr] = nil log.error('codelens', err) return end - M.save(result, ctx.bufnr, ctx.client_id) + M.save(result, bufnr, ctx.client_id) -- Eager display for any resolved (and unresolved) lenses and refresh them -- once resolved. - M.display(result, ctx.bufnr, ctx.client_id) - resolve_lenses(result, ctx.bufnr, ctx.client_id, function() - active_refreshes[assert(ctx.bufnr)] = nil - M.display(result, ctx.bufnr, ctx.client_id) + M.display(result, bufnr, ctx.client_id) + resolve_lenses(result, bufnr, ctx.client_id, function() + active_refreshes[bufnr] = nil + M.display(result, bufnr, ctx.client_id) end) end diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 60574a94cd..ac8099de1b 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -38,7 +38,7 @@ local lsp = vim.lsp local protocol = lsp.protocol local ms = protocol.Methods -local rtt_ms = 50 +local rtt_ms = 50.0 local ns_to_ms = 0.000001 --- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] @@ -92,7 +92,7 @@ local completion_timer = nil --- @return uv.uv_timer_t local function new_timer() - return assert(vim.uv.new_timer()) + return (assert(vim.uv.new_timer())) end local function reset_timer() @@ -110,7 +110,7 @@ end local function exp_avg(window, warmup) local count = 0 local sum = 0 - local value = 0 + local value = 0.0 return function(sample) if count < warmup then @@ -278,7 +278,6 @@ 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 @@ -365,7 +364,7 @@ end --- @param lnum integer 0-indexed --- @param line string --- @param items lsp.CompletionItem[] ---- @param encoding string +--- @param encoding 'utf-8'|'utf-16'|'utf-32' --- @return integer? local function adjust_start_col(lnum, line, items, encoding) local min_start_char = nil @@ -384,7 +383,6 @@ local function adjust_start_col(lnum, line, items, encoding) end end ---- @private --- @param line string line content --- @param lnum integer 0-indexed line number --- @param cursor_col integer @@ -392,7 +390,7 @@ end --- @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 +--- @param encoding 'utf-8'|'utf-16'|'utf-32' --- @return table[] matches --- @return integer? server_start_boundary function M._convert_results( @@ -487,7 +485,7 @@ local function trigger(bufnr, clients, ctx) 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() + local start_time = vim.uv.hrtime() --[[@as integer]] Context.last_request_time = start_time local cancel_request = request(clients, bufnr, win, ctx, function(responses) @@ -557,7 +555,7 @@ local function on_insert_char_pre(handle) else completion_timer = new_timer() completion_timer:start( - debounce_ms, + math.floor(debounce_ms), 0, vim.schedule_wrap(function() M.get({ ctx = ctx }) diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1ea0123b1b..bdddb704a5 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -11,25 +11,28 @@ local augroup = api.nvim_create_augroup('nvim.lsp.diagnostic', {}) ---@class (private) vim.lsp.diagnostic.BufState ---@field enabled boolean Whether diagnostics are enabled for this buffer ---@field client_result_id table Latest responded `resultId` ----@type table + +---@type table local bufstates = {} local DEFAULT_CLIENT_ID = -1 ---@param severity lsp.DiagnosticSeverity +---@return vim.diagnostic.Severity local function severity_lsp_to_vim(severity) if type(severity) == 'string' then - severity = protocol.DiagnosticSeverity[severity] --- @type integer + return protocol.DiagnosticSeverity[severity] --[[@as vim.diagnostic.Severity]] end return severity end +---@param severity vim.diagnostic.Severity|vim.diagnostic.SeverityName ---@return lsp.DiagnosticSeverity local function severity_vim_to_lsp(severity) if type(severity) == 'string' then - severity = vim.diagnostic.severity[severity] --- @type integer + return vim.diagnostic.severity[severity] end - return severity + return severity --[[@as lsp.DiagnosticSeverity]] end ---@param bufnr integer @@ -186,10 +189,9 @@ function M.get_namespace(client_id, is_pull) local client = vim.lsp.get_client_by_id(client_id) if is_pull then local server_id = - vim.tbl_get((client or {}).server_capabilities, 'diagnosticProvider', 'identifier') - local key = string.format('%d:%s', client_id, server_id or 'nil') - local name = string.format( - 'nvim.lsp.%s.%d.%s', + vim.tbl_get((client or {}).server_capabilities or {}, 'diagnosticProvider', 'identifier') + local key = ('%d:%s'):format(client_id, server_id or 'nil') + local name = ('nvim.lsp.%s.%d.%s'):format( client and client.name or 'unknown', client_id, server_id or 'nil' @@ -200,15 +202,15 @@ function M.get_namespace(client_id, is_pull) _client_pull_namespaces[key] = ns end return ns - else - local name = string.format('nvim.lsp.%s.%d', client and client.name or 'unknown', client_id) - local ns = _client_push_namespaces[client_id] - if not ns then - ns = api.nvim_create_namespace(name) - _client_push_namespaces[client_id] = ns - end - return ns end + + local ns = _client_push_namespaces[client_id] + if not ns then + local name = ('nvim.lsp.%s.%d'):format(client and client.name or 'unknown', client_id) + ns = api.nvim_create_namespace(name) + _client_push_namespaces[client_id] = ns + end + return ns end --- @param uri string @@ -227,9 +229,7 @@ local function handle_diagnostics(uri, client_id, diagnostics, is_pull) return end - if client_id == nil then - client_id = DEFAULT_CLIENT_ID - end + client_id = client_id or DEFAULT_CLIENT_ID local namespace = M.get_namespace(client_id, is_pull) @@ -380,7 +380,6 @@ end --- Enable pull diagnostics for a buffer ---@param bufnr (integer) Buffer handle, or 0 for current ----@private function M._enable(bufnr) bufnr = vim._resolve_bufnr(bufnr) diff --git a/runtime/lua/vim/lsp/document_color.lua b/runtime/lua/vim/lsp/document_color.lua index 039b8debff..f721f1536d 100644 --- a/runtime/lua/vim/lsp/document_color.lua +++ b/runtime/lua/vim/lsp/document_color.lua @@ -40,7 +40,13 @@ local document_color_opts = { style = 'background' } --- @param color string local function get_contrast_color(color) local r_s, g_s, b_s = color:match('^#(%x%x)(%x%x)(%x%x)$') + if not (r_s and g_s and b_s) then + error('Invalid color format: ' .. color) + end local r, g, b = tonumber(r_s, 16), tonumber(g_s, 16), tonumber(b_s, 16) + if not (r and g and b) then + error('Invalid color format: ' .. color) + end -- Source: https://www.w3.org/TR/WCAG21/#dfn-relative-luminance -- Using power 2.2 is a close approximation to full piecewise transform @@ -185,7 +191,7 @@ local function buf_enable(bufnr) api.nvim_buf_attach(bufnr, false, { on_reload = function(_, buf) buf_clear(buf) - if bufstates[buf].enabled then + if assert(bufstates[buf]).enabled then M._buf_refresh(buf) end end, @@ -203,7 +209,7 @@ local function buf_enable(bufnr) if (method == ms.textDocument_didChange or method == ms.textDocument_didOpen) - and bufstates[args.buf].enabled + and assert(bufstates[args.buf]).enabled then M._buf_refresh(args.buf, args.data.client_id) end @@ -254,7 +260,7 @@ function M.is_enabled(bufnr) reset_bufstate(bufnr, false) end - return bufstates[bufnr].enabled + return assert(bufstates[bufnr]).enabled end --- Enables document highlighting from the given language client in the given buffer. diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 796b6503b1..a85b291285 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -241,7 +241,7 @@ end --- --- The returned function has an optional {config} parameter that accepts |vim.lsp.ListOpts| --- ----@param map_result fun(resp, bufnr: integer, position_encoding: 'utf-8'|'utf-16'|'utf-32'): table to convert the response +---@param map_result fun(resp: any, bufnr: integer, position_encoding: 'utf-8'|'utf-16'|'utf-32'): table to convert the response ---@param entity string name of the resource used in a `not found` error message ---@param title_fn fun(ctx: lsp.HandlerContext): string Function to call to generate list title ---@return lsp.Handler diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 97ac09f69e..592c89ae67 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -15,6 +15,7 @@ local globalstate = { ---@field version? integer ---@field client_hints? table> client_id -> (lnum -> hints) ---@field applied table Last version of hints applied to this line + ---@type table local bufstates = vim.defaulttable(function(_) return setmetatable({ applied = {} }, { diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 446a98f7e2..0e082d0f80 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -36,6 +36,7 @@ end local M = {} --- Mapping of error codes used by the client +--- @enum vim.lsp.rpc.ClientErrors local client_errors = { INVALID_SERVER_MESSAGE = 1, INVALID_SERVER_JSON = 2, @@ -150,6 +151,7 @@ local default_dispatchers = { local strbuffer = require('vim._stringbuffer') +--- @async local function request_parser_loop() local buf = strbuffer.new() while true do @@ -279,7 +281,7 @@ function Client:request(method, params, callback, notify_reply_callback) end ---@package ----@param errkind integer +---@param errkind vim.lsp.rpc.ClientErrors ---@param ... any function Client:on_error(errkind, ...) assert(M.client_errors[errkind]) @@ -375,7 +377,7 @@ function Client:handle_body(body) -- This works because we are expecting vim.NIL here elseif decoded.id and (decoded.result ~= vim.NIL or decoded.error ~= vim.NIL) then -- We sent a number, so we expect a number. - local result_id = assert(tonumber(decoded.id), 'response id must be a number') + local result_id = assert(tonumber(decoded.id), 'response id must be a number') --[[@as integer]] -- Notify the user that a response was received for the request local notify_reply_callback = self.notify_reply_callbacks[result_id] diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index 5f60b732de..6cb1547169 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -90,6 +90,7 @@ end --- Converts a raw token list to a list of highlight ranges used by the on_win callback --- +---@async ---@param data integer[] ---@param bufnr integer ---@param client vim.lsp.Client @@ -326,6 +327,7 @@ end --- Finally, a redraw command is issued to force nvim to redraw the screen to --- pick up changed highlight tokens. --- +---@async ---@param response lsp.SemanticTokens|lsp.SemanticTokensDelta ---@private function STHighlighter:process_response(response, client, version) @@ -491,7 +493,7 @@ function STHighlighter:on_win(topline, botline) local is_folded, foldend for i = first, last do - local token = highlights[i] + local token = assert(highlights[i]) is_folded, foldend = check_fold(token.line + 1, foldend) diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 621f63b25f..a7c688ee89 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -52,10 +52,11 @@ local str_utf_end = vim.str_utf_end -- utf-8 index and either the utf-16, or utf-32 index. ---@param line string the line to index into ---@param byte integer the byte idx ----@param position_encoding string utf-8|utf-16|utf-32|nil (default: utf-8) +---@param position_encoding 'utf-8'|'utf-16'|'utf-32'? (default: utf-8) ---@return integer byte_idx of first change position ---@return integer char_idx of first change position local function align_end_position(line, byte, position_encoding) + position_encoding = position_encoding or 'utf-8' local char --- @type integer -- If on the first byte, or an empty string: the trivial case if byte == 1 or #line == 0 then @@ -93,7 +94,7 @@ end ---@param firstline integer firstline from on_lines, adjusted to 1-index ---@param lastline integer lastline from on_lines, adjusted to 1-index ---@param new_lastline integer new_lastline from on_lines, adjusted to 1-index ----@param position_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) +---@param position_encoding 'utf-8'|'utf-16'|'utf-32'? (default: utf-8) ---@return vim.lsp.sync.Range result table include line_idx, byte_idx, and char_idx of first change position local function compute_start_range( prev_lines, @@ -103,6 +104,8 @@ local function compute_start_range( new_lastline, position_encoding ) + position_encoding = position_encoding or 'utf-8' + local char_idx --- @type integer? local byte_idx --- @type integer? -- If firstline == lastline, no existing text is changed. All edit operations @@ -130,8 +133,8 @@ local function compute_start_range( return { line_idx = firstline, byte_idx = 1, char_idx = 1 } end - local prev_line = prev_lines[firstline] - local curr_line = curr_lines[firstline] + local prev_line = assert(prev_lines[firstline]) + local curr_line = assert(curr_lines[firstline]) -- Iterate across previous and current line containing first change -- to find the first different byte. @@ -174,7 +177,7 @@ end ---@param firstline integer ---@param lastline integer ---@param new_lastline integer ----@param position_encoding string +---@param position_encoding 'utf-8'|'utf-16'|'utf-32' ---@return vim.lsp.sync.Range prev_end_range ---@return vim.lsp.sync.Range curr_end_range local function compute_end_range( @@ -189,7 +192,7 @@ local function compute_end_range( -- 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] + local prev_line = assert(prev_lines[lastline - 1]) return { line_idx = lastline - 1, byte_idx = #prev_line + 1, @@ -219,8 +222,8 @@ local function compute_end_range( local prev_line_idx = lastline - 1 local curr_line_idx = new_lastline - 1 - local prev_line = prev_lines[lastline - 1] - local curr_line = curr_lines[new_lastline - 1] + local prev_line = assert(prev_lines[lastline - 1]) + local curr_line = assert(curr_lines[new_lastline - 1]) local prev_line_length = #prev_line local curr_line_length = #curr_line @@ -284,8 +287,8 @@ end --- Get the text of the range defined by start and end line/column ---@param lines table list of lines ----@param start_range table table returned by first_difference ----@param end_range table new_end_range returned by last_difference +---@param start_range vim.lsp.sync.Range table returned by first_difference +---@param end_range vim.lsp.sync.Range new_end_range returned by last_difference ---@return string text extracted from defined region local function extract_text(lines, start_range, end_range, line_ending) if not lines[start_range.line_idx] then @@ -326,7 +329,7 @@ end ---@param lines string[] ---@param start_range vim.lsp.sync.Range ---@param end_range vim.lsp.sync.Range ----@param position_encoding string +---@param position_encoding 'utf-8'|'utf-16'|'utf-32' ---@param line_ending string ---@return integer local function compute_range_length(lines, start_range, end_range, position_encoding, line_ending) @@ -352,7 +355,9 @@ local function compute_range_length(lines, start_range, end_range, position_enco for idx = start_range.line_idx + 1, end_range.line_idx - 1 do -- Length full line plus newline character if #lines[idx] > 0 then - range_length = range_length + str_utfindex(lines[idx], position_encoding) + #line_ending + range_length = range_length + + str_utfindex(assert(lines[idx]), position_encoding) + + #line_ending else range_length = range_length + line_ending_length end @@ -372,7 +377,7 @@ end ---@param firstline integer line to begin search for first difference ---@param lastline integer line to begin search in old_lines for last difference ---@param new_lastline integer line to begin search in new_lines for last difference ----@param position_encoding string encoding requested by language server +---@param position_encoding 'utf-8'|'utf-16'|'utf-32' encoding requested by language server ---@param line_ending string ---@return lsp.TextDocumentContentChangeEvent : see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent function M.compute_diff( diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 1f83d71edf..277bb8211b 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -68,6 +68,7 @@ local function get_border_size(opts) end --- @param e string + --- @return integer local function border_height(e) return #e > 0 and 1 or 0 end @@ -133,9 +134,9 @@ function M.set_lines(lines, A, B, new_lines) error('Invalid range: ' .. vim.inspect({ A = A, B = B, #lines, new_lines })) end local prefix = '' - local suffix = lines[i_n]:sub(B[2] + 1) + local suffix = assert(lines[i_n]):sub(B[2] + 1) if A[2] > 0 then - prefix = lines[i_0]:sub(1, A[2]) + prefix = assert(lines[i_0]):sub(1, A[2]) end local n = i_n - i_0 + 1 if n ~= #new_lines then @@ -181,7 +182,7 @@ end --- ---@param bufnr integer bufnr to get the lines from ---@param rows integer[] zero-indexed line numbers ----@return table|string a table mapping rows to lines +---@return table # a table mapping rows to lines local function get_lines(bufnr, rows) --- @type integer[] rows = type(rows) == 'table' and rows or { rows } @@ -219,7 +220,7 @@ local function get_lines(bufnr, rows) -- get the data from the file local fd = uv.fs_open(filename, 'r', 438) if not fd then - return '' + return {} end local stat = assert(uv.fs_fstat(fd)) local data = assert(uv.fs_read(fd, stat.size, 0)) @@ -322,6 +323,8 @@ function M.apply_text_edits(text_edits, bufnr, position_encoding) end end + --- @cast text_edits (lsp.TextEdit|{_index: integer})[] + -- Sort text_edits ---@param a lsp.TextEdit | { _index: integer } ---@param b lsp.TextEdit | { _index: integer } @@ -1298,7 +1301,6 @@ end --- 2. Successive empty lines are collapsed into a single empty line --- 3. Thematic breaks are expanded to the given width --- ----@private ---@param contents string[] ---@param opts? vim.lsp.util._normalize_markdown.Opts ---@return string[] table of lines containing normalized Markdown @@ -1369,7 +1371,6 @@ local function close_preview_autocmd(events, winnr, bufnrs) end end ----@private --- Computes size of float needed to show contents (with optional wrapping) --- ---@param contents string[] of lines to show in window @@ -1796,7 +1797,7 @@ function M.symbols_to_items(symbols, bufnr, position_encoding) 'symbols_to_items must be called with valid position encoding', vim.log.levels.WARN ) - position_encoding = vim.lsp.get_clients({ bufnr = bufnr })[1].offset_encoding + position_encoding = assert(vim.lsp.get_clients({ bufnr = bufnr })[1]).offset_encoding end local items = {} --- @type vim.quickfix.entry[] @@ -1874,11 +1875,11 @@ end ---@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') - local language_id = lines[1]:match('^```(.*)') + local language_id = assert(lines[1]):match('^```(.*)') if language_id then local has_inner_code_fence = false for i = 2, (#lines - 1) do - local line = lines[i] + local line = lines[i] --[[@as string]] if line:sub(1, 3) == '```' then has_inner_code_fence = true break @@ -1937,7 +1938,7 @@ end --- Utility function for getting the encoding of the first LSP client on the given buffer. ---@deprecated ---@param bufnr integer buffer handle or 0 for current, defaults to current ----@return string encoding first client if there is one, nil otherwise +---@return 'utf-8'|'utf-16'|'utf-32' encoding first client if there is one, nil otherwise function M._get_offset_encoding(bufnr) validate('bufnr', bufnr, 'number', true) @@ -1963,6 +1964,7 @@ function M._get_offset_encoding(bufnr) ) end end + --- @cast offset_encoding -? hack - not safe return offset_encoding end @@ -2056,7 +2058,7 @@ end --- Create the workspace params ---@param added lsp.WorkspaceFolder[] ---@param removed lsp.WorkspaceFolder[] ----@return lsp.WorkspaceFoldersChangeEvent +---@return lsp.DidChangeWorkspaceFoldersParams function M.make_workspace_params(added, removed) return { event = { added = added, removed = removed } } end @@ -2105,7 +2107,7 @@ function M.character_offset(buf, row, col, offset_encoding) 'character_offset must be called with valid offset encoding', vim.log.levels.WARN ) - offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding + offset_encoding = assert(vim.lsp.get_clients({ bufnr = buf })[1]).offset_encoding end return vim.str_utfindex(line, offset_encoding, col, false) end @@ -2168,7 +2170,6 @@ end ---@field method? vim.lsp.protocol.Method.ClientToServer.Request ---@field type? string ----@private --- Cancel all {filter}ed requests. --- ---@param filter? vim.lsp.util._cancel_requests.Filter @@ -2203,10 +2204,9 @@ end ---@field client_id? integer Client ID to refresh (default: all clients) ---@field handler? lsp.Handler ----@private --- Request updated LSP information for a buffer. --- ----@param method string LSP method to call +---@param method vim.lsp.protocol.Method.ClientToServer.Request LSP method to call ---@param opts? vim.lsp.util._refresh.Opts Options table function M._refresh(method, opts) opts = opts or {} diff --git a/runtime/lua/vim/secure.lua b/runtime/lua/vim/secure.lua index 169214871a..c3731bf595 100644 --- a/runtime/lua/vim/secure.lua +++ b/runtime/lua/vim/secure.lua @@ -27,8 +27,8 @@ end --- If {fullpath} is a directory, then nothing is read from the filesystem, and --- `contents = true` and `hash = "directory"` is returned instead. --- ----@param fullpath (string) Path to a file or directory to read. ----@param bufnr (number?) The number of the buffer. +---@param fullpath string Path to a file or directory to read. +---@param bufnr integer? The number of the buffer. ---@return string|boolean? contents the contents of the file, or true if it's a directory ---@return string? hash the hash of the contents, or "directory" if it's a directory local function compute_hash(fullpath, bufnr) diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 73b7408118..9ce24719aa 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -105,7 +105,7 @@ end --- @return fun():string? : Iterator over the split components function vim.gsplit(s, sep, opts) local plain --- @type boolean? - local trimempty = false + local trimempty = false --- @type boolean? if type(opts) == 'boolean' then plain = opts -- For backwards compatibility. else @@ -616,7 +616,7 @@ function vim.spairs(t) --- @cast t table -- collect the keys - local keys = {} + local keys = {} --- @type string[] for k in pairs(t) do table.insert(keys, k) end @@ -1027,7 +1027,7 @@ do --- --- @param name string Argument name --- @param value any Argument value - --- @param validator vim.validate.Validator + --- @param validator vim.validate.Validator : --- - (`string|string[]`): Any value that can be returned from |lua-type()| in addition to --- `'callable'`: `'boolean'`, `'callable'`, `'function'`, `'nil'`, `'number'`, `'string'`, `'table'`, --- `'thread'`, `'userdata'`. @@ -1194,7 +1194,6 @@ do end end ---- @private --- @generic T --- @param root string --- @param mod T @@ -1214,7 +1213,6 @@ function vim._defer_require(root, mod) }) end ---- @private --- Creates a module alias/shim that lazy-loads a target module. --- --- Unlike `vim.defaulttable()` this also: @@ -1423,7 +1421,7 @@ function vim._resolve_bufnr(bufnr) end --- @generic T ---- @param x elem_or_list? +--- @param x T|T[] --- @return T[] function vim._ensure_list(x) if type(x) == 'table' then @@ -1432,4 +1430,7 @@ function vim._ensure_list(x) return { x } end +-- Use max 32-bit signed int value to avoid overflow on 32-bit systems. #31633 +vim._maxint = 2 ^ 32 - 1 + return vim diff --git a/runtime/lua/vim/text.lua b/runtime/lua/vim/text.lua index 93220a2e42..25126d738d 100644 --- a/runtime/lua/vim/text.lua +++ b/runtime/lua/vim/text.lua @@ -79,7 +79,7 @@ end --- --- @param size integer Number of spaces. --- @param text string Text to indent. ---- @param opts? { expandtab?: number } +--- @param opts? { expandtab?: integer } --- @return string # Indented text. --- @return integer # Indent size _before_ modification. function M.indent(size, text, opts) @@ -91,7 +91,7 @@ function M.indent(size, text, opts) local tabspaces = opts.expandtab and (' '):rep(opts.expandtab) or nil --- Minimum common indent shared by all lines. - local old_indent --[[@type number?]] + local old_indent --- @type integer? local prefix = tabspaces and ' ' or nil -- Indent char (space or tab). --- Check all non-empty lines, capturing leading whitespace (if any). --- @diagnostic disable-next-line: no-unknown @@ -106,7 +106,7 @@ function M.indent(size, text, opts) end prefix = prefix and prefix or line_ws:sub(1, 1) local _, end_ = line_ws:find('^[' .. prefix .. ']+') - old_indent = math.min(old_indent or math.huge, end_ or 0) + old_indent = math.min(old_indent or math.huge, end_ or 0) --[[@as integer?]] end -- Default to 0 if all lines are empty. old_indent = old_indent or 0 diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index c2df96d9b4..01ef856b31 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -280,18 +280,19 @@ function M.get_captures_at_pos(bufnr, row, col) end local q = buf_highlighter:get_query(tree:lang()) + local query = q:query() -- Some injected languages may not have highlight queries. - if not q:query() then + if not query then return end - local iter = q:query():iter_captures(root, buf_highlighter.bufnr, row, row + 1) + local iter = query:iter_captures(root, buf_highlighter.bufnr, row, row + 1) for id, node, metadata, match in iter do if M.is_in_node_range(node, row, col) then ---@diagnostic disable-next-line: invisible - local capture = q._query.captures[id] -- name of the capture in the query + local capture = query.captures[id] -- name of the capture in the query if capture ~= nil then local _, pattern_id = match:info() table.insert(matches, { diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index 6975b7d441..8cab984598 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -154,7 +154,6 @@ local function lint_match(buf, match, query, lang_context, diagnostics) end end ---- @private --- @param buf integer Buffer to lint --- @param opts vim.treesitter.query.lint.Opts|QueryLinterNormalizedOpts|nil Options for linting function M.lint(buf, opts) @@ -193,13 +192,11 @@ function M.lint(buf, opts) vim.diagnostic.set(namespace, buf, diagnostics) end ---- @private --- @param buf integer function M.clear(buf) vim.diagnostic.reset(namespace, buf) end ---- @private --- @param findstart 0|1 --- @param base string function M.omnifunc(findstart, base) diff --git a/runtime/lua/vim/treesitter/_range.lua b/runtime/lua/vim/treesitter/_range.lua index 885df570c2..014f3b1c2e 100644 --- a/runtime/lua/vim/treesitter/_range.lua +++ b/runtime/lua/vim/treesitter/_range.lua @@ -72,7 +72,6 @@ M.cmp_pos = { setmetatable(M.cmp_pos, { __call = cmp_pos }) ----@private ---Check if a variable is a valid range object ---@param r any ---@return boolean @@ -92,7 +91,6 @@ function M.validate(r) return true end ----@private ---@param r1 Range ---@param r2 Range ---@return boolean @@ -113,7 +111,6 @@ function M.intercepts(r1, r2) return true end ----@private ---@param r1 Range6 ---@param r2 Range6 ---@return Range6? @@ -126,7 +123,6 @@ function M.intersection(r1, r2) return { rs[1], rs[2], rs[3], re[4], re[5], re[6] } end ----@private ---@param r Range ---@return integer, integer, integer, integer function M.unpack4(r) @@ -137,14 +133,12 @@ function M.unpack4(r) return r[1], r[2], r[3 + off_1], r[4 + off_1] end ----@private ---@param r Range6 ---@return integer, integer, integer, integer, integer, integer function M.unpack6(r) return r[1], r[2], r[3], r[4], r[5], r[6] end ----@private ---@param r1 Range ---@param r2 Range ---@return boolean whether r1 contains r2 @@ -188,7 +182,6 @@ local function get_offset(source, index) return byte end ----@private ---@param source integer|string ---@param range Range ---@return Range6 diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua index 1ce1916d4b..f44db7b668 100644 --- a/runtime/lua/vim/treesitter/dev.lua +++ b/runtime/lua/vim/treesitter/dev.lua @@ -15,7 +15,7 @@ local TSTreeView = {} ---@class (private) vim.treesitter.dev.TSTreeViewOpts ---@field anon boolean If true, display anonymous nodes. ---@field lang boolean If true, display the language alongside each node. ----@field indent number Number of spaces to indent nested lines. +---@field indent integer Number of spaces to indent nested lines. ---@class (private) vim.treesitter.dev.Node ---@field node TSNode Treesitter node @@ -290,7 +290,7 @@ end --- The node number is dependent on whether or not anonymous nodes are displayed. --- ---@param i integer Node number to get ----@return vim.treesitter.dev.Node +---@return vim.treesitter.dev.Node? ---@package function TSTreeView:get(i) local t = self.opts.anon and self.nodes or self.named @@ -329,8 +329,7 @@ end --- source buffer as its only argument and should return a string. --- @field title (string|fun(bufnr:integer):string|nil) ---- @private ---- +--- @nodoc --- @param opts vim.treesitter.dev.inspect_tree.Opts? function M.inspect_tree(opts) vim.validate('opts', opts, 'table', true) @@ -401,7 +400,7 @@ function M.inspect_tree(opts) -- update source window if original was closed if not api.nvim_win_is_valid(win) then - win = vim.fn.win_findbuf(buf)[1] + win = assert(vim.fn.win_findbuf(buf)[1]) end api.nvim_set_current_win(win) @@ -475,7 +474,7 @@ function M.inspect_tree(opts) -- update source window if original was closed if not api.nvim_win_is_valid(win) then - win = vim.fn.win_findbuf(buf)[1] + win = assert(vim.fn.win_findbuf(buf)[1]) end local topline, botline = vim.fn.line('w0', win), vim.fn.line('w$', win) @@ -599,7 +598,7 @@ local function update_editor_highlights(query_win, base_win, lang) end end ---- @private +--- @nodoc --- @param lang? string language to open the query editor for. --- @return boolean? `true` on success, `nil` on failure --- @return string? error message, if applicable diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index f70f99421c..5255e233fa 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -41,7 +41,7 @@ function M.get_lang(filetype) return ft_to_lang[filetype] end -- for subfiletypes like html.glimmer use only "main" filetype - filetype = vim.split(filetype, '.', { plain = true })[1] + filetype = assert(vim.split(filetype, '.', { plain = true })[1]) return ft_to_lang[filetype] or filetype end diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index d560302f8c..c3dfb86689 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -49,7 +49,10 @@ local hrtime = vim.uv.hrtime local default_parse_timeout_ns = 3 * 1000000 ---@type Range2 -local entire_document_range = { 0, math.huge } +local entire_document_range = { + 0, + math.huge --[[@as integer]], +} ---@alias TSCallbackName ---| 'changedtree' diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 8d0a185de6..b50d59e674 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -193,7 +193,7 @@ function M.get_files(lang, query_name, is_included) local langlist = modeline:match(MODELINE_FORMAT) if langlist then ---@diagnostic disable-next-line:param-type-mismatch - for _, incllang in ipairs(vim.split(langlist, ',', true)) do + for _, incllang in ipairs(vim.split(langlist, ',')) do local is_optional = incllang:match('%(.*%)') if is_optional then @@ -778,7 +778,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: vim.treesitter.query.TSMetadata): boolean? +---@param handler fun(match: table, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata): boolean? # --- - see |vim.treesitter.query.add_directive()| for argument meanings ---@param opts? vim.treesitter.query.add_predicate.Opts function M.add_predicate(name, handler, opts) @@ -818,7 +818,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: vim.treesitter.query.TSMetadata) +---@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. diff --git a/runtime/lua/vim/ui/clipboard/osc52.lua b/runtime/lua/vim/ui/clipboard/osc52.lua index 73f64c9743..a49b690965 100644 --- a/runtime/lua/vim/ui/clipboard/osc52.lua +++ b/runtime/lua/vim/ui/clipboard/osc52.lua @@ -22,7 +22,7 @@ end function M.paste(reg) local clipboard = reg == '+' and 'c' or 'p' return function() - local contents = nil + local contents = nil --- @type string? local id = vim.api.nvim_create_autocmd('TermResponse', { callback = function(args) local resp = args.data.sequence ---@type string diff --git a/src/gen/gen_eval_files.lua b/src/gen/gen_eval_files.lua index 221c7975f6..d1bd089dd8 100755 --- a/src/gen/gen_eval_files.lua +++ b/src/gen/gen_eval_files.lua @@ -32,6 +32,7 @@ local LUA_API_RETURN_OVERRIDES = { nvim_get_command = 'table', nvim_get_keymap = 'vim.api.keyset.get_keymap[]', nvim_get_mark = 'vim.api.keyset.get_mark', + nvim_eval_statusline = 'vim.api.keyset.eval_statusline_ret', -- Can also return table, however we need to -- pick one to get some benefit. @@ -45,6 +46,7 @@ local LUA_API_RETURN_OVERRIDES = { nvim_get_option_info2 = 'vim.api.keyset.get_option_info', nvim_parse_cmd = 'vim.api.keyset.parse_cmd', nvim_win_get_config = 'vim.api.keyset.win_config', + nvim_win_text_height = 'vim.api.keyset.win_text_height_ret', } local LUA_API_KEYSET_OVERRIDES = { diff --git a/src/gen/luacats_parser.lua b/src/gen/luacats_parser.lua index 36bdc44076..cfc3c3b022 100644 --- a/src/gen/luacats_parser.lua +++ b/src/gen/luacats_parser.lua @@ -147,6 +147,9 @@ local function process_doc_line(line, state) cur_obj.fields = {} elseif kind == 'field' then --- @cast parsed nvim.luacats.Field + if parsed.desc == '' then + parsed.desc = nil + end parsed.desc = parsed.desc or state.doc_lines and table.concat(state.doc_lines, '\n') or nil if parsed.desc then parsed.desc = vim.trim(parsed.desc) diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 11b9d36be9..4c0c9cb412 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3970,6 +3970,7 @@ M.funcs = { ]=], name = 'getcurpos', params = { { 'winid', 'integer' } }, + returns = '[integer, integer, integer, integer, integer]', signature = 'getcurpos([{winid}])', }, getcursorcharpos = { @@ -4313,6 +4314,7 @@ M.funcs = { ]=], name = 'getmatches', params = { { 'win', 'integer' } }, + returns = 'vim.fn.getmatches.ret.item[]', signature = 'getmatches([{win}])', }, getmousepos = { @@ -4428,7 +4430,7 @@ M.funcs = { ]=], name = 'getpos', params = { { 'expr', 'string' } }, - returns = 'integer[]', + returns = '[integer, integer, integer, integer]', signature = 'getpos({expr})', }, getqflist = { @@ -4672,7 +4674,11 @@ M.funcs = { < ]=], name = 'getregion', - params = { { 'pos1', 'table' }, { 'pos2', 'table' }, { 'opts', 'table' } }, + params = { + { 'pos1', '[integer, integer, integer, integer]' }, + { 'pos2', '[integer, integer, integer, integer]' }, + { 'opts', '{type?:string, exclusive?:boolean}' }, + }, returns = 'string[]', signature = 'getregion({pos1}, {pos2} [, {opts}])', }, @@ -4712,8 +4718,12 @@ M.funcs = { (default: |FALSE|) ]=], name = 'getregionpos', - params = { { 'pos1', 'table' }, { 'pos2', 'table' }, { 'opts', 'table' } }, - returns = 'integer[][][]', + params = { + { 'pos1', '[integer, integer, integer, integer]' }, + { 'pos2', '[integer, integer, integer, integer]' }, + { 'opts', '{type?:string, exclusive?:boolean, eol?:boolean}' }, + }, + returns = '[ [integer, integer, integer, integer], [integer, integer, integer, integer] ][]', signature = 'getregionpos({pos1}, {pos2} [, {opts}])', }, getregtype = { @@ -8648,6 +8658,7 @@ M.funcs = { ]=], name = 'readfile', params = { { 'fname', 'string' }, { 'type', 'string' }, { 'max', 'integer' } }, + returns = 'string[]', signature = 'readfile({fname} [, {type} [, {max}]])', }, reduce = { @@ -9998,7 +10009,7 @@ M.funcs = { ]=], name = 'setmatches', - params = { { 'list', 'any' }, { 'win', 'integer' } }, + params = { { 'list', 'vim.fn.getmatches.ret.item[]' }, { 'win', 'integer' } }, signature = 'setmatches({list} [, {win}])', }, setpos = { @@ -12924,6 +12935,7 @@ M.funcs = { ]=], name = 'virtcol', params = { { 'expr', 'string|any[]' }, { 'list', 'boolean' }, { 'winid', 'integer' } }, + returns = 'integer|[integer, integer]', signature = 'virtcol({expr} [, {list} [, {winid}]])', }, virtcol2col = {