Regenerate nvim config
This commit is contained in:
@ -0,0 +1,131 @@
|
||||
---Functions are compatible with LuaJIT's.
|
||||
---@class PromiseAsyncCompat
|
||||
local M = {}
|
||||
|
||||
---@return boolean
|
||||
function M.is51()
|
||||
return _G._VERSION:sub(-3) == '5.1' and not jit
|
||||
end
|
||||
|
||||
if table.pack then
|
||||
M.pack = table.pack
|
||||
else
|
||||
M.pack = function(...)
|
||||
return {n = select('#', ...), ...}
|
||||
end
|
||||
end
|
||||
|
||||
if table.unpack then
|
||||
M.unpack = table.unpack
|
||||
else
|
||||
M.unpack = unpack
|
||||
end
|
||||
---@diagnostic enable: deprecated
|
||||
|
||||
if M.is51() then
|
||||
local _pcall, _xpcall = pcall, xpcall
|
||||
local utils = require('promise-async.utils')
|
||||
|
||||
local function yieldInCoroutine(thread, co, success, ...)
|
||||
if coroutine.status(co) == 'suspended' then
|
||||
return yieldInCoroutine(thread, co, coroutine.resume(co, coroutine.yield(...)))
|
||||
end
|
||||
return success, ...
|
||||
end
|
||||
|
||||
local function doPcall(thread, f, ...)
|
||||
local typ = type(f)
|
||||
local ok, fn = utils.getCallable(f, typ)
|
||||
if not ok then
|
||||
return false, ('attempt to call a %s value'):format(typ)
|
||||
end
|
||||
local co = coroutine.create(function(...)
|
||||
return fn(...)
|
||||
end)
|
||||
return yieldInCoroutine(thread, co, coroutine.resume(co, ...))
|
||||
end
|
||||
|
||||
M.pcall = function(f, ...)
|
||||
local thread = coroutine.running()
|
||||
if not thread then
|
||||
return _pcall(f, ...)
|
||||
end
|
||||
return doPcall(thread, f, ...)
|
||||
end
|
||||
|
||||
local function xpcallCatch(msgh, success, ...)
|
||||
if success then
|
||||
return true, ...
|
||||
end
|
||||
local ok, result = _pcall(msgh, ...)
|
||||
return false, ok and result or 'error in error handling'
|
||||
end
|
||||
|
||||
M.xpcall = function(f, msgh, ...)
|
||||
local thread = coroutine.running()
|
||||
if not thread then
|
||||
return _xpcall(f, msgh, ...)
|
||||
end
|
||||
return xpcallCatch(msgh, doPcall(thread, f, ...))
|
||||
end
|
||||
else
|
||||
M.pcall = pcall
|
||||
M.xpcall = xpcall
|
||||
end
|
||||
|
||||
if setfenv then
|
||||
M.setfenv = setfenv
|
||||
M.getfenv = getfenv
|
||||
else
|
||||
local function findENV(f)
|
||||
local name = ''
|
||||
local value
|
||||
local up = 1
|
||||
while name do
|
||||
name, value = debug.getupvalue(f, up)
|
||||
if name == '_ENV' then
|
||||
return up, value
|
||||
end
|
||||
up = up + 1;
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function envHelper(f, name)
|
||||
if type(f) == 'number' then
|
||||
if f < 0 then
|
||||
error(([[bad argument #1 to '%s' (level must be non-negative)]]):format(name), 3)
|
||||
end
|
||||
local ok, dInfo = pcall(debug.getinfo, f + 2, 'f')
|
||||
if not ok or not dInfo then
|
||||
error(([[bad argument #1 to '%s' (invalid level)]]):format(name), 3)
|
||||
end
|
||||
f = dInfo.func
|
||||
elseif type(f) ~= 'function' then
|
||||
error(([[bad argument #1 to '%s' (number expected, got %s)]]):format(name, type(f)), 3)
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
function M.setfenv(f, table)
|
||||
f = envHelper(f, 'setfenv')
|
||||
local up = findENV(f)
|
||||
if up > 0 then
|
||||
debug.upvaluejoin(f, up, function()
|
||||
return table
|
||||
end, 1)
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
function M.getfenv(f)
|
||||
if f == 0 or f == nil then
|
||||
return _G
|
||||
end
|
||||
f = envHelper(f, 'getfenv')
|
||||
local up, value = findENV(f)
|
||||
return up > 0 and value or _G
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,115 @@
|
||||
local errorId = {}
|
||||
|
||||
---@class PromiseAsyncError
|
||||
---@field err any
|
||||
---@field queue string[]
|
||||
---@field index number
|
||||
local Error = {_id = errorId}
|
||||
Error.__index = Error
|
||||
|
||||
local function dump(o, limit)
|
||||
local s
|
||||
if type(o) ~= 'table' then
|
||||
s = tostring(o)
|
||||
else
|
||||
local meta = getmetatable(o)
|
||||
if meta and meta.__tostring then
|
||||
s = tostring(o)
|
||||
else
|
||||
if limit > 0 then
|
||||
local fmt = '%s [%s] = %s,'
|
||||
s = '{'
|
||||
for k, v in pairs(o) do
|
||||
if type(k) ~= 'number' then
|
||||
k = '"' .. k .. '"'
|
||||
end
|
||||
s = fmt:format(s, k, dump(v, limit - 1))
|
||||
end
|
||||
s = s:sub(1, #s - 1) .. ' }'
|
||||
else
|
||||
s = '{...}'
|
||||
end
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function Error.isInstance(o)
|
||||
return type(o) == 'table' and o._id == errorId
|
||||
end
|
||||
|
||||
---@param thread? thread
|
||||
---@param level number
|
||||
---@param skipShortSrc? string
|
||||
---@return string?
|
||||
function Error.format(thread, level, skipShortSrc)
|
||||
local res
|
||||
local dInfo = thread and debug.getinfo(thread, level, 'nSl') or debug.getinfo(level, 'nSl')
|
||||
if dInfo then
|
||||
local name, shortSrc, currentline = dInfo.name, dInfo.short_src, dInfo.currentline
|
||||
if skipShortSrc == shortSrc then
|
||||
return
|
||||
end
|
||||
local detail
|
||||
if not name or name == '' then
|
||||
detail = ('in function <Anonymous:%d>'):format(dInfo.linedefined)
|
||||
else
|
||||
detail = ([[in function '%s']]):format(name)
|
||||
end
|
||||
res = (' %s:%d: %s'):format(shortSrc, currentline, detail)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
---@param err any
|
||||
---@return PromiseAsyncError
|
||||
function Error.new(err)
|
||||
local o = setmetatable({}, Error)
|
||||
o.err = err
|
||||
o.queue = {}
|
||||
o.index = 0
|
||||
return o
|
||||
end
|
||||
|
||||
function Error:__tostring()
|
||||
local errMsg = dump(self.err, 1)
|
||||
if #self.queue == 0 then
|
||||
return errMsg
|
||||
end
|
||||
local t = {}
|
||||
for i = 1, self.index do
|
||||
table.insert(t, self.queue[i])
|
||||
end
|
||||
table.insert(t, errMsg)
|
||||
if self.index < #self.queue then
|
||||
table.insert(t, 'stack traceback:')
|
||||
end
|
||||
for i = self.index + 1, #self.queue do
|
||||
table.insert(t, self.queue[i])
|
||||
end
|
||||
return table.concat(t, '\n')
|
||||
end
|
||||
|
||||
---@param value string
|
||||
function Error:unshift(value)
|
||||
if value then
|
||||
self.index = self.index + 1
|
||||
table.insert(self.queue, 1, value)
|
||||
end
|
||||
return #self.queue
|
||||
end
|
||||
|
||||
---@param value? string
|
||||
function Error:push(value)
|
||||
if value then
|
||||
table.insert(self.queue, value)
|
||||
end
|
||||
return #self.queue
|
||||
end
|
||||
|
||||
---@return any
|
||||
function Error:peek()
|
||||
return self.err
|
||||
end
|
||||
|
||||
return Error
|
||||
@ -0,0 +1,85 @@
|
||||
local uv = require('luv')
|
||||
|
||||
---@class PromiseAsyncLoop
|
||||
---@field tick userdata
|
||||
---@field tickCallbacks function[]
|
||||
---@field tickStarted boolean
|
||||
---@field idle userdata
|
||||
---@field idleCallbacks function[]
|
||||
---@field idleStarted boolean
|
||||
local EventLoop = {
|
||||
tick = uv.new_timer(),
|
||||
tickCallbacks = {},
|
||||
tickStarted = false,
|
||||
idle = uv.new_idle(),
|
||||
idleCallbacks = {},
|
||||
idleStarted = false
|
||||
}
|
||||
|
||||
function EventLoop.setTimeout(callback, ms)
|
||||
local timer = uv.new_timer()
|
||||
timer:start(ms, 0, function()
|
||||
timer:close()
|
||||
EventLoop.callWrapper(callback)
|
||||
end)
|
||||
return timer
|
||||
end
|
||||
|
||||
local function runTick()
|
||||
EventLoop.tickStarted = true
|
||||
local callbacks = EventLoop.tickCallbacks
|
||||
EventLoop.tickCallbacks = {}
|
||||
for _, cb in ipairs(callbacks) do
|
||||
EventLoop.callWrapper(cb)
|
||||
end
|
||||
if #EventLoop.tickCallbacks > 0 then
|
||||
EventLoop.tick:start(0, 0, runTick)
|
||||
else
|
||||
EventLoop.tickStarted = false
|
||||
end
|
||||
end
|
||||
|
||||
function EventLoop.nextTick(callback)
|
||||
table.insert(EventLoop.tickCallbacks, callback)
|
||||
if not EventLoop.tickStarted then
|
||||
EventLoop.tick:start(0, 0, runTick)
|
||||
end
|
||||
end
|
||||
|
||||
local function runIdle()
|
||||
EventLoop.idleStarted = true
|
||||
local callbacks = EventLoop.idleCallbacks
|
||||
EventLoop.idleCallbacks = {}
|
||||
for _, cb in ipairs(callbacks) do
|
||||
EventLoop.callWrapper(cb)
|
||||
end
|
||||
if #EventLoop.idleCallbacks > 0 then
|
||||
EventLoop.idle:start(runIdle)
|
||||
else
|
||||
EventLoop.idle:stop()
|
||||
EventLoop.idleStarted = false
|
||||
end
|
||||
end
|
||||
|
||||
function EventLoop.nextIdle(callback)
|
||||
EventLoop.nextTick(function()
|
||||
table.insert(EventLoop.idleCallbacks, callback)
|
||||
if not EventLoop.idleStarted then
|
||||
EventLoop.idle:start(runIdle)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if vim and type(vim.schedule) == 'function' then
|
||||
EventLoop.callWrapper = vim.schedule
|
||||
else
|
||||
function EventLoop.callWrapper(fn)
|
||||
local ok, res = pcall(fn)
|
||||
if not ok then
|
||||
-- luv can't handle object with __tostring filed
|
||||
error(tostring(res))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return EventLoop
|
||||
@ -0,0 +1,33 @@
|
||||
---@class PromiseAsyncUtils
|
||||
local M = {}
|
||||
|
||||
---@param o any
|
||||
---@param expectedType string
|
||||
function M.assertType(o, expectedType)
|
||||
local gotType = type(o)
|
||||
local fmt = '%s expected, got %s'
|
||||
return assert(gotType == expectedType, fmt:format(expectedType, gotType))
|
||||
end
|
||||
|
||||
---@param o any
|
||||
---@param typ? string
|
||||
---@return boolean, function|table|any
|
||||
function M.getCallable(o, typ)
|
||||
local ok
|
||||
local f
|
||||
local t = typ or type(o)
|
||||
if t == 'function' then
|
||||
ok, f = true, o
|
||||
elseif t ~= 'table' then
|
||||
ok, f = false, o
|
||||
else
|
||||
local meta = getmetatable(o)
|
||||
ok = meta and type(meta.__call) == 'function'
|
||||
if ok then
|
||||
f = meta.__call
|
||||
end
|
||||
end
|
||||
return ok, f
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user