build: enable more EmmyLua checks

Enable checks for unused code, deprecated calls, return types, and
annotations.

Fix the warnings and replace the deprecated highlight function. Keep
exceptions where old APIs are still needed or the checker gets it wrong.

AI-assisted
This commit is contained in:
Lewis Russell
2026-09-09 13:04:46 +01:00
committed by Lewis Russell
parent 08dd3adffb
commit d039f19af5
44 changed files with 202 additions and 117 deletions

View File

@@ -28,29 +28,27 @@
"disable": [
"annotation-usage-error",
"assign-type-mismatch",
"await-in-sync",
"code-style-check",
"deprecated",
"global-in-non-module",
"incomplete-signature-doc",
"invert-if",
"iter-variable-reassign",
"missing-global-doc",
"need-check-nil",
"non-literal-expressions-in-assert",
"param-type-mismatch",
"preferred-local-alias",
"return-type-mismatch",
"unknown-doc-tag",
"unnecessary-assert",
"unnecessary-if",
"unused"
"unnecessary-if"
],
"severity": {
"deprecated": "warning",
"duplicate-require": "warning",
"preferred-local-alias": "warning",
"redefined-local": "warning",
"unreachable-code": "warning"
}
"unreachable-code": "warning",
"unused": "warning"
},
"enables": [
"missing-global-doc",
"non-literal-expressions-in-assert",
"unknown-doc-tag"
]
},
"codeAction": {
"insertSpace": true
@@ -58,5 +56,14 @@
"strict": {
"typeCall": true,
"arrayIndex": true
},
"doc": {
"knownTags": [
"brief",
"inlinedoc",
"nodoc",
"note",
"since"
]
}
}

View File

@@ -2187,6 +2187,9 @@ get({filter}) *vim.lsp.codelens.get()*
• {client_id}? (`integer`, default: all) Client ID, or nil
for all.
Overloads: ~
• `fun(filter: integer): lsp.CodeLens[]`
Return: ~
(`table[]`) A list of objects with the following fields:
• {client_id} (`integer`)

View File

@@ -48,6 +48,7 @@ local running = coroutine.running
--- @type table<thread,thread>
local coromap = setmetatable({}, { __mode = "k" })
--- @async
local function handleReturnValue(err, co, status, ...)
if not status then
return false, err(debug.traceback(co, (...)), ...)
@@ -59,6 +60,7 @@ local function handleReturnValue(err, co, status, ...)
end
end
--- @async
function performResume(err, co, ...)
return handleReturnValue(err, co, coroutine.resume(co, ...))
end
@@ -68,6 +70,10 @@ local function id(trace, ...)
return trace
end
--- @param f function
--- @param err function
--- @param ... any
--- @return boolean, any...
function _G.coxpcall(f, err, ...)
local current = running()
if not current then
@@ -87,6 +93,8 @@ function _G.coxpcall(f, err, ...)
co = coroutine.create(newf)
end
coromap[co] = current
-- This branch only runs inside a coroutine.
--- @diagnostic disable-next-line: await-in-sync
return performResume(err, co, ...)
end
end
@@ -109,7 +117,12 @@ end
-- Implements pcall with coroutines
-------------------------------------------------------------------------------
--- @param f function
--- @param ... any
--- @return boolean, any...
function _G.copcall(f, ...)
-- EmmyLua does not distribute the union of xpcall return tuples.
--- @diagnostic disable-next-line: return-type-mismatch
return coxpcall(f, id, ...)
end

View File

@@ -385,8 +385,8 @@ end
--- (try `:Man 3 App::CLI`). Also on linux, name seems to be case-insensitive.
--- So for `:Man PRIntf`, we still want the name of the buffer to be 'printf'.
--- @param path string
--- @return string name
--- @return string sect
--- @return string? name
--- @return string? sect
local function parse_path(path)
local tail = vim.fs.basename(path)
if

View File

@@ -535,10 +535,10 @@ do
local function make_dict_accessor(scope, handle)
vim.validate('scope', scope, 'string')
local mt = {}
function mt:__newindex(k, v)
function mt.__newindex(_, k, v)
return vim._setvar(scope, handle or 0, k, v)
end
function mt:__index(k)
function mt.__index(_, k)
if handle == nil and type(k) == 'number' then
return make_dict_accessor(scope, k)
end
@@ -926,7 +926,7 @@ function vim.str_utfindex(s, encoding, index, strict_indexing)
if encoding == 'utf-8' then
local len = #s
return index <= len and index or (strict_indexing and error('index out of range') or len)
return (index <= len and index or (strict_indexing and error('index out of range') or len)) --[[@as integer]]
end
local col32, col16 = vim._str_utfindex(s, index) --[[@as integer?,integer?]]
local col = encoding == 'utf-16' and col16 or col32

View File

@@ -216,7 +216,7 @@ function M.ex_log(eap)
else
path = fs.joinpath(log_dir, filename .. '.log')
end
if not vim.uv.fs_stat(path) then
if not uv.fs_stat(path) then
util.echo_err(N_('E5200: No such log file: %s'):format(path))
return
end
@@ -229,7 +229,7 @@ end
--- @return string[] completions
function M.log_complete()
local names = { 'nvim' } --- @type string[]
for file, type in vim.fs.dir(log_dir, { depth = math.huge }) do
for file, type in fs.dir(log_dir, { depth = math.huge }) do
local name, matches = file:gsub('%.log$', '')
if matches ~= 0 and type == 'file' and name ~= 'nvim' then
names[#names + 1] = name

View File

@@ -249,7 +249,7 @@ end
---
---@return string? resolved The resolved help tag, or nil if no match found
function M.resolve_tag()
local tag = vim.fn.expand('<cWORD>')
local tag = vim.fn.expand('<cWORD>') --[[@as string]]
if not tag or tag == '' then
return nil
end

View File

@@ -295,7 +295,7 @@ local function create_option_accessor(scope)
end,
append = function(self, right)
vim.api.nvim_set_option_value(self._name, right, { operation = 'append', scope = scope })
api.nvim_set_option_value(self._name, right, { operation = 'append', scope = scope })
end,
__infix = function(self, right, operation)
@@ -315,7 +315,7 @@ local function create_option_accessor(scope)
end
return make_option(
self._name,
vim.api.nvim_set_option_value(
api.nvim_set_option_value(
self._name,
right,
{ operation = operation, scope = scope, dry_run = true }
@@ -329,7 +329,7 @@ local function create_option_accessor(scope)
end,
prepend = function(self, right)
vim.api.nvim_set_option_value(self._name, right, { operation = 'prepend', scope = scope })
api.nvim_set_option_value(self._name, right, { operation = 'prepend', scope = scope })
end,
__pow = function(self, right)
@@ -337,7 +337,7 @@ local function create_option_accessor(scope)
end,
remove = function(self, right)
vim.api.nvim_set_option_value(self._name, right, { operation = 'remove', scope = scope })
api.nvim_set_option_value(self._name, right, { operation = 'remove', scope = scope })
end,
__sub = function(self, right)
@@ -479,6 +479,7 @@ local Option = {} -- luacheck: no unused
--- end
--- ```
---@return string|integer|boolean|nil value of option
---@diagnostic disable-next-line: unused used for gen_vimdoc
function Option:get() end
--- Append a value to string-style options. See |:set+=|
@@ -490,7 +491,7 @@ function Option:get() end
--- vim.opt.formatoptions = vim.opt.formatoptions + 'j'
--- ```
---@param value string Value to append
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
---@diagnostic disable-next-line:unused used for gen_vimdoc
function Option:append(value) end -- luacheck: no unused
--- Prepend a value to string-style options. See |:set^=|
@@ -502,7 +503,7 @@ function Option:append(value) end -- luacheck: no unused
--- vim.opt.wildignore = vim.opt.wildignore ^ '*.o'
--- ```
---@param value string Value to prepend
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
---@diagnostic disable-next-line:unused used for gen_vimdoc
function Option:prepend(value) end -- luacheck: no unused
--- Remove a value from string-style options. See |:set-=|
@@ -514,7 +515,7 @@ function Option:prepend(value) end -- luacheck: no unused
--- vim.opt.wildignore = vim.opt.wildignore - '*.pyc'
--- ```
---@param value string Value to remove
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
---@diagnostic disable-next-line:unused used for gen_vimdoc
function Option:remove(value) end -- luacheck: no unused
--- @nodoc

View File

@@ -1680,6 +1680,7 @@ end
--- @return T[]
function vim._ensure_list(x)
if type(x) == 'table' then
--- @cast x T[]
return x
end
return { x }

View File

@@ -147,6 +147,8 @@ function SystemObj:wait(timeout)
end, nil, true)
end
-- TODO: A short timeout can leave result nil even after sending SIGKILL.
---@diagnostic disable-next-line: return-type-mismatch
return state.result
end

View File

@@ -5,17 +5,14 @@ local has_clear, clear = pcall(require, 'table.clear')
local M = {}
if not has_new then
---@diagnostic disable-next-line: unused-local
new = function(narr, nrec)
new = function(_narr, _nrec)
return {}
end
end
if not has_clear then
clear = function(tab)
---@diagnostic disable-next-line: no-unknown
for k in pairs(tab) do
---@diagnostic disable-next-line: no-unknown
tab[k] = nil
end
end

View File

@@ -195,7 +195,7 @@ function M.enable(opts)
M.cfg.msg.targets = type(M.cfg.msg.targets) == 'table' and M.cfg.msg.targets
or { default = M.cfg.msg.targets }
M.cfg.msg.targets.default = M.cfg.msg.targets.default or 'cmd'
if #vim.api.nvim_list_uis() == 0 then
if #api.nvim_list_uis() == 0 then
return -- Don't prevent stdout messaging when no UIs are attached.
end

View File

@@ -56,6 +56,8 @@ function vim.inspect_pos(buf, row, col, filter)
row, col = cursor[1] - 1, cursor[2]
end
buf = vim._resolve_bufnr(buf)
---@cast row integer
---@cast col integer
local results = {
treesitter = {}, --- @type table[]

View File

@@ -5,6 +5,8 @@ local store = require('vim.diagnostic._store')
--- @class (private) vim.diagnostic._float
local M = {}
local float_ns = api.nvim_create_namespace('nvim.diagnostic.float')
local severity = vim.diagnostic.severity
--- @type table<vim.diagnostic.Severity, string>
@@ -263,19 +265,31 @@ function M.open(opts, ...)
end
end, { buf = float_bufnr, remap = false })
--- @diagnostic disable-next-line: deprecated
local add_highlight = api.nvim_buf_add_highlight
-- The preview may trim empty lines or reuse an older buffer, so highlight ranges
-- can extend past its contents. Use strict = false to tolerate this.
for i, hl in ipairs(highlights) do
local line = lines[i]
local prefix_len = hl.prefix and hl.prefix.length or 0
local suffix_len = hl.suffix and hl.suffix.length or 0
if prefix_len > 0 then
add_highlight(float_bufnr, -1, hl.prefix.hlname, i - 1, 0, prefix_len)
api.nvim_buf_set_extmark(float_bufnr, float_ns, i - 1, 0, {
hl_group = hl.prefix.hlname,
end_col = prefix_len,
strict = false,
})
end
add_highlight(float_bufnr, -1, hl.hlname, i - 1, prefix_len, #line - suffix_len)
api.nvim_buf_set_extmark(float_bufnr, float_ns, i - 1, prefix_len, {
hl_group = hl.hlname,
end_col = #line - suffix_len,
strict = false,
})
if suffix_len > 0 then
add_highlight(float_bufnr, -1, hl.suffix.hlname, i - 1, #line - suffix_len, -1)
api.nvim_buf_set_extmark(float_bufnr, float_ns, i - 1, #line - suffix_len, {
hl_group = hl.suffix.hlname,
end_row = i,
end_col = 0,
strict = false,
})
end
end

View File

@@ -58,6 +58,8 @@ function M.get_logical_pos(diagnostic)
return diagnostic.lnum, diagnostic.col, diagnostic.end_lnum, diagnostic.end_col, true
end
-- Diagnostic extmarks always have an end position.
---@cast extmark [integer, integer, {end_row: integer, end_col: integer, invalid?: boolean}]
return extmark[1], extmark[2], extmark[3].end_row, extmark[3].end_col, not extmark[3].invalid
end

View File

@@ -109,7 +109,7 @@ end
--- @return table<string,true>
function M._get_known_filetypes()
local known = {} --- @type table<string,true>
for _, ft in ipairs(vim.fn.getcompletion('', 'filetype')) do
for _, ft in ipairs(fn.getcompletion('', 'filetype')) do
known[ft] = true
end
local registry = vim.filetype.inspect()

View File

@@ -276,7 +276,7 @@ local function fs_scandir_next(fs, path)
end
if etype == nil then
local stat = vim.uv.fs_lstat(M.joinpath(path, name))
local stat = uv.fs_lstat(M.joinpath(path, name))
-- Workaround #39612 https://github.com/luvit/luv/issues/660
etype = stat and stat.type or 'unknown'
end

View File

@@ -801,6 +801,8 @@ local function check_sysinfo()
local encoded_body = vim.uri_encode(body) --- @type string
local issue_url = 'https://github.com/neovim/neovim/issues/new?type=Bug&body=' .. encoded_body
--- Opens the prefilled issue from the checkhealth winbar.
---@diagnostic disable-next-line: global-in-non-module
_G.nvim_health_bugreport_open = function()
vim.ui.open(issue_url)
end

View File

@@ -276,7 +276,7 @@ function Iter:unique(key)
end
--- @nodoc
--- @diagnostic disable-next-line:unused-local
--- @diagnostic disable-next-line:unused
function Iter:flatten(depth)
error('flatten() requires an array-like table')
end
@@ -629,7 +629,7 @@ function IterArray:next()
end
--- @nodoc
--- @diagnostic disable-next-line: unused-local
--- @diagnostic disable-next-line: unused
function Iter:rev()
error('rev() requires an array-like table')
end
@@ -743,7 +743,7 @@ function Iter:find(f)
end
--- @nodoc
--- @diagnostic disable-next-line:unused-local
--- @diagnostic disable-next-line:unused
function Iter:rfind(f)
error('rfind() requires an array-like table')
end
@@ -866,7 +866,7 @@ function IterArray:take(n)
end
--- @nodoc
--- @diagnostic disable-next-line: unused-local
--- @diagnostic disable-next-line: unused
function Iter:pop()
error('pop() requires an array-like table')
end
@@ -894,7 +894,7 @@ function IterArray:pop()
end
--- @nodoc
--- @diagnostic disable-next-line: unused-local
--- @diagnostic disable-next-line: unused
function Iter:rpeek()
error('rpeek() requires an array-like table')
end
@@ -1003,7 +1003,7 @@ function IterArray:skip(n)
end
--- @nodoc
--- @diagnostic disable-next-line:unused-local
--- @diagnostic disable-next-line:unused
function Iter:rskip(n)
error('rskip() requires an array-like table')
end
@@ -1064,7 +1064,7 @@ function Iter:nth(n)
end
--- @nodoc
--- @diagnostic disable-next-line:unused-local
--- @diagnostic disable-next-line:unused
function Iter:slice(first, last)
error('slice() requires an array-like table')
end

View File

@@ -437,7 +437,8 @@ function M.enable(enable)
M.enabled = enable
if enable then
vim.fn.mkdir(vim.fs.abspath(M.path), 'p')
vim.fn.mkdir(fs.abspath(M.path), 'p')
---@diagnostic disable-next-line: global-in-non-module
_G.loadfile = loadfile_cached
-- add Lua loader
table.insert(loaders, 2, loader_cached)
@@ -451,6 +452,7 @@ function M.enable(enable)
end
end
else
---@diagnostic disable-next-line: global-in-non-module
_G.loadfile = _loadfile
for l = #loaders, 1, -1 do
local loader = loaders[l]

View File

@@ -118,18 +118,18 @@ end
--- Callback invoked when textDocument/didClose is sent for a client.
---@param client_id integer
---@diagnostic disable-next-line: unused-local
---@diagnostic disable-next-line: unused
function M:on_close(client_id) end
--- Callback invoked when textDocument/didChange or textDocument/didOpen is sent for a client.
---@param client_id integer
---@diagnostic disable-next-line: unused-local
---@diagnostic disable-next-line: unused
function M:on_change(client_id) end
--- Callback invoked on every redraw.
---@param topline integer
---@param botline integer
---@diagnostic disable-next-line: unused-local
---@diagnostic disable-next-line: unused
function M:on_win(topline, botline) end
---@param name vim.lsp.capability.Name

View File

@@ -254,7 +254,7 @@ function State:on_attach(client_id)
self:refresh(client_id)
end
---@params client_id integer
---@param client_id integer
function State:on_detach(client_id)
self.client_state[client_id] = nil
self:evaluate()
@@ -275,7 +275,7 @@ end
---@param kind lsp.FoldingRangeKind
---@param winid integer
function State:foldclose(kind, winid)
function State.foldclose(_, kind, winid)
vim._with({ win = winid }, function()
local bufnr = api.nvim_win_get_buf(winid)
local row_kinds = State.active[bufnr].row_kinds
@@ -395,7 +395,7 @@ function M.foldtext(lnum)
local row = lnum - 1
local state = State.active[bufnr]
local lang = state and state.lang
local line = vim.fn.getline(lnum)
local line = vim.fn.getline(lnum) --[[@as string]]
if not lang then
return line
end ---@cast state -nil

View File

@@ -36,7 +36,7 @@ local function ctx_is_valid(ctx)
not bufnr
or not api.nvim_buf_is_valid(bufnr)
or api.nvim_get_current_buf() ~= bufnr
or vim.lsp.util.buf_versions[bufnr] ~= ctx.version
or lsp.util.buf_versions[bufnr] ~= ctx.version
then
return false
end

View File

@@ -989,7 +989,7 @@ end
--- Get provider for a method to be registered dynamically.
--- @param method vim.lsp.protocol.Method | vim.lsp.protocol.Method.Registration
function Client:_registration_provider(method)
function Client._registration_provider(_, method)
return lsp.protocol._request_name_to_registration_provider[method] or method
end
@@ -1224,7 +1224,7 @@ function Client:on_attach(bufnr)
-- schedule the initialization of capabilities to give the above on_attach and LspAttach callbacks
-- the ability to enable or disable them
vim.schedule(function()
if not vim.api.nvim_buf_is_valid(bufnr) then
if not api.nvim_buf_is_valid(bufnr) then
return
end
for _, Capability in pairs(lsp._capability.all) do
@@ -1456,7 +1456,7 @@ function Client:_on_detach(bufnr)
end
end
vim.diagnostic.reset(vim.lsp.diagnostic.get_namespace(self.id, false), bufnr)
vim.diagnostic.reset(lsp.diagnostic.get_namespace(self.id, false), bufnr)
changetracking.reset_buf(self, bufnr)
@@ -1468,10 +1468,10 @@ end
--- Reset defaults set by `set_defaults`.
--- Must only be called if the last client attached to a buffer exits.
local function reset_defaults(bufnr)
if vim.bo[bufnr].tagfunc == vim.lsp.tagfunc then
if vim.bo[bufnr].tagfunc == lsp.tagfunc then
vim.bo[bufnr].tagfunc = nil
end
if vim.bo[bufnr].omnifunc == vim.lsp.omnifunc then
if vim.bo[bufnr].omnifunc == lsp.omnifunc then
vim.bo[bufnr].omnifunc = nil
end
if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then

View File

@@ -297,6 +297,7 @@ end
---
---@param filter? vim.lsp.codelens.get.Filter
---@return vim.lsp.codelens.get.Result[]
---@overload fun(filter: integer): lsp.CodeLens[]
function M.get(filter)
if type(filter) == 'number' then
vim.deprecate(
@@ -316,6 +317,7 @@ function M.get(filter)
result = vim.list_extend(result, row_lenses.lenses)
end
end
---@diagnostic disable-next-line: return-type-mismatch
return result
end

View File

@@ -145,7 +145,7 @@ local compute_new_average = exp_avg(10, 10)
---
--- @param last_request_time integer?
--- @param current_rtt_ms number
--- @return integer
--- @return number
local function adaptive_debounce(last_request_time, current_rtt_ms)
if not last_request_time then
return current_rtt_ms
@@ -298,6 +298,7 @@ local function get_items(result)
return result.items
else
-- Else just return the items as they are.
---@cast result lsp.CompletionItem[]
return result
end
end
@@ -308,7 +309,7 @@ end
---@return lsp.MarkupKind
local function get_doc(item)
local doc = item.documentation
local default_kind = vim.lsp.protocol.MarkupKind.Markdown
local default_kind = protocol.MarkupKind.Markdown
if not doc then
return '', default_kind
end
@@ -349,11 +350,11 @@ end
---@return string? kind text or "■" for colors
---@return string? highlight group for colors
local function generate_kind(item)
if not lsp.protocol.CompletionItemKind[item.kind] then
if not protocol.CompletionItemKind[item.kind] then
return 'Unknown'
end
if item.kind ~= lsp.protocol.CompletionItemKind.Color then
return lsp.protocol.CompletionItemKind[item.kind]
if item.kind ~= protocol.CompletionItemKind.Color then
return protocol.CompletionItemKind[item.kind] --[[@as string]]
end
local doc = get_doc(item)
if #doc == 0 then
@@ -575,6 +576,7 @@ function M._lsp_to_complete_items(
local hl_group = ''
if
---@diagnostic disable-next-line: deprecated
item.deprecated
or vim.list_contains((item.tags or {}), protocol.CompletionTag.Deprecated)
then
@@ -786,7 +788,7 @@ end
--- @param kind? string
local function update_popup_window(winid, bufnr, kind)
if winid and api.nvim_win_is_valid(winid) and bufnr and api.nvim_buf_is_valid(bufnr) then
if kind == lsp.protocol.MarkupKind.Markdown then
if kind == protocol.MarkupKind.Markdown then
vim.wo[winid].conceallevel = 2
vim.treesitter.start(bufnr, kind)
end
@@ -856,9 +858,9 @@ end
--- @return boolean, table Validity of the request and the completion info
function CompletionResolver:is_valid()
local cmp_info = vim.fn.complete_info({ 'selected', 'completed' })
return vim.api.nvim_buf_is_valid(self.bufnr)
and vim.api.nvim_get_current_buf() == self.bufnr
and vim.startswith(vim.api.nvim_get_mode().mode, 'i')
return api.nvim_buf_is_valid(self.bufnr)
and api.nvim_get_current_buf() == self.bufnr
and vim.startswith(api.nvim_get_mode().mode, 'i')
and vim.fn.pumvisible() ~= 0
and (vim.tbl_get(cmp_info, 'completed', 'word') or '') == self.word,
cmp_info
@@ -887,7 +889,7 @@ function CompletionResolver:request(bufnr, param, selected_word)
self:cancel_pending_requests()
local client_id = vim.tbl_get(cmp_info.completed, 'user_data', 'nvim', 'lsp', 'client_id')
local client = client_id and vim.lsp.get_client_by_id(client_id)
local client = client_id and lsp.get_client_by_id(client_id)
-- completionItem/resolve is not registrable, so supports_method() would
-- only see the static capability.
if not client or not completion_options(client, bufnr).resolveProvider then
@@ -917,7 +919,7 @@ function CompletionResolver:request(bufnr, param, selected_word)
local info, kind = complete_item_info(result)
if info ~= '' and info ~= cmp_info.completed.info then
local windata = vim.api.nvim__complete_set(cmp_info.selected, { info = info })
local windata = api.nvim__complete_set(cmp_info.selected, { info = info })
update_popup_window(windata.winid, windata.bufnr, kind)
end
end, bufnr)

View File

@@ -295,12 +295,12 @@ function M.on_diagnostic(error, result, ctx)
if error ~= nil then
if error.code == protocol.ErrorCodes.ServerCancelled then
if error.data == nil or error.data.retriggerRequest ~= false then
local client = assert(lsp.get_client_by_id(ctx.client_id))
local client = assert(lsp.get_client_by_id(client_id))
---@diagnostic disable-next-line: param-type-mismatch
client:request(ctx.method, ctx.params, nil, ctx.bufnr)
end
else
vim.lsp.log.error('diagnostics', error)
lsp.log.error('diagnostics', error)
end
return
end
@@ -354,7 +354,7 @@ end
---@package
---@param client_id integer Client ID to refresh
function Diagnostics:refresh(client_id)
local client = vim.lsp.get_client_by_id(client_id)
local client = lsp.get_client_by_id(client_id)
local method = 'textDocument/diagnostic'
local clients = { client }
@@ -389,7 +389,7 @@ function M.on_refresh(err, _, ctx)
if err then
return vim.NIL
end
local client = vim.lsp.get_client_by_id(ctx.client_id)
local client = lsp.get_client_by_id(ctx.client_id)
if client == nil then
return vim.NIL
end

View File

@@ -44,6 +44,7 @@ local function show_message_notification(params, ctx)
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
---@diagnostic disable-next-line: deprecated
RCS['workspace/executeCommand'] = function(_, _, _)
-- Error handling is done implicitly by wrapping all handlers; see end of this file
end
@@ -120,6 +121,8 @@ RSC['window/showMessageRequest'] = function(_, params, ctx)
coroutine.resume(co, choice or vim.NIL)
end)
end)
-- The coroutine.running() check above guards this yield.
---@diagnostic disable-next-line: await-in-sync
return coroutine.yield()
else
local option_strings = { params.message, '\nRequest Actions:' }
@@ -259,11 +262,13 @@ NSC['textDocument/publishDiagnostics'] = function(...)
end
--- @private
---@diagnostic disable-next-line: deprecated
RCS['textDocument/diagnostic'] = function(...)
return vim.lsp.diagnostic.on_diagnostic(...)
end
--- @private
---@diagnostic disable-next-line: deprecated
RCS['textDocument/inlayHint'] = function(...)
return vim.lsp.inlay_hint.on_inlayhint(...)
end
@@ -304,6 +309,7 @@ end
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
---@diagnostic disable-next-line: deprecated
RCS['textDocument/documentSymbol'] = response_to_list(
util.symbols_to_items,
'document symbols',
@@ -315,12 +321,14 @@ RCS['textDocument/documentSymbol'] = response_to_list(
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
---@diagnostic disable-next-line: deprecated
RCS['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols', function(ctx)
return string.format("Symbols matching '%s'", ctx.params.query)
end)
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
---@diagnostic disable-next-line: deprecated
RCS['textDocument/rename'] = function(_, result, ctx)
if not result then
vim.notify("Language server couldn't provide rename result", vim.log.levels.INFO)
@@ -332,6 +340,7 @@ end
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
---@diagnostic disable-next-line: deprecated
RCS['textDocument/rangeFormatting'] = function(_, result, ctx)
if not result then
return
@@ -342,6 +351,7 @@ end
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
---@diagnostic disable-next-line: deprecated
RCS['textDocument/formatting'] = function(_, result, ctx)
if not result then
return
@@ -352,6 +362,7 @@ end
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
---@diagnostic disable-next-line: deprecated
RCS['textDocument/completion'] = function(_, result, _)
if vim.tbl_isempty(result or {}) then
return
@@ -495,6 +506,7 @@ RCS['textDocument/signatureHelp'] = M.signature_help
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
---@diagnostic disable-next-line: deprecated
RCS['textDocument/documentHighlight'] = function(_, result, ctx)
if not result then
return
@@ -547,10 +559,12 @@ end
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls
---@diagnostic disable-next-line: deprecated
RCS['callHierarchy/incomingCalls'] = make_call_hierarchy_handler('from')
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls
---@diagnostic disable-next-line: deprecated
RCS['callHierarchy/outgoingCalls'] = make_call_hierarchy_handler('to')
--- Displays type hierarchy in the quickfix window.
@@ -584,10 +598,12 @@ end
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#typeHierarchy_incomingCalls
---@diagnostic disable-next-line: deprecated
RCS['typeHierarchy/subtypes'] = make_type_hierarchy_handler()
--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#typeHierarchy_outgoingCalls
---@diagnostic disable-next-line: deprecated
RCS['typeHierarchy/supertypes'] = make_type_hierarchy_handler()
--- @see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage
@@ -690,6 +706,7 @@ end
--- @nodoc
--- @type table<string, lsp.Handler>
---@diagnostic disable-next-line: deprecated
M = vim.tbl_extend('force', M, RSC, NSC, RCS)
-- Add boilerplate error validation and logging for all of these.

View File

@@ -227,7 +227,7 @@ end
---@param enable boolean? `true` or `nil` to enable, `false` to disable.
---@param filter vim.lsp.capability.enable.Filter?
function M.enable(enable, filter)
vim.lsp._capability.enable('linked_editing_range', enable, filter)
lsp._capability.enable('linked_editing_range', enable, filter)
end
return M

View File

@@ -37,7 +37,7 @@ local function on_type_formatting(err, result, ctx)
return
end
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
local client = assert(lsp.get_client_by_id(ctx.client_id))
util.apply_text_edits(result, ctx.bufnr, client.offset_encoding)
end
@@ -246,8 +246,10 @@ function M.enable(enable, filter)
filter = filter or {}
if filter.client_id then
local client =
assert(lsp.get_client_by_id(filter.client_id), 'Client not found for id ' .. filter.client_id)
local client = lsp.get_client_by_id(filter.client_id)
if not client then
error('Client not found for id ' .. filter.client_id)
end
toggle_for_client(enable, client)
else
toggle_globally(enable)

View File

@@ -111,6 +111,7 @@ local function tokens_to_ranges(data, bufnr, client, request, ranges)
-- If it's stale, we don't resume the coroutine so it'll be garbage collected.
if
version == util.buf_versions[bufnr]
---@diagnostic disable-next-line: preferred-local-alias
and request_id == request.request_id
and api.nvim_buf_is_valid(bufnr)
then
@@ -457,7 +458,7 @@ end
--- @return lsp.Range
function STHighlighter:get_overscan_range()
local wins = vim.fn.win_findbuf(self.bufnr)
local num_lines = vim.api.nvim_buf_line_count(self.bufnr)
local num_lines = api.nvim_buf_line_count(self.bufnr)
local min_start, max_end = nil, nil
for _, win in ipairs(wins) do
@@ -775,7 +776,7 @@ end
---@private
---@param state STClientState
function STHighlighter:reset_timer(state)
function STHighlighter.reset_timer(_, state)
local timer = state.timer
if timer then
state.timer = nil

View File

@@ -106,8 +106,8 @@ local function compute_start_range(
)
position_encoding = position_encoding or 'utf-8'
local char_idx --- @type integer?
local byte_idx --- @type integer?
local char_idx --- @type integer
local byte_idx --- @type integer
-- If firstline == lastline, no existing text is changed. All edit operations
-- occur on a new line pointed to by lastline. This occurs during insertion of
-- new lines(O), the new newline is inserted at the line indicated by

View File

@@ -70,6 +70,8 @@ local function get_border_size(opts)
-- border specified as a list of border characters
return e
end
-- EmmyLua rejects `never` as a subtype of the declared string result.
---@diagnostic disable-next-line: return-type-mismatch
return border_error(border)
end
@@ -280,10 +282,10 @@ function M.apply_text_edits(text_edits, bufnr, position_encoding, change_annotat
'change_annotations must be provided for annotated text edits'
)
local annotation = assert(
change_annotations[text_edit.annotationId],
string.format('No change annotation found for ID: %s', text_edit.annotationId)
)
local annotation = change_annotations[text_edit.annotationId]
if not annotation then
error(string.format('No change annotation found for ID: %s', text_edit.annotationId))
end
if annotation.needsConfirmation then
confirmations[text_edit.annotationId] = (confirmations[text_edit.annotationId] or 0) + 1
@@ -365,7 +367,7 @@ function M.apply_text_document_edit(
position_encoding,
change_annotations
)
vim.validate('position_encoding', position_encoding, 'string')
validate('position_encoding', position_encoding, 'string')
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
@@ -548,8 +550,8 @@ end
---@param position_encoding 'utf-8'|'utf-16'|'utf-32' (required)
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit, position_encoding)
vim.validate('workspace_edit', workspace_edit, 'table')
vim.validate('position_encoding', position_encoding, 'string')
validate('workspace_edit', workspace_edit, 'table')
validate('position_encoding', position_encoding, 'string')
if workspace_edit.documentChanges then
for idx, change in ipairs(workspace_edit.documentChanges) do
@@ -597,6 +599,7 @@ end
--- Note that if the input is of type `MarkupContent` and its kind is `plaintext`,
--- then the corresponding value is returned without further modifications.
---
---@diagnostic disable-next-line: deprecated
---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent
---@param contents string[]? List of strings to extend with converted lines. Defaults to {}.
---@return string[] extended with lines of converted markdown.
@@ -867,7 +870,7 @@ end
---@param opts? vim.lsp.util.show_document.Opts
---@return boolean `true` if succeeded
function M.show_document(location, position_encoding, opts)
vim.validate('position_encoding', position_encoding, 'string')
validate('position_encoding', position_encoding, 'string')
-- location may be Location or LocationLink
local uri = location.uri or location.targetUri
@@ -919,10 +922,10 @@ function M.show_document(location, position_encoding, opts)
-- nvim_win_set_cursor clamps to last char at EOL. In insert mode the cursor
-- should be past the last char (append position).
if vim.api.nvim_get_mode().mode == 'i' then
if api.nvim_get_mode().mode == 'i' then
local line = api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or ''
if col >= #line then
vim.api.nvim_feedkeys(vim.keycode('<End>'), 'n', false)
api.nvim_feedkeys(vim.keycode('<End>'), 'n', false)
end
end
end
@@ -979,10 +982,10 @@ local function is_float(winnr)
end
---Returns true if the line is empty or only contains whitespace.
---@param line string
---@param line string?
---@return boolean
local function is_blank_line(line)
return line and line:match('^%s*$')
return line ~= nil and line:match('^%s*$') ~= nil
end
---Returns true if the line corresponds to a Markdown thematic break.
@@ -1131,7 +1134,7 @@ function M.stylize_markdown(bufnr, contents, opts)
--- @param line string
--- @param match {type:string,ft:string}
--- @return string
--- @return string?
local function match_end(line, match)
local pattern = matchers[match.type]
return line:match(string.format('^%%s*%s%%s*$', pattern[3]))
@@ -1733,7 +1736,7 @@ end)
---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@return vim.quickfix.entry[] # See |setqflist()| for the format
function M.locations_to_items(locations, position_encoding)
vim.validate('position_encoding', position_encoding, 'string')
validate('position_encoding', position_encoding, 'string')
local items = {} --- @type vim.quickfix.entry[]
@@ -1793,7 +1796,7 @@ end
---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@return vim.quickfix.entry[] # See |setqflist()| for the format
function M.symbols_to_items(symbols, bufnr, position_encoding)
vim.validate('position_encoding', position_encoding, 'string')
validate('position_encoding', position_encoding, 'string')
bufnr = vim._resolve_bufnr(bufnr)
@@ -1814,6 +1817,7 @@ function M.symbols_to_items(symbols, bufnr, position_encoding)
if filename and range then
local kind = protocol.SymbolKind[symbol.kind] or 'Unknown'
---@diagnostic disable-next-line: deprecated
local is_deprecated = not vim.isnil(symbol.deprecated or nil)
or (
not vim.isnil(symbol.tags)
@@ -1958,7 +1962,7 @@ end
---@return integer `position_encoding` index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(buf, row, col, position_encoding)
vim.deprecate('vim.lsp.util.character_offset', 'vim.str_utfindex', '0.14')
vim.validate('position_encoding', position_encoding, 'string')
validate('position_encoding', position_encoding, 'string')
local line = get_line(buf, row)
return vim.str_utfindex(line, position_encoding, col, false)

View File

@@ -878,7 +878,7 @@ local function install_list(plug_list, confirm)
trigger_events(plug_list, 'PackChangedPre', 'install')
run_list(plug_list, do_install, 'Installing plugins')
local installed = vim.tbl_filter(function(p) --- @param p vim.pack.Plug
return p.info.installed
return p.info.installed == true
end, plug_list)
trigger_events(installed, 'PackChanged', 'install')
end
@@ -1023,7 +1023,7 @@ local function lock_sync(confirm, specs)
-- Compute installed plugins
local plug_dir = get_plug_dir()
if vim.uv.fs_stat(plug_dir) == nil then
if uv.fs_stat(plug_dir) == nil then
vim.fn.mkdir(plug_dir, 'p')
end
@@ -1351,7 +1351,7 @@ end
--- @param bufnr integer
--- @return table<string,boolean>
local function get_update_map(bufnr)
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
--- @type table<string,boolean>, boolean
local res, is_in_update = {}, false
for _, l in ipairs(lines) do
@@ -1383,7 +1383,7 @@ local function update_list(plug_list)
run_list(plug_list, do_update, 'Applying updates')
local updated = vim.tbl_filter(function(p) --- @param p vim.pack.Plug
return p.info.updated
return p.info.updated == true
end, plug_list)
trigger_events(updated, 'PackChanged', 'update')
end

View File

@@ -79,11 +79,11 @@ end
--- @param line string Buffer line to find a link in
--- @param pattern string Pattern matching link location and contents, like `'^Path: +()(.+)()$'`
--- @param link_type "commit"|"path"|"src"|"tag"
--- @param lnum number Line number in a buffer
--- @param lnum integer Line number in a buffer
--- @param src string Plugin source
--- @return vim.pack.lsp.DocumentLink? # A link structure according to the LSP specification
local function match_link(line, pattern, link_type, lnum, src)
--- @type number?, string?, number?
--- @type integer?, string?, integer?
local from, match, to = line:match(pattern)
if not (from and match and to) then
return nil

View File

@@ -94,7 +94,7 @@ function M.get_lines(buf, rows)
end
-- Get the data from the file.
local success, data = pcall(vim.fn.readblob, vim.api.nvim_buf_get_name(buf))
local success, data = pcall(vim.fn.readblob, api.nvim_buf_get_name(buf))
if not success then
return row_line
end

View File

@@ -199,7 +199,7 @@ end
---@param buf integer
---@param range Range
---@returns string
---@return string
local function buf_range_get_text(buf, range)
local start_row, start_col, end_row, end_col = M._range.unpack4(range)
local append_newline = end_col == 0 and start_row ~= end_row

View File

@@ -80,6 +80,8 @@ function M.intersection(r1, r2)
if #r1 == 4 or #r2 == 4 then
local rs = M.cmp_pos.le(r1[1], r1[2], r2[1], r2[2]) and r2 or r1
local re = M.cmp_pos.ge(r1[3], r1[4], r2[3], r2[4]) and r2 or r1
-- This branch implements the Range4 overload.
---@diagnostic disable-next-line: return-type-mismatch
return { rs[1], rs[2], re[3], re[4] }
end
@@ -95,6 +97,8 @@ function M.unpack4(r)
return r[1], 0, r[2], 0
end
local off_1 = #r == 6 and 1 or 0
-- EmmyLua does not narrow tuple fields from the range length.
---@diagnostic disable-next-line: return-type-mismatch
return r[1], r[2], r[3 + off_1], r[4 + off_1]
end

View File

@@ -148,9 +148,8 @@ function TSTreeView:new(buf, lang)
},
}
setmetatable(t, self)
self.__index = self
return t
return setmetatable(t, self)
end
local decor_ns = api.nvim_create_namespace('nvim.treesitter.dev')

View File

@@ -2,7 +2,7 @@ local api = vim.api
local M = {}
---@type table<string,string>
---@type table<string,string?>
local ft_to_lang = {
help = 'vimdoc',
checkhealth = 'vimdoc',

View File

@@ -412,6 +412,7 @@ end
--- @return Range6[] changes
--- @return integer no_regions_parsed
--- @return number total_parse_time
--- @async
function LanguageTree:_parse_regions(range, thread_state)
local changes = {}
local no_regions_parsed = 0
@@ -636,12 +637,15 @@ function LanguageTree:parse(range, on_parse)
if on_parse then
return self:_async_parse(range, on_parse)
end
-- Without a timeout, parsing never yields.
---@diagnostic disable-next-line: await-in-sync
local trees, _ = self:_parse(range, {})
return trees
end
---@param thread_state ParserThreadState
---@param time integer
---@async
function LanguageTree:_subtract_time(thread_state, time)
thread_state.timeout = thread_state.timeout and math.max(thread_state.timeout - time, 0)
if thread_state.timeout == 0 then
@@ -654,6 +658,7 @@ end
--- @param thread_state ParserThreadState
--- @return table<integer, TSTree> trees
--- @return boolean finished
--- @async
function LanguageTree:_parse(range, thread_state)
if self:is_valid(nil, type(range) == 'table' and range or nil) then
self:_log('valid')
@@ -1088,6 +1093,7 @@ end
--- @param range Range|Range[]|true
--- @param thread_state ParserThreadState
--- @return table<string, Range6[][]>
--- @async
function LanguageTree:_get_injections(range, thread_state)
if not self._injection_query or #self._injection_query.captures == 0 then
self._processed_injection_region = entire_document_range

View File

@@ -830,7 +830,7 @@ end
---@param captures table<integer, TSNode[]>
---@param source integer|string
---@return boolean whether the predicates match
function Query:_match_predicates(predicates, pattern_i, captures, source)
function Query._match_predicates(predicates, pattern_i, captures, source)
for _, predicate in ipairs(predicates) do
local processed_name = predicate[1]
local should_match = predicate[2]
@@ -856,7 +856,7 @@ end
---@param source integer|string
---@param captures table<integer, TSNode[]>
---@return vim.treesitter.query.TSMetadata metadata
function Query:_apply_directives(directives, pattern_i, captures, source)
function Query._apply_directives(_, directives, pattern_i, captures, source)
---@type vim.treesitter.query.TSMetadata
local metadata = {}
@@ -979,7 +979,7 @@ function Query:iter_captures(node, source, start_row, end_row, opts)
local captures = match:captures()
local predicates = processed_pattern.predicates
if not self:_match_predicates(predicates, pattern_i, captures, source) then
if not self._match_predicates(predicates, pattern_i, captures, source) then
cursor:remove_match(match_id)
local row, col = captured_node:range()
@@ -1081,7 +1081,7 @@ function Query:iter_matches(node, source, start, stop, opts)
local metadata = {}
if processed_pattern then
local predicates = processed_pattern.predicates
if not self:_match_predicates(predicates, pattern_i, captures, source) then
if not self._match_predicates(predicates, pattern_i, captures, source) then
cursor:remove_match(match_id)
return iter() -- tail call: try next match
end

View File

@@ -243,6 +243,8 @@ local function cterm_to_hex(colorstr)
cterm_color_cache = cterm_16_to_hex
end
end
-- EmmyLua retains the failed lookup narrowing after the cache is updated.
---@diagnostic disable-next-line: return-type-mismatch
return cterm_color_cache[color]
end

View File

@@ -883,9 +883,9 @@ void ui_refresh(void)
local query0 = vim.treesitter.query.parse('c', query)
local match_preds = query0._match_predicates
local called = 0
function query0:_match_predicates(...)
function query0._match_predicates(...)
called = called + 1
return match_preds(self, ...)
return match_preds(...)
end
local parser = vim.treesitter.get_parser(0, 'c')
local root = parser:parse()[1]:root()