mirror of
https://github.com/kepler155c/opus
synced 2025-01-16 02:15:42 +00:00
environments, error messages, and stack traces, oh my!
Changed the way processes are launched. multishell.openTab and kernel.run now accept the current environment as a parameter. That new process inherits a copy of the passed environment. Reduces complexity as the calling process is not required to create a suitable env. Stack traces have been greatly improved and now include the stack for coroutines that error.
This commit is contained in:
parent
bd911e80e8
commit
8279c1ae12
@ -255,7 +255,7 @@ function page.packetSlide:eventHandler(event)
|
|||||||
page:setFocus(page.packetGrid)
|
page:setFocus(page.packetGrid)
|
||||||
|
|
||||||
elseif event.type == 'packet_lua' then
|
elseif event.type == 'packet_lua' then
|
||||||
multishell.openTab({ path = 'sys/apps/Lua.lua', args = { self.currentPacket.message }, focused = true })
|
multishell.openTab(_ENV, { path = 'sys/apps/Lua.lua', args = { self.currentPacket.message }, focused = true })
|
||||||
|
|
||||||
elseif event.type == 'prev_packet' then
|
elseif event.type == 'prev_packet' then
|
||||||
local c = self.currentPacket
|
local c = self.currentPacket
|
||||||
|
@ -12,6 +12,7 @@ local page = UI.Page {
|
|||||||
buttons = {
|
buttons = {
|
||||||
{ text = 'Activate', event = 'activate' },
|
{ text = 'Activate', event = 'activate' },
|
||||||
{ text = 'Terminate', event = 'terminate' },
|
{ text = 'Terminate', event = 'terminate' },
|
||||||
|
{ text = 'Inspect', event = 'inspect' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
grid = UI.ScrollingGrid {
|
grid = UI.ScrollingGrid {
|
||||||
@ -49,6 +50,12 @@ local page = UI.Page {
|
|||||||
multishell.setFocus(t.uid)
|
multishell.setFocus(t.uid)
|
||||||
elseif event.type == 'terminate' then
|
elseif event.type == 'terminate' then
|
||||||
multishell.terminate(t.uid)
|
multishell.terminate(t.uid)
|
||||||
|
elseif event.type == 'inspect' then
|
||||||
|
multishell.openTab(_ENV, {
|
||||||
|
path = 'sys/apps/Lua.lua',
|
||||||
|
args = { t },
|
||||||
|
focused = true,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if event.type == 'quit' then
|
if event.type == 'quit' then
|
||||||
|
@ -110,7 +110,7 @@ page = UI.Page {
|
|||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
|
|
||||||
elseif event.type == 'grid_select' then
|
elseif event.type == 'grid_select' then
|
||||||
multishell.openTab({
|
multishell.openTab(_ENV, {
|
||||||
path = 'sys/apps/Lua.lua',
|
path = 'sys/apps/Lua.lua',
|
||||||
args = { event.selected.raw },
|
args = { event.selected.raw },
|
||||||
focused = true,
|
focused = true,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
_G.requireInjector(_ENV)
|
|
||||||
|
|
||||||
local Event = require('opus.event')
|
local Event = require('opus.event')
|
||||||
local Util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
|
@ -31,21 +31,14 @@ local function snmpConnection(socket)
|
|||||||
socket:write('pong')
|
socket:write('pong')
|
||||||
|
|
||||||
elseif msg.type == 'script' then
|
elseif msg.type == 'script' then
|
||||||
local env = kernel.makeEnv()
|
kernel.run(_ENV, {
|
||||||
local fn, err = load(msg.args, 'script', nil, env)
|
chunk = msg.args,
|
||||||
if fn then
|
title = 'script',
|
||||||
kernel.run({
|
})
|
||||||
fn = fn,
|
|
||||||
env = env,
|
|
||||||
title = 'script',
|
|
||||||
})
|
|
||||||
else
|
|
||||||
_G.printError(err)
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif msg.type == 'scriptEx' then
|
elseif msg.type == 'scriptEx' then
|
||||||
local s, m = pcall(function()
|
local s, m = pcall(function()
|
||||||
local env = kernel.makeEnv()
|
local env = kernel.makeEnv(_ENV)
|
||||||
local fn, m = load(msg.args, 'script', nil, env)
|
local fn, m = load(msg.args, 'script', nil, env)
|
||||||
if not fn then
|
if not fn then
|
||||||
error(m)
|
error(m)
|
||||||
|
@ -41,12 +41,12 @@ local function telnetHost(socket, mode)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local shellThread = kernel.run({
|
local shellThread = kernel.run(_ENV, {
|
||||||
window = win,
|
window = win,
|
||||||
title = mode .. ' client',
|
title = mode .. ' client',
|
||||||
hidden = true,
|
hidden = true,
|
||||||
fn = function()
|
fn = function()
|
||||||
Util.run(kernel.makeEnv(), Alt.get('shell'), table.unpack(termInfo.program))
|
Util.run(kernel.makeEnv(_ENV), Alt.get('shell'), table.unpack(termInfo.program))
|
||||||
if socket.queue then
|
if socket.queue then
|
||||||
socket:write(socket.queue)
|
socket:write(socket.queue)
|
||||||
end
|
end
|
||||||
|
@ -6,16 +6,6 @@ local fs = _G.fs
|
|||||||
local settings = _G.settings
|
local settings = _G.settings
|
||||||
local shell = _ENV.shell
|
local shell = _ENV.shell
|
||||||
|
|
||||||
local sandboxEnv = { }
|
|
||||||
for k,v in pairs(_ENV) do
|
|
||||||
sandboxEnv[k] = v
|
|
||||||
end
|
|
||||||
sandboxEnv.package = nil
|
|
||||||
sandboxEnv.require = nil
|
|
||||||
sandboxEnv.arg = nil
|
|
||||||
sandboxEnv._ENV = nil
|
|
||||||
sandboxEnv.shell = shell
|
|
||||||
|
|
||||||
_G.requireInjector(_ENV)
|
_G.requireInjector(_ENV)
|
||||||
|
|
||||||
local trace = require('opus.trace')
|
local trace = require('opus.trace')
|
||||||
@ -51,7 +41,7 @@ local function run(...)
|
|||||||
local args = tokenise(...)
|
local args = tokenise(...)
|
||||||
local command = table.remove(args, 1) or error('No such program')
|
local command = table.remove(args, 1) or error('No such program')
|
||||||
local isUrl = not not command:match("^(https?:)")
|
local isUrl = not not command:match("^(https?:)")
|
||||||
local env = shell.makeEnv()
|
local env = shell.makeEnv(_ENV)
|
||||||
|
|
||||||
local path, loadFn
|
local path, loadFn
|
||||||
if isUrl then
|
if isUrl then
|
||||||
@ -64,7 +54,7 @@ local function run(...)
|
|||||||
|
|
||||||
local fn, err = loadFn(path, env)
|
local fn, err = loadFn(path, env)
|
||||||
if not fn then
|
if not fn then
|
||||||
error(err)
|
error(err, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
if _ENV.multishell then
|
if _ENV.multishell then
|
||||||
@ -287,13 +277,9 @@ function shell.getRunningInfo()
|
|||||||
return tProgramStack[#tProgramStack]
|
return tProgramStack[#tProgramStack]
|
||||||
end
|
end
|
||||||
|
|
||||||
function shell.setEnv(name, value)
|
-- convenience function for making a runnable env
|
||||||
_ENV[name] = value
|
function shell.makeEnv(env)
|
||||||
sandboxEnv[name] = value
|
env = setmetatable(Util.shallowCopy(env), { __index = _G })
|
||||||
end
|
|
||||||
|
|
||||||
function shell.makeEnv()
|
|
||||||
local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G })
|
|
||||||
_G.requireInjector(env)
|
_G.requireInjector(env)
|
||||||
return env
|
return env
|
||||||
end
|
end
|
||||||
@ -321,7 +307,6 @@ function shell.newTab(tabInfo, ...)
|
|||||||
|
|
||||||
if path then
|
if path then
|
||||||
tabInfo.path = path
|
tabInfo.path = path
|
||||||
tabInfo.env = shell.makeEnv()
|
|
||||||
tabInfo.args = args
|
tabInfo.args = args
|
||||||
tabInfo.title = fs.getName(path):match('([^%.]+)')
|
tabInfo.title = fs.getName(path):match('([^%.]+)')
|
||||||
|
|
||||||
@ -329,25 +314,21 @@ function shell.newTab(tabInfo, ...)
|
|||||||
table.insert(tabInfo.args, 1, tabInfo.path)
|
table.insert(tabInfo.args, 1, tabInfo.path)
|
||||||
tabInfo.path = 'sys/apps/shell.lua'
|
tabInfo.path = 'sys/apps/shell.lua'
|
||||||
end
|
end
|
||||||
return _ENV.multishell.openTab(tabInfo)
|
return _ENV.multishell.openTab(_ENV, tabInfo)
|
||||||
end
|
end
|
||||||
return nil, 'No such program'
|
return nil, 'No such program'
|
||||||
end
|
end
|
||||||
|
|
||||||
function shell.openTab(...)
|
if not _ENV.multishell then
|
||||||
-- needs to use multishell.launch .. so we can run with stock multishell
|
function shell.newTab()
|
||||||
local tWords = tokenise( ... )
|
error('Multishell is not available')
|
||||||
local sCommand = tWords[1]
|
|
||||||
if sCommand then
|
|
||||||
local sPath = shell.resolveProgram(sCommand)
|
|
||||||
if sPath == "sys/apps/shell.lua" then
|
|
||||||
return _ENV.multishell.launch(shell.makeEnv(), sPath, table.unpack(tWords, 2))
|
|
||||||
else
|
|
||||||
return _ENV.multishell.launch(shell.makeEnv(), "sys/apps/shell.lua", sCommand, table.unpack(tWords, 2))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function shell.openTab(...)
|
||||||
|
return shell.newTab({ }, ...)
|
||||||
|
end
|
||||||
|
|
||||||
function shell.openForegroundTab( ... )
|
function shell.openForegroundTab( ... )
|
||||||
return shell.newTab({ focused = true }, ...)
|
return shell.newTab({ focused = true }, ...)
|
||||||
end
|
end
|
||||||
|
@ -10,9 +10,8 @@ if multishell and multishell.getTabs then
|
|||||||
local tab = kernel.getFocused()
|
local tab = kernel.getFocused()
|
||||||
if tab and not tab.noTerminate then
|
if tab and not tab.noTerminate then
|
||||||
multishell.terminate(tab.uid)
|
multishell.terminate(tab.uid)
|
||||||
multishell.openTab({
|
multishell.openTab(tab.env, {
|
||||||
path = tab.path,
|
path = tab.path,
|
||||||
env = tab.env,
|
|
||||||
args = tab.args,
|
args = tab.args,
|
||||||
focused = true,
|
focused = true,
|
||||||
})
|
})
|
||||||
|
@ -39,7 +39,7 @@ local function systemLog()
|
|||||||
keyboard.removeHotkey('control-d')
|
keyboard.removeHotkey('control-d')
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.run({
|
kernel.run(_ENV, {
|
||||||
title = 'System Log',
|
title = 'System Log',
|
||||||
fn = systemLog,
|
fn = systemLog,
|
||||||
noTerminate = true,
|
noTerminate = true,
|
||||||
|
@ -15,7 +15,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function startNetwork()
|
local function startNetwork()
|
||||||
kernel.run({
|
kernel.run(_ENV, {
|
||||||
title = 'Net daemon',
|
title = 'Net daemon',
|
||||||
path = 'sys/apps/netdaemon.lua',
|
path = 'sys/apps/netdaemon.lua',
|
||||||
hidden = true,
|
hidden = true,
|
||||||
|
@ -8,7 +8,6 @@ local kernel = _G.kernel
|
|||||||
local keys = _G.keys
|
local keys = _G.keys
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
local printError = _G.printError
|
local printError = _G.printError
|
||||||
local shell = _ENV.shell
|
|
||||||
local window = _G.window
|
local window = _G.window
|
||||||
|
|
||||||
local parentTerm = _G.device.terminal
|
local parentTerm = _G.device.terminal
|
||||||
@ -18,7 +17,7 @@ local tabsDirty = false
|
|||||||
local closeInd = Util.getVersion() >= 1.76 and '\215' or '*'
|
local closeInd = Util.getVersion() >= 1.76 and '\215' or '*'
|
||||||
local multishell = { }
|
local multishell = { }
|
||||||
|
|
||||||
shell.setEnv('multishell', multishell)
|
_ENV.multishell = multishell
|
||||||
|
|
||||||
kernel.window.reposition(1, 2, w, h - 1)
|
kernel.window.reposition(1, 2, w, h - 1)
|
||||||
|
|
||||||
@ -93,22 +92,21 @@ function multishell.getTabs()
|
|||||||
return kernel.routines
|
return kernel.routines
|
||||||
end
|
end
|
||||||
|
|
||||||
function multishell.launch( tProgramEnv, sProgramPath, ... )
|
function multishell.launch(env, path, ...)
|
||||||
-- backwards compatibility
|
-- backwards compatibility
|
||||||
return multishell.openTab({
|
return multishell.openTab(env, {
|
||||||
env = tProgramEnv,
|
path = path,
|
||||||
path = sProgramPath,
|
|
||||||
args = { ... },
|
args = { ... },
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function multishell.openTab(tab)
|
function multishell.openTab(env, tab)
|
||||||
if not tab.title and tab.path then
|
if not tab.title and tab.path then
|
||||||
tab.title = fs.getName(tab.path):match('([^%.]+)')
|
tab.title = fs.getName(tab.path):match('([^%.]+)')
|
||||||
end
|
end
|
||||||
tab.title = tab.title or 'untitled'
|
tab.title = tab.title or 'untitled'
|
||||||
tab.window = tab.window or window.create(parentTerm, 1, 2, w, h - 1, false)
|
tab.window = tab.window or window.create(parentTerm, 1, 2, w, h - 1, false)
|
||||||
tab.onExit = function(self, result, err)
|
tab.onExit = tab.onExit or function(self, result, err)
|
||||||
if not result and err and err ~= 'Terminated' or (err and err ~= 0) then
|
if not result and err and err ~= 'Terminated' or (err and err ~= 0) then
|
||||||
self.terminal.setBackgroundColor(colors.black)
|
self.terminal.setBackgroundColor(colors.black)
|
||||||
if tonumber(err) then
|
if tonumber(err) then
|
||||||
@ -131,14 +129,17 @@ function multishell.openTab(tab)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local routine = kernel.run(tab)
|
local routine, message = kernel.run(env, tab)
|
||||||
|
|
||||||
if tab.focused then
|
if routine then
|
||||||
multishell.setFocus(routine.uid)
|
if tab.focused then
|
||||||
else
|
multishell.setFocus(routine.uid)
|
||||||
redrawMenu()
|
else
|
||||||
|
redrawMenu()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return routine.uid
|
|
||||||
|
return routine and routine.uid, message
|
||||||
end
|
end
|
||||||
|
|
||||||
function multishell.hideTab(tabId)
|
function multishell.hideTab(tabId)
|
||||||
@ -316,15 +317,22 @@ kernel.hook('mouse_scroll', function(_, eventData)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
kernel.hook('kernel_ready', function()
|
kernel.hook('kernel_ready', function()
|
||||||
overviewId = multishell.openTab({
|
overviewId = multishell.openTab(_ENV, {
|
||||||
path = config.launcher or 'sys/apps/Overview.lua',
|
path = 'sys/apps/shell.lua',
|
||||||
|
args = { config.launcher or 'sys/apps/Overview.lua' },
|
||||||
isOverview = true,
|
isOverview = true,
|
||||||
noTerminate = true,
|
noTerminate = true,
|
||||||
focused = true,
|
focused = true,
|
||||||
title = '+',
|
title = '+',
|
||||||
|
onExit = function(_, s, m)
|
||||||
|
if not s then
|
||||||
|
kernel.halt(s, m)
|
||||||
|
end
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
multishell.setTitle(overviewId, '+')
|
||||||
|
|
||||||
multishell.openTab({
|
multishell.openTab(_ENV, {
|
||||||
path = 'sys/apps/shell.lua',
|
path = 'sys/apps/shell.lua',
|
||||||
args = { 'sys/apps/autorun.lua' },
|
args = { 'sys/apps/autorun.lua' },
|
||||||
title = 'Autorun',
|
title = 'Autorun',
|
||||||
|
@ -108,6 +108,38 @@ function Routine:resume(event, ...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Routine:run()
|
||||||
|
self.co = self.co or coroutine.create(function()
|
||||||
|
local result, err, fn
|
||||||
|
|
||||||
|
if self.fn then
|
||||||
|
fn = self.fn
|
||||||
|
_G.setfenv(fn, self.env)
|
||||||
|
elseif self.path then
|
||||||
|
fn, err = loadfile(self.path, self.env)
|
||||||
|
elseif self.chunk then
|
||||||
|
fn, err = load(self.chunk, self.title, nil, self.env)
|
||||||
|
end
|
||||||
|
|
||||||
|
if fn then
|
||||||
|
result, err = trace(fn, table.unpack(self.args or { } ))
|
||||||
|
else
|
||||||
|
err = err or 'kernel: invalid routine'
|
||||||
|
end
|
||||||
|
|
||||||
|
pcall(self.onExit, self, result, err)
|
||||||
|
self:cleanup()
|
||||||
|
|
||||||
|
if not result then
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
table.insert(kernel.routines, self)
|
||||||
|
|
||||||
|
return self:resume()
|
||||||
|
end
|
||||||
|
|
||||||
-- override if any post processing is required
|
-- override if any post processing is required
|
||||||
function Routine:onExit(status, message) -- self, status, message
|
function Routine:onExit(status, message) -- self, status, message
|
||||||
if not status and message ~= 'Terminated' then
|
if not status and message ~= 'Terminated' then
|
||||||
@ -134,9 +166,14 @@ function kernel.getShell()
|
|||||||
return shell
|
return shell
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.makeEnv = shell.makeEnv
|
-- each routine inherits the parent's env
|
||||||
|
function kernel.makeEnv(env)
|
||||||
|
env = setmetatable(Util.shallowCopy(env or _ENV), { __index = _G })
|
||||||
|
_G.requireInjector(env)
|
||||||
|
return env
|
||||||
|
end
|
||||||
|
|
||||||
function kernel.newRoutine(args)
|
function kernel.newRoutine(env, args)
|
||||||
kernel.UID = kernel.UID + 1
|
kernel.UID = kernel.UID + 1
|
||||||
|
|
||||||
local routine = setmetatable({
|
local routine = setmetatable({
|
||||||
@ -147,52 +184,16 @@ function kernel.newRoutine(args)
|
|||||||
}, { __index = Routine })
|
}, { __index = Routine })
|
||||||
|
|
||||||
Util.merge(routine, args)
|
Util.merge(routine, args)
|
||||||
routine.env = args.env or shell.makeEnv()
|
routine.env = args.env or kernel.makeEnv(env)
|
||||||
routine.terminal = routine.terminal or routine.window
|
routine.terminal = routine.terminal or routine.window
|
||||||
|
|
||||||
return routine
|
return routine
|
||||||
end
|
end
|
||||||
|
|
||||||
local function xprun(env, path, ...)
|
function kernel.run(env, args)
|
||||||
setmetatable(env, { __index = _G })
|
local routine = kernel.newRoutine(env, args)
|
||||||
local fn, m = loadfile(path, env)
|
local s, m = routine:run()
|
||||||
if fn then
|
return s and routine, m
|
||||||
return trace(fn, ...)
|
|
||||||
end
|
|
||||||
return fn, m
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.launch(routine)
|
|
||||||
routine.co = routine.co or coroutine.create(function()
|
|
||||||
local result, err
|
|
||||||
|
|
||||||
if routine.fn then
|
|
||||||
result, err = Util.runFunction(routine.env, routine.fn, table.unpack(routine.args or { } ))
|
|
||||||
elseif routine.path then
|
|
||||||
result, err = xprun(routine.env, routine.path, table.unpack(routine.args or { } ))
|
|
||||||
else
|
|
||||||
err = 'kernel: invalid routine'
|
|
||||||
end
|
|
||||||
|
|
||||||
pcall(routine.onExit, routine, result, err)
|
|
||||||
routine:cleanup()
|
|
||||||
|
|
||||||
if not result then
|
|
||||||
error(err)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
table.insert(kernel.routines, routine)
|
|
||||||
|
|
||||||
local s, m = routine:resume()
|
|
||||||
|
|
||||||
return s and routine.uid, m
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.run(args)
|
|
||||||
local routine = kernel.newRoutine(args)
|
|
||||||
kernel.launch(routine)
|
|
||||||
return routine
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function kernel.raise(uid)
|
function kernel.raise(uid)
|
||||||
@ -314,9 +315,10 @@ local function init(...)
|
|||||||
for _,file in ipairs(files) do
|
for _,file in ipairs(files) do
|
||||||
local level = file:match('(%d).%S+.lua') or 99
|
local level = file:match('(%d).%S+.lua') or 99
|
||||||
if tonumber(level) <= runLevel then
|
if tonumber(level) <= runLevel then
|
||||||
|
-- All init programs run under the original shell
|
||||||
local s, m = shell.run(fs.combine(dir, file))
|
local s, m = shell.run(fs.combine(dir, file))
|
||||||
if not s then
|
if not s then
|
||||||
error(m)
|
error(m, -1)
|
||||||
end
|
end
|
||||||
os.sleep(0)
|
os.sleep(0)
|
||||||
end
|
end
|
||||||
@ -331,7 +333,7 @@ local function init(...)
|
|||||||
shell.run('sys/apps/autorun.lua')
|
shell.run('sys/apps/autorun.lua')
|
||||||
|
|
||||||
local win = window.create(kernel.terminal, 1, 1, w, h, true)
|
local win = window.create(kernel.terminal, 1, 1, w, h, true)
|
||||||
local s, m = kernel.run({
|
local s, m = kernel.run(_ENV, {
|
||||||
title = args[1],
|
title = args[1],
|
||||||
path = 'sys/apps/shell.lua',
|
path = 'sys/apps/shell.lua',
|
||||||
args = args,
|
args = args,
|
||||||
@ -349,7 +351,7 @@ local function init(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.run({
|
kernel.run(_ENV, {
|
||||||
fn = init,
|
fn = init,
|
||||||
title = 'init',
|
title = 'init',
|
||||||
args = { ... },
|
args = { ... },
|
||||||
|
@ -100,7 +100,7 @@ local function crypt(data, key, nonce, cntr, round)
|
|||||||
cntr = tonumber(cntr) or 1
|
cntr = tonumber(cntr) or 1
|
||||||
round = tonumber(round) or 20
|
round = tonumber(round) or 20
|
||||||
|
|
||||||
local throttle = Util.throttle(function() _syslog('throttle') end)
|
local throttle = Util.throttle()
|
||||||
local out = {}
|
local out = {}
|
||||||
local state = initState(key, nonce, cntr)
|
local state = initState(key, nonce, cntr)
|
||||||
local blockAmt = math.floor(#data/64)
|
local blockAmt = math.floor(#data/64)
|
||||||
|
@ -58,6 +58,14 @@ function Routine:resume(event, ...)
|
|||||||
else
|
else
|
||||||
s, m = coroutine.resume(self.co, event, ...)
|
s, m = coroutine.resume(self.co, event, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not s and event ~= 'terminate' then
|
||||||
|
if m and debug and debug.traceback then
|
||||||
|
local t = (debug.traceback(self.co, 1)) or ''
|
||||||
|
m = m .. '\n' .. t:match('%d\n(.+)')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if self:isDead() then
|
if self:isDead() then
|
||||||
self.co = nil
|
self.co = nil
|
||||||
self.filter = nil
|
self.filter = nil
|
||||||
|
@ -32,95 +32,63 @@ local function traceback(x)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function trim_traceback(target, marker)
|
local function trim_traceback(target)
|
||||||
local ttarget, tmarker = {}, {}
|
local t = { }
|
||||||
for line in target:gmatch("([^\n]*)\n?") do ttarget[#ttarget + 1] = line end
|
local filters = {
|
||||||
for line in marker:gmatch("([^\n]*)\n?") do tmarker[#tmarker + 1] = line end
|
"%[C%]: in function 'xpcall'",
|
||||||
|
"(...tail calls...)",
|
||||||
|
"xpcall: $",
|
||||||
|
"trace.lua:%d+:",
|
||||||
|
}
|
||||||
|
|
||||||
--[[
|
local function matchesFilter(line)
|
||||||
TODO : fix this trace
|
for _, filter in pairs(filters) do
|
||||||
Anavrins - if you could take a look, it would be appreciated
|
if line:match(filter) then
|
||||||
-- basically i want the stack logged in a more readable
|
return true
|
||||||
-- format and the normal code/error message to be returned
|
end
|
||||||
|
end
|
||||||
-- unsure why the traceback method concatenates the stack
|
|
||||||
-- when it can just be returned as a table - would make
|
|
||||||
-- filtering much simpler
|
|
||||||
|
|
||||||
-- the following seems to reduce the stacktrace way too
|
|
||||||
-- much - losing most of the relevant call stack
|
|
||||||
|
|
||||||
-- i have modified this a bit from the original - not sure
|
|
||||||
-- if my changes are causing the issues or not
|
|
||||||
|
|
||||||
-- Trim identical suffixes
|
|
||||||
local t_len, m_len = #ttarget, #tmarker
|
|
||||||
while t_len >= 3 and ttarget[t_len] == tmarker[m_len] do
|
|
||||||
table.remove(ttarget, t_len)
|
|
||||||
t_len, m_len = t_len - 1, m_len - 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Trim elements from this file and xpcall invocations
|
for line in target:gmatch("([^\n]*)\n?") do
|
||||||
while t_len >= 1 and ttarget[t_len]:find("^\tstack_trace%.lua:%d+:") or
|
if not matchesFilter(line) then
|
||||||
ttarget[t_len] == "\t[C]: in function 'xpcall'" or ttarget[t_len] == " xpcall: " do
|
table.insert(t, line)
|
||||||
table.remove(ttarget, t_len)
|
end
|
||||||
t_len = t_len - 1
|
|
||||||
end
|
end
|
||||||
]]
|
|
||||||
ttarget[#ttarget] = nil -- remove 2 calls added by the added xpcall
|
|
||||||
ttarget[#ttarget] = nil
|
|
||||||
|
|
||||||
return ttarget
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Run a function with
|
|
||||||
return function (fn, ...)
|
return function (fn, ...)
|
||||||
-- So this is rather grim: we need to get the full traceback and current one and remove
|
|
||||||
-- the common prefix
|
|
||||||
local trace
|
|
||||||
local args = { ... }
|
|
||||||
|
|
||||||
-- xpcall in Lua 5.1 does not accept parameters
|
-- xpcall in Lua 5.1 does not accept parameters
|
||||||
-- which is not ideal
|
-- which is not ideal
|
||||||
|
local args = { ... }
|
||||||
local res = table.pack(xpcall(function()
|
local res = table.pack(xpcall(function()
|
||||||
return fn(table.unpack(args))
|
return fn(table.unpack(args))
|
||||||
end, traceback))
|
end, traceback))
|
||||||
|
|
||||||
if not res[1] then
|
|
||||||
trace = traceback("trace.lua:1:")
|
|
||||||
end
|
|
||||||
local ok, err = res[1], res[2]
|
local ok, err = res[1], res[2]
|
||||||
|
|
||||||
if not ok and err ~= nil then
|
if not ok and err ~= nil then
|
||||||
trace = trim_traceback(err, trace)
|
local trace = trim_traceback(err)
|
||||||
|
|
||||||
-- Find the position where the stack traceback actually starts
|
err = { }
|
||||||
local trace_starts
|
while true do
|
||||||
for i = #trace, 1, -1 do
|
local line = table.remove(trace, 1)
|
||||||
if trace[i] == "stack traceback:" then trace_starts = i; break end
|
if not line or line == 'stack traceback:' then
|
||||||
end
|
break
|
||||||
|
end
|
||||||
_G._syslog('')
|
table.insert(err, line)
|
||||||
for _, line in pairs(trace) do
|
end
|
||||||
_G._syslog(line)
|
err = table.concat(err, '\n')
|
||||||
end
|
|
||||||
|
_G._syslog('\n' .. err .. '\n' .. 'stack traceback:')
|
||||||
-- If this traceback is more than 15 elements long, keep the first 9, last 5
|
for _, v in ipairs(trace) do
|
||||||
-- and put an ellipsis between the rest
|
if v ~= 'stack traceback:' then
|
||||||
local max = 10
|
_G._syslog(v:gsub("in function", "in"))
|
||||||
if trace_starts and #trace - trace_starts > max then
|
|
||||||
local keep_starts = trace_starts + 7
|
|
||||||
for i = #trace - trace_starts - max, 0, -1 do
|
|
||||||
table.remove(trace, keep_starts + i)
|
|
||||||
end
|
end
|
||||||
table.insert(trace, keep_starts, " ...")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for k, line in pairs(trace) do
|
return ok, err
|
||||||
trace[k] = line:gsub("in function", " in")
|
|
||||||
end
|
|
||||||
|
|
||||||
return false, table.remove(trace, 1), table.concat(trace, "\n")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return table.unpack(res, 1, res.n)
|
return table.unpack(res, 1, res.n)
|
||||||
|
@ -117,7 +117,7 @@ function UI:init()
|
|||||||
|
|
||||||
if ie.code == 'control-shift-mouse_click' then -- hack
|
if ie.code == 'control-shift-mouse_click' then -- hack
|
||||||
local event = currentPage:pointToChild(x, y)
|
local event = currentPage:pointToChild(x, y)
|
||||||
_ENV.multishell.openTab({
|
_ENV.multishell.openTab(_ENV, {
|
||||||
path = 'sys/apps/Lua.lua',
|
path = 'sys/apps/Lua.lua',
|
||||||
args = { event.element, self, _ENV },
|
args = { event.element, self, _ENV },
|
||||||
focused = true })
|
focused = true })
|
||||||
|
Loading…
Reference in New Issue
Block a user