aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/coxpcall.lua
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
commit1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch)
treecd08258054db80bb9a11b1061bb091c70b76926a /runtime/lua/coxpcall.lua
parenteaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.gz
rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.bz2
rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.zip
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'runtime/lua/coxpcall.lua')
-rw-r--r--runtime/lua/coxpcall.lua108
1 files changed, 108 insertions, 0 deletions
diff --git a/runtime/lua/coxpcall.lua b/runtime/lua/coxpcall.lua
new file mode 100644
index 0000000000..6b179f1ef0
--- /dev/null
+++ b/runtime/lua/coxpcall.lua
@@ -0,0 +1,108 @@
+-------------------------------------------------------------------------------
+-- Coroutine safe xpcall and pcall versions
+--
+-- 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
+ copcall = pcall
+ coxpcall = xpcall
+ return { pcall = pcall, xpcall = xpcall, running = coroutine.running }
+end
+
+-------------------------------------------------------------------------------
+-- Implements xpcall with coroutines
+-------------------------------------------------------------------------------
+local performResume, handleReturnValue
+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
+local coromap = setmetatable({}, { __mode = "k" })
+
+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
+
+function performResume(err, co, ...)
+ return handleReturnValue(err, co, coroutine.resume(co, ...))
+end
+
+local function id(trace, ...)
+ return trace
+end
+
+function 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
+ return performResume(err, co, ...)
+ end
+end
+
+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
+-------------------------------------------------------------------------------
+
+function copcall(f, ...)
+ return coxpcall(f, id, ...)
+end
+
+return { pcall = copcall, xpcall = coxpcall, running = corunning }