Files
neovim/runtime/lua/coxpcall.lua
Lewis Russell d039f19af5 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
2026-09-09 22:31:58 +01:00

130 lines
4.1 KiB
Lua

-------------------------------------------------------------------------------
-- (Not needed for LuaJIT or Lua 5.2+)
--
-- Coroutine safe xpcall and pcall versions
--
-- https://keplerproject.github.io/coxpcall/
--
-- Encapsulates the protected calls with a coroutine based loop, so errors can
-- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines
-- yielding inside the call to pcall or xpcall.
--
-- Authors: Roberto Ierusalimschy and Andre Carregal
-- Contributors: Thomas Harning Jr., Ignacio Burgueño, Fabio Mascarenhas
--
-- Copyright 2005 - Kepler Project
--
-- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Checks if (x)pcall function is coroutine safe
-------------------------------------------------------------------------------
local function isCoroutineSafe(func)
local co = coroutine.create(function()
return func(coroutine.yield, function() end)
end)
coroutine.resume(co)
return coroutine.resume(co)
end
-- No need to do anything if pcall and xpcall are already safe.
if isCoroutineSafe(pcall) and isCoroutineSafe(xpcall) then
_G.copcall = pcall
_G.coxpcall = xpcall
return { pcall = pcall, xpcall = xpcall, running = coroutine.running }
end
-------------------------------------------------------------------------------
-- Implements xpcall with coroutines
-------------------------------------------------------------------------------
---@diagnostic disable-next-line
local performResume
local oldpcall, oldxpcall = pcall, xpcall
local pack = table.pack or function(...) return {n = select("#", ...), ...} end
local unpack = table.unpack or unpack
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, (...)), ...)
end
if coroutine.status(co) == 'suspended' then
return performResume(err, co, coroutine.yield(...))
else
return true, ...
end
end
--- @async
function performResume(err, co, ...)
return handleReturnValue(err, co, coroutine.resume(co, ...))
end
--- @diagnostic disable-next-line: unused-vararg
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
if err == id then
return oldpcall(f, ...)
else
if select("#", ...) > 0 then
local oldf, params = f, pack(...)
f = function() return oldf(unpack(params, 1, params.n)) end
end
return oldxpcall(f, err)
end
else
local res, co = oldpcall(coroutine.create, f)
if not res then
local newf = function(...) return f(...) end
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
--- @param coro? thread
local function corunning(coro)
if coro ~= nil then
assert(type(coro)=="thread", "Bad argument; expected thread, got: "..type(coro))
else
coro = running()
end
while coromap[coro] do
coro = coromap[coro]
end
if coro == "mainthread" then return nil end
return coro
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
return { pcall = copcall, xpcall = coxpcall, running = corunning }