mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-23 10:58:06 +11:00
Finish lowering memory use, R1
Since this is after the technical "release", version numbers have been bumped to 1. Changes before this commit for R1: Kernel memory usage reduction schemes, with some security fixes. Still need to deal w/ proxies (see later) Changes in this commit: Some various little things in apps CLAW inet actually works now on 192K sys-icecap no longer uses the event/neoux combination, and now handles Everest disappearance as a mass-close, but still handles Everest not being around on window create. So it still handles every situation that matters. neoux no longer handles everest crash protection. Security policy and filedialog obviously don't use neoux anymore. Kernel now only guarantees parsing, not event-loop, by executeAsync This is safer and allows app-launcher to get rid of NeoUX by any means necessary. wrapMeta cache now exists, and proxies get wrapMeta'd to deal with various low-priority security shenanigans. This is a *stopgap* until I work out how to force OCEmu to give me totally accurate boot-time memory figures, so I can create the ultimate lowmem proxy. I'm calling it "puppet". FG knows why.
This commit is contained in:
parent
fcabf5b853
commit
7bde8fee55
8
.gitignore
vendored
8
.gitignore
vendored
@ -12,6 +12,14 @@ work/*/
|
||||
work/*/*
|
||||
work/*/*/
|
||||
work/*/*/*
|
||||
repobuild
|
||||
repobuild/
|
||||
repobuild/*
|
||||
repobuild/*/
|
||||
repobuild/*/*
|
||||
repobuild/*/*/
|
||||
repobuild/*/*/*
|
||||
|
||||
inst.lua
|
||||
com2/code.tar.bd
|
||||
upldr.sh
|
||||
|
17
clawmerge.lua
Normal file
17
clawmerge.lua
Normal file
@ -0,0 +1,17 @@
|
||||
local merges = {...}
|
||||
neo = {
|
||||
wrapMeta = function (x)
|
||||
return x
|
||||
end
|
||||
}
|
||||
local serial = loadfile("code/libs/serial.lua")()
|
||||
local repo = {}
|
||||
for _, v in ipairs(merges) do
|
||||
local f = io.open(v, "rb")
|
||||
local fd = f:read("*a")
|
||||
f:close()
|
||||
for k, v in pairs(serial.deserialize(fd)) do
|
||||
repo[k] = v
|
||||
end
|
||||
end
|
||||
io.write(serial.serialize(repo))
|
@ -20,7 +20,7 @@ if primaryINet then primaryINet = primaryINet.list()() end
|
||||
|
||||
local function yielder()
|
||||
-- slightly dangerous, but what can we do?
|
||||
event.sleepTo(os.uptime() + 0.05)
|
||||
pcall(event.sleepTo, os.uptime() + 0.05)
|
||||
end
|
||||
|
||||
local function download(url, cb)
|
||||
@ -28,16 +28,12 @@ local function download(url, cb)
|
||||
local req, err = primaryINet.request(source .. url)
|
||||
if not req then
|
||||
cb(nil)
|
||||
return nil, tostring(err)
|
||||
end
|
||||
local ok, err = req.finishConnect()
|
||||
if not req.finishConnect() then
|
||||
req.close()
|
||||
cb(nil)
|
||||
return nil, tostring(err)
|
||||
return nil, "dlR/" .. tostring(err)
|
||||
end
|
||||
-- OpenComputers#535
|
||||
req.finishConnect()
|
||||
while true do
|
||||
local n, n2 = req.read()
|
||||
local n, n2 = req.read(neo.readBufSize)
|
||||
local o, r = cb(n)
|
||||
if not o then
|
||||
req.close()
|
||||
|
@ -4,8 +4,7 @@
|
||||
-- app-taskmgr: Task manager
|
||||
-- a-hello : simple test program for Everest.
|
||||
|
||||
local everest = neo.requestAccess("x.neo.pub.window")
|
||||
if not everest then error("no everest") return end
|
||||
local everest = neo.requireAccess("x.neo.pub.window", "main window")
|
||||
|
||||
local kill = neo.requestAccess("k.kill")
|
||||
|
||||
@ -13,7 +12,6 @@ local sW, sH = 20, 8
|
||||
local headlines = 2
|
||||
|
||||
local window = everest(sW, sH)
|
||||
if not window then error("no window") end
|
||||
|
||||
local lastIdleTimeTime = os.uptime()
|
||||
local lastIdleTime = neo.totalIdleTime()
|
||||
|
@ -4,11 +4,6 @@
|
||||
-- s-icecap : Responsible for x.neo.pub API, crash dialogs, and security policy that isn't "sys- has ALL access, anything else has none"
|
||||
-- In general, this is what userspace will be interacting with in some way or another to get stuff done
|
||||
|
||||
local event = require("event")(neo)
|
||||
local neoux, err = require("neoux")
|
||||
if not neoux then error(err) end -- This app is basically neoux's testcase
|
||||
neoux = neoux(event, neo)
|
||||
|
||||
local settings = neo.requireAccess("x.neo.sys.manage", "security sysconf access")
|
||||
|
||||
local fs = neo.requireAccess("c.filesystem", "file managers")
|
||||
@ -17,6 +12,72 @@ local donkonitDFProvider = neo.requireAccess("r.neo.pub.base", "creating basic N
|
||||
|
||||
local targsDH = {} -- data disposal
|
||||
|
||||
local todo = {}
|
||||
|
||||
local onEverest = {}
|
||||
local everestWindows = {}
|
||||
|
||||
local nexus
|
||||
|
||||
local function resumeWF(...)
|
||||
local ok, e = coroutine.resume(...)
|
||||
if not ok then
|
||||
e = tostring(e)
|
||||
neo.emergency(e)
|
||||
nexus.startDialog(e, "ice")
|
||||
end
|
||||
return ok
|
||||
end
|
||||
|
||||
nexus = {
|
||||
createNexusThread = function (f, ...)
|
||||
local t = coroutine.create(f)
|
||||
if not resumeWF(t, ...) then return end
|
||||
local early = neo.requestAccess("x.neo.pub.window")
|
||||
if early then
|
||||
onEverest[#onEverest] = nil
|
||||
resumeWF(t, early)
|
||||
end
|
||||
return function ()
|
||||
for k, v in ipairs(onEverest) do
|
||||
if v == t then
|
||||
table.remove(onEverest, k)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
create = function (w, h, t)
|
||||
local thr = coroutine.running()
|
||||
table.insert(onEverest, thr)
|
||||
local everest = coroutine.yield()
|
||||
local dw = everest(w, h, title)
|
||||
everestWindows[dw.id] = thr
|
||||
return dw
|
||||
end,
|
||||
startDialog = function (tx, ti)
|
||||
local fmt = require("fmttext")
|
||||
local txl = fmt.fmtText(unicode.safeTextFormat(tx), 40)
|
||||
fmt = nil
|
||||
nexus.createNexusThread(function ()
|
||||
local w = nexus.create(40, #txl, ti)
|
||||
while true do
|
||||
local ev, a = coroutine.yield()
|
||||
if ev == "line" then
|
||||
w.span(1, a, txl[a], 0xFFFFFF, 0)
|
||||
elseif ev == "close" then
|
||||
w.close()
|
||||
return
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
close = function (wnd)
|
||||
wnd.close()
|
||||
everestWindows[wnd.id] = nil
|
||||
end
|
||||
}
|
||||
|
||||
donkonitDFProvider(function (pkg, pid, sendSig)
|
||||
local prefixNS = "data/" .. pkg
|
||||
local prefixWS = "data/" .. pkg .. "/"
|
||||
@ -32,9 +93,10 @@ donkonitDFProvider(function (pkg, pid, sendSig)
|
||||
-- Not hooked into the event API, so can't safely interfere
|
||||
-- Thus, this is async and uses a return event.
|
||||
local tag = {}
|
||||
event.runAt(0, function ()
|
||||
neo.scheduleTimer(0)
|
||||
table.insert(todo, function ()
|
||||
-- sys-filedialog is yet another "library to control memory usage".
|
||||
local closer = require("sys-filedialog")(event, neoux, function (res) openHandles[tag] = nil sendSig("filedialog", tag, res) end, fs, pkg, forWrite)
|
||||
local closer = require("sys-filedialog")(event, nexus, function (res) openHandles[tag] = nil sendSig("filedialog", tag, res) end, fs, pkg, forWrite)
|
||||
openHandles[tag] = closer
|
||||
end)
|
||||
return tag
|
||||
@ -122,9 +184,10 @@ rootAccess.securityPolicy = function (pid, proc, perm, req)
|
||||
req(def)
|
||||
return
|
||||
end
|
||||
-- Push to ICECAP thread to avoid deadlock on neoux b/c wrong event-pull context
|
||||
event.runAt(0, function ()
|
||||
local ok, err = pcall(secpol, neoux, settings, proc.pkg, pid, perm, req)
|
||||
-- Push to ICECAP thread to avoid deadlock b/c wrong event-pull context
|
||||
neo.scheduleTimer(0)
|
||||
table.insert(todo, function ()
|
||||
local ok, err = pcall(secpol, nexus, settings, proc.pkg, pid, perm, req)
|
||||
if not ok then
|
||||
neo.emergency("Used fallback policy because of run-err: " .. err)
|
||||
req(def)
|
||||
@ -132,19 +195,41 @@ rootAccess.securityPolicy = function (pid, proc, perm, req)
|
||||
end)
|
||||
end
|
||||
|
||||
event.listen("k.procdie", function (evt, pkg, pid, reason)
|
||||
if targsDH[pid] then
|
||||
targsDH[pid]()
|
||||
end
|
||||
targsDH[pid] = nil
|
||||
if reason then
|
||||
-- Process death logging in console (for lifecycle dbg)
|
||||
-- neo.emergency(n[2])
|
||||
-- neo.emergency(n[4])
|
||||
neoux.startDialog(string.format("%s/%i died:\n%s", pkg, pid, reason), "error")
|
||||
end
|
||||
end)
|
||||
|
||||
while true do
|
||||
event.pull()
|
||||
local ev = {coroutine.yield()}
|
||||
if ev[1] == "k.procdie" then
|
||||
local _, pkg, pid, reason = table.unpack(ev)
|
||||
if targsDH[pid] then
|
||||
targsDH[pid]()
|
||||
end
|
||||
targsDH[pid] = nil
|
||||
if reason then
|
||||
nexus.startDialog(string.format("%s/%i died:\n%s", pkg, pid, reason), "error")
|
||||
end
|
||||
elseif ev[1] == "k.timer" then
|
||||
local nt = todo
|
||||
todo = {}
|
||||
for _, v in ipairs(nt) do
|
||||
local ok, e = pcall(v)
|
||||
if not ok then
|
||||
nexus.startDialog(tostring(e), "terr")
|
||||
end
|
||||
end
|
||||
elseif ev[1] == "k.registration" then
|
||||
if ev[2] == "x.neo.pub.window" then
|
||||
local nt = onEverest
|
||||
onEverest = {}
|
||||
for _, v in ipairs(nt) do
|
||||
coroutine.resume(v, neo.requestAccess("x.neo.pub.window"))
|
||||
end
|
||||
end
|
||||
elseif ev[1] == "x.neo.pub.window" then
|
||||
local v = everestWindows[ev[2]]
|
||||
if v then
|
||||
resumeWF(v, table.unpack(ev, 3))
|
||||
if coroutine.status(v) == "dead" then
|
||||
everestWindows[ev[2]] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
return {
|
||||
["neo"] = {
|
||||
desc = "KittenOS NEO Kernel & Base Libs",
|
||||
v = 0,
|
||||
v = 1,
|
||||
deps = {
|
||||
},
|
||||
dirs = {
|
||||
@ -14,6 +14,7 @@ return {
|
||||
"apps/sys-glacier.lua",
|
||||
"libs/event.lua",
|
||||
"libs/serial.lua",
|
||||
"libs/fmttext.lua",
|
||||
"libs/neoux.lua",
|
||||
"libs/braille.lua",
|
||||
"libs/sys-filewrap.lua"
|
||||
@ -62,7 +63,7 @@ return {
|
||||
},
|
||||
["neo-icecap"] = {
|
||||
desc = "KittenOS NEO / Icecap",
|
||||
v = 0,
|
||||
v = 1,
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -79,20 +80,19 @@ return {
|
||||
},
|
||||
["neo-secpolicy"] = {
|
||||
desc = "KittenOS NEO / Secpolicy",
|
||||
v = 0,
|
||||
v = 1,
|
||||
deps = {
|
||||
},
|
||||
dirs = {
|
||||
"libs"
|
||||
},
|
||||
files = {
|
||||
"libs/sys-secpolicy.lua",
|
||||
"libs/sys-criticals.lua"
|
||||
"libs/sys-secpolicy.lua"
|
||||
}
|
||||
},
|
||||
["neo-coreapps"] = {
|
||||
desc = "KittenOS NEO Core Apps",
|
||||
v = 0,
|
||||
v = 1,
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -136,7 +136,7 @@ return {
|
||||
},
|
||||
["app-claw"] = {
|
||||
desc = "KittenOS NEO Package Manager",
|
||||
v = 0,
|
||||
v = 1,
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
|
@ -101,12 +101,23 @@ end
|
||||
|
||||
uniqueNEOProtectionObject = {}
|
||||
|
||||
wrapMetaCache = {}
|
||||
setmetatable(wrapMetaCache, {__mode = "v"})
|
||||
|
||||
function wrapMeta(t)
|
||||
if type(t) == "table" then
|
||||
if wrapMetaCache[t] then
|
||||
return wrapMetaCache[t]
|
||||
end
|
||||
local t2 = {}
|
||||
wrapMetaCache[t] = t2
|
||||
setmetatable(t2, {
|
||||
__index = function (a, k) return wrapMeta(t[k]) end,
|
||||
__newindex = error,
|
||||
-- WTF
|
||||
__call = function (_, ...)
|
||||
return t(...)
|
||||
end,
|
||||
__pairs = function (a)
|
||||
return function (x, key)
|
||||
local k, v = next(t, k)
|
||||
@ -392,8 +403,8 @@ function retrieveAccess(perm, pkg, pid)
|
||||
local temporary = nil
|
||||
local t = perm:sub(3)
|
||||
if t == "filesystem" then
|
||||
primary = primaryDisk
|
||||
temporary = component.proxy(computer.tmpAddress())
|
||||
primary = wrapMeta(primaryDisk)
|
||||
temporary = wrapMeta(component.proxy(computer.tmpAddress()))
|
||||
end
|
||||
return {
|
||||
list = function ()
|
||||
@ -401,7 +412,7 @@ function retrieveAccess(perm, pkg, pid)
|
||||
return function ()
|
||||
local ii = i()
|
||||
if not ii then return nil end
|
||||
return component.proxy(ii)
|
||||
return wrapMeta(component.proxy(ii))
|
||||
end
|
||||
end,
|
||||
primary = primary,
|
||||
@ -556,10 +567,7 @@ function start(pkg, ...)
|
||||
-- Note the target process doesn't get the procnew (the dist occurs before it's creation)
|
||||
pcall(distEvent, nil, "k.procnew", pkg, pid)
|
||||
processes[pid] = proc
|
||||
-- For processes waiting on others, this at least tries to guarantee some safety.
|
||||
if not pcall(execEvent, pid, ...) then
|
||||
return nil, "neocore"
|
||||
end
|
||||
table.insert(timers, {0, execEvent, pid, ...})
|
||||
return pid
|
||||
end
|
||||
|
||||
|
67
code/libs/fmttext.lua
Normal file
67
code/libs/fmttext.lua
Normal file
@ -0,0 +1,67 @@
|
||||
local fmt
|
||||
fmt = {
|
||||
pad = function (t, len, centre, cut)
|
||||
local l = unicode.len(t)
|
||||
local add = len - l
|
||||
if add > 0 then
|
||||
if centre then
|
||||
t = (" "):rep(math.floor(add / 2)) .. t .. (" "):rep(math.ceil(add / 2))
|
||||
else
|
||||
t = t .. (" "):rep(add)
|
||||
end
|
||||
end
|
||||
if cut then
|
||||
t = unicode.sub(t, 1, len)
|
||||
end
|
||||
return t
|
||||
end,
|
||||
fmtText = function (text, w)
|
||||
local nl = text:find("\n")
|
||||
if nl then
|
||||
local base = text:sub(1, nl - 1)
|
||||
local ext = text:sub(nl + 1)
|
||||
local baseT = fmt.fmtText(base, w)
|
||||
local extT = fmt.fmtText(ext, w)
|
||||
for _, v in ipairs(extT) do
|
||||
table.insert(baseT, v)
|
||||
end
|
||||
return baseT
|
||||
end
|
||||
if unicode.len(text) > w then
|
||||
local lastSpace
|
||||
for i = 1, w do
|
||||
if unicode.sub(text, i, i) == " " then
|
||||
-- Check this isn't an inserted space (unicode safe text format)
|
||||
local ok = true
|
||||
if i > 1 then
|
||||
if unicode.charWidth(unicode.sub(text, i - 1, i - 1)) ~= 1 then
|
||||
ok = false
|
||||
end
|
||||
end
|
||||
if ok then
|
||||
lastSpace = i
|
||||
end
|
||||
end
|
||||
end
|
||||
local baseText, extText
|
||||
if not lastSpace then
|
||||
-- Break at a 1-earlier boundary
|
||||
local wEffect = w
|
||||
if unicode.charWidth(unicode.sub(text, w, w)) ~= 1 then
|
||||
-- Guaranteed to be safe, so
|
||||
wEffect = wEffect - 1
|
||||
end
|
||||
baseText = unicode.sub(text, 1, wEffect)
|
||||
extText = unicode.sub(text, wEffect + 1)
|
||||
else
|
||||
baseText = unicode.sub(text, 1, lastSpace - 1)
|
||||
extText = unicode.sub(text, lastSpace + 1)
|
||||
end
|
||||
local full = fmt.fmtText(extText, w)
|
||||
table.insert(full, 1, fmt.pad(baseText, w))
|
||||
return full
|
||||
end
|
||||
return {fmt.pad(text, w)}
|
||||
end
|
||||
}
|
||||
return neo.wrapMeta(fmt)
|
@ -16,57 +16,12 @@
|
||||
|
||||
-- Global forces reference. Otherwise, nasty duplication happens.
|
||||
newNeoux = function (event, neo)
|
||||
-- this is why neo access is 'needed'
|
||||
local function retrieveIcecap()
|
||||
return neo.requestAccess("x.neo.pub.base")
|
||||
end
|
||||
local function retrieveEverest()
|
||||
return neo.requestAccess("x.neo.pub.window")
|
||||
end
|
||||
-- id -> {lclEv, w, h, title, callback}
|
||||
local windows = {}
|
||||
-- id -> callback
|
||||
local lclEvToW = {}
|
||||
retrieveEverest()
|
||||
local function everestDied()
|
||||
for _, v in pairs(windows) do
|
||||
v[1] = nil
|
||||
end
|
||||
lclEvToW = {}
|
||||
end
|
||||
local function pushWindowToEverest(k)
|
||||
local everest = retrieveEverest()
|
||||
if not everest then
|
||||
everestDied()
|
||||
return
|
||||
end
|
||||
local v = windows[k]
|
||||
local r, res = pcall(everest, v[2], v[3], v[4])
|
||||
if not r then
|
||||
everestDied()
|
||||
return
|
||||
else
|
||||
-- res is the window!
|
||||
lclEvToW[res.id] = k
|
||||
windows[k][1] = res
|
||||
end
|
||||
end
|
||||
event.listen("k.registration", function (_, xe)
|
||||
if #windows > 0 then
|
||||
if xe == "x.neo.pub.window" then
|
||||
for k, v in pairs(windows) do
|
||||
pushWindowToEverest(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
event.listen("k.deregistration", function (_, xe)
|
||||
if xe == "x.neo.pub.window" then
|
||||
everestDied()
|
||||
end
|
||||
end)
|
||||
local everest = neo.requireAccess("x.neo.pub.window", "windowing")
|
||||
event.listen("x.neo.pub.window", function (_, window, tp, ...)
|
||||
if lclEvToW[window] then
|
||||
windows[lclEvToW[window]][5](tp, ...)
|
||||
lclEvToW[window](tp, ...)
|
||||
end
|
||||
end)
|
||||
local neoux = {}
|
||||
@ -80,7 +35,7 @@ newNeoux = function (event, neo)
|
||||
rtt = rt
|
||||
end
|
||||
end
|
||||
local tag = retrieveIcecap().showFileDialogAsync(forWrite)
|
||||
local tag = neo.requestAccess("x.neo.pub.base").showFileDialogAsync(forWrite)
|
||||
local f
|
||||
f = function (_, fd, tg, re)
|
||||
if fd == "filedialog" then
|
||||
@ -99,117 +54,40 @@ newNeoux = function (event, neo)
|
||||
-- Creates a wrapper around a window.
|
||||
neoux.create = function (w, h, title, callback)
|
||||
local window = {}
|
||||
local windowCore = {nil, w, h, title, function (...) callback(window, ...) end}
|
||||
local k = #windows + 1
|
||||
table.insert(windows, windowCore)
|
||||
pushWindowToEverest(k)
|
||||
local windowCore = everest(w, h, title)
|
||||
-- res is the window!
|
||||
lclEvToW[windowCore.id] = function (...) callback(window, ...) end
|
||||
-- API convenience: args compatible with .create
|
||||
window.reset = function (nw, nh, _, cb)
|
||||
callback = cb
|
||||
if nw or nh then
|
||||
windowCore[2] = nw
|
||||
windowCore[3] = nh
|
||||
end
|
||||
if windowCore[1] then
|
||||
windowCore[1].setSize(windowCore[2], windowCore[3])
|
||||
end
|
||||
w = nw or w
|
||||
h = nh or h
|
||||
windowCore.setSize(w, h)
|
||||
end
|
||||
window.getSize = function ()
|
||||
return windowCore[2], windowCore[3]
|
||||
return w, h
|
||||
end
|
||||
window.getDepth = function ()
|
||||
if windowCore[1] then
|
||||
return windowCore[1].getDepth()
|
||||
end
|
||||
return 1
|
||||
end
|
||||
window.setSize = function (w, h)
|
||||
windowCore[2] = w
|
||||
windowCore[3] = h
|
||||
if windowCore[1] then
|
||||
windowCore[1].setSize(w, h)
|
||||
end
|
||||
end
|
||||
window.span = function (x, y, text, bg, fg)
|
||||
if windowCore[1] then
|
||||
pcall(windowCore[1].span, x, y, text, bg, fg)
|
||||
end
|
||||
window.getDepth = windowCore.getDepth
|
||||
window.setSize = function (nw, nh)
|
||||
w = nw
|
||||
h = nh
|
||||
windowCore.setSize(w, h)
|
||||
end
|
||||
window.span = windowCore.span
|
||||
window.close = function ()
|
||||
if windowCore[1] then
|
||||
windowCore[1].close()
|
||||
lclEvToW[windowCore[1].id] = nil
|
||||
windowCore[1] = nil
|
||||
end
|
||||
windows[k] = nil
|
||||
windowCore.close()
|
||||
lclEvToW[windowCore.id] = nil
|
||||
windowCore = nil
|
||||
end
|
||||
return window
|
||||
end
|
||||
-- Padding function
|
||||
neoux.pad = function (t, len, centre, cut)
|
||||
local l = unicode.len(t)
|
||||
local add = len - l
|
||||
if add > 0 then
|
||||
if centre then
|
||||
t = (" "):rep(math.floor(add / 2)) .. t .. (" "):rep(math.ceil(add / 2))
|
||||
else
|
||||
t = t .. (" "):rep(add)
|
||||
end
|
||||
end
|
||||
if cut then
|
||||
t = unicode.sub(t, 1, len)
|
||||
end
|
||||
return t
|
||||
end
|
||||
neoux.pad = require("fmttext").pad
|
||||
-- Text dialog formatting function.
|
||||
-- Assumes you've run unicode.safeTextFormat if need be
|
||||
neoux.fmtText = function (text, w)
|
||||
local nl = text:find("\n")
|
||||
if nl then
|
||||
local base = text:sub(1, nl - 1)
|
||||
local ext = text:sub(nl + 1)
|
||||
local baseT = neoux.fmtText(base, w)
|
||||
local extT = neoux.fmtText(ext, w)
|
||||
for _, v in ipairs(extT) do
|
||||
table.insert(baseT, v)
|
||||
end
|
||||
return baseT
|
||||
end
|
||||
if unicode.len(text) > w then
|
||||
local lastSpace
|
||||
for i = 1, w do
|
||||
if unicode.sub(text, i, i) == " " then
|
||||
-- Check this isn't an inserted space (unicode safe text format)
|
||||
local ok = true
|
||||
if i > 1 then
|
||||
if unicode.charWidth(unicode.sub(text, i - 1, i - 1)) ~= 1 then
|
||||
ok = false
|
||||
end
|
||||
end
|
||||
if ok then
|
||||
lastSpace = i
|
||||
end
|
||||
end
|
||||
end
|
||||
local baseText, extText
|
||||
if not lastSpace then
|
||||
-- Break at a 1-earlier boundary
|
||||
local wEffect = w
|
||||
if unicode.charWidth(unicode.sub(text, w, w)) ~= 1 then
|
||||
-- Guaranteed to be safe, so
|
||||
wEffect = wEffect - 1
|
||||
end
|
||||
baseText = unicode.sub(text, 1, wEffect)
|
||||
extText = unicode.sub(text, wEffect + 1)
|
||||
else
|
||||
baseText = unicode.sub(text, 1, lastSpace - 1)
|
||||
extText = unicode.sub(text, lastSpace + 1)
|
||||
end
|
||||
local full = neoux.fmtText(extText, w)
|
||||
table.insert(full, 1, neoux.pad(baseText, w))
|
||||
return full
|
||||
end
|
||||
return {neoux.pad(text, w)}
|
||||
neoux.fmtText = function (...)
|
||||
local fmt = require("fmttext")
|
||||
return fmt.fmtText(...)
|
||||
end
|
||||
-- UI FRAMEWORK --
|
||||
neoux.tcwindow = function (w, h, controls, closing, bg, fg, selIndex)
|
||||
|
@ -2,8 +2,8 @@
|
||||
-- No warranty is provided, implied or otherwise.
|
||||
|
||||
-- just don't bother with proper indent here
|
||||
return function (event, neoux, retFunc, fs, pkg, mode)
|
||||
|
||||
return function (event, nexus, retFunc, fs, pkg, mode)
|
||||
local fmt = require("fmttext")
|
||||
local class = "manage"
|
||||
if mode ~= nil then
|
||||
if mode then
|
||||
@ -23,7 +23,7 @@ local function cb(...)
|
||||
name = "F.M. Error",
|
||||
list = function ()
|
||||
local l = {}
|
||||
for k, v in ipairs(neoux.fmtText(unicode.safeTextFormat(e), 25)) do
|
||||
for k, v in ipairs(fmt.fmtText(unicode.safeTextFormat(e), 25)) do
|
||||
l[k] = {v, function () return true end}
|
||||
end
|
||||
return l
|
||||
@ -64,7 +64,7 @@ local function prepareNodeI(node)
|
||||
if sel then
|
||||
colB, colA = 0xFFFFFF, 0
|
||||
end
|
||||
wnd.span(1, a, neoux.pad(unicode.safeTextFormat(text), w, cen, true), colA, colB)
|
||||
wnd.span(1, a, fmt.pad(unicode.safeTextFormat(text), w, cen, true), colA, colB)
|
||||
end
|
||||
local function flush(wnd)
|
||||
for i = 1, h do
|
||||
@ -108,7 +108,7 @@ local function prepareNodeI(node)
|
||||
end
|
||||
if aResult then
|
||||
retFunc(res)
|
||||
wnd.close()
|
||||
nexus.close(wnd)
|
||||
else
|
||||
prepareNode(res)
|
||||
end
|
||||
@ -148,13 +148,13 @@ local function prepareNodeI(node)
|
||||
end
|
||||
if evt == "close" then
|
||||
retFunc(nil)
|
||||
wnd.close()
|
||||
nexus.close(wnd)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local text = class .. " " .. pkg
|
||||
local window = neoux.create(25, 10, text, cb)
|
||||
local window
|
||||
|
||||
function prepareNode(node)
|
||||
local w, h, c = prepareNodeI(node)
|
||||
@ -162,10 +162,24 @@ function prepareNode(node)
|
||||
window.setSize(w, h)
|
||||
end
|
||||
|
||||
prepareNode(require("sys-filevfs")(fs, mode))
|
||||
local closer = nexus.createNexusThread(function ()
|
||||
window = nexus.create(25, 10, text)
|
||||
prepareNode(require("sys-filevfs")(fs, mode))
|
||||
while window do
|
||||
cb(window, coroutine.yield())
|
||||
end
|
||||
end)
|
||||
if not closer then
|
||||
retFunc()
|
||||
return
|
||||
end
|
||||
return function ()
|
||||
retFunc()
|
||||
window.close()
|
||||
closer()
|
||||
if window then
|
||||
nexus.close(window)
|
||||
window = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- end bad indent
|
||||
|
@ -51,39 +51,92 @@ local actualPolicy = function (pkg, pid, perm)
|
||||
return "ask"
|
||||
end
|
||||
|
||||
return function (neoux, settings, pkg, pid, perm, rsp)
|
||||
return function (nexus, settings, pkg, pid, perm, rsp)
|
||||
local res = actualPolicy(pkg, pid, perm)
|
||||
if res == "ask" and settings then
|
||||
res = settings.getSetting("perm|" .. pkg .. "|" .. perm) or "ask"
|
||||
end
|
||||
if res == "ask" and neoux then
|
||||
local fmt = neoux.fmtText(unicode.safeTextFormat(string.format("%s/%i wants:\n%s\nAllow this?", pkg, pid, perm)), 20)
|
||||
local always = "Always"
|
||||
local yes = "Yes"
|
||||
local no = "No"
|
||||
local totalW = (#yes) + (#always) + (#no) + 8
|
||||
neoux.create(20, #fmt + 2, "security", neoux.tcwindow(20, #fmt + 3, {
|
||||
neoux.tcbutton(1, #fmt + 2, no, function (w)
|
||||
if res == "ask" and nexus then
|
||||
local totalW = 3 + 6 + 2 + 8
|
||||
local fmt = require("fmttext").fmtText(unicode.safeTextFormat(string.format("%s/%i wants:\n%s\nAllow this?\n\n", pkg, pid, perm)), totalW)
|
||||
local buttons = {
|
||||
{"<No>", function (w)
|
||||
rsp(false)
|
||||
w.close()
|
||||
end),
|
||||
neoux.tcbutton(totalW - ((#yes) + 1), #fmt + 2, yes, function (w)
|
||||
rsp(true)
|
||||
w.close()
|
||||
end),
|
||||
neoux.tcbutton((#yes) + 3, #fmt + 2, always, function (w)
|
||||
nexus.close(w)
|
||||
end},
|
||||
{"<Always>", function (w)
|
||||
if settings then
|
||||
settings.setSetting("perm|" .. pkg .. "|" .. perm, "allow")
|
||||
end
|
||||
rsp(true)
|
||||
w.close()
|
||||
end),
|
||||
neoux.tchdivider(1, #fmt + 1, 21),
|
||||
neoux.tcrawview(1, 1, fmt),
|
||||
}, function (w)
|
||||
rsp(false)
|
||||
w.close()
|
||||
end, 0xFFFFFF, 0))
|
||||
nexus.close(w)
|
||||
end},
|
||||
{"<Yes>", function (w)
|
||||
rsp(true)
|
||||
nexus.close(w)
|
||||
end}
|
||||
}
|
||||
nexus.createNexusThread(function ()
|
||||
local window = nexus.create(totalW, #fmt, "security")
|
||||
local cButton = 0
|
||||
local ev, a, b, c
|
||||
while true do
|
||||
if not ev then
|
||||
ev, a, b, c = coroutine.yield()
|
||||
end
|
||||
if ev == "line" or ev == "touch" then
|
||||
local cor = b
|
||||
if ev == "line" then
|
||||
cor = a
|
||||
if fmt[a] then
|
||||
window.span(1, a, fmt[a], 0xFFFFFF, 0)
|
||||
end
|
||||
end
|
||||
if cor == #fmt then
|
||||
local x = 1
|
||||
for k, v in ipairs(buttons) do
|
||||
if ev == "line" then
|
||||
if k ~= cButton + 1 then
|
||||
window.span(x, a, v[1], 0xFFFFFF, 0)
|
||||
else
|
||||
window.span(x, a, v[1], 0, 0xFFFFFF)
|
||||
end
|
||||
elseif a >= x and a < (x + #v[1]) then
|
||||
cButton = k - 1
|
||||
ev = "key"
|
||||
a = 32
|
||||
b = 0
|
||||
c = true
|
||||
break
|
||||
end
|
||||
x = x + #v[1] + 1
|
||||
end
|
||||
end
|
||||
elseif ev == "close" then
|
||||
rsp(false)
|
||||
nexus.close(window)
|
||||
return
|
||||
end
|
||||
if ev == "key" then
|
||||
if c and (a == 9 or b == 205) then
|
||||
cButton = (cButton + 1) % #buttons
|
||||
ev = "line"
|
||||
a = #fmt
|
||||
elseif c and b == 203 then
|
||||
cButton = (cButton - 1) % #buttons
|
||||
ev = "line"
|
||||
a = #fmt
|
||||
elseif c and (a == 13 or a == 32) then
|
||||
buttons[cButton + 1][2](window)
|
||||
ev = nil
|
||||
else
|
||||
ev = nil
|
||||
end
|
||||
else
|
||||
ev = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
else
|
||||
rsp(res == "allow")
|
||||
end
|
||||
|
@ -7,3 +7,11 @@ rm code.tar
|
||||
# Hey, look behind you, there's nothing to see here.
|
||||
# ... ok, are they seriously all named "Mann"?
|
||||
tar --owner=gray:0 --group=mann:0 -cf code.tar code
|
||||
lua heroes.lua `wc -c code.tar` > inst.lua
|
||||
|
||||
stat repobuild/data/app-claw/local.lua && rm -rf repobuild
|
||||
mkdir repobuild
|
||||
cp -r code/* repobuild/
|
||||
cp -r repository/* repobuild/
|
||||
cp inst.lua repobuild/
|
||||
lua clawmerge.lua repository/data/app-claw/local.lua code/data/app-claw/local.lua > repobuild/data/app-claw/local.lua
|
||||
|
Loading…
Reference in New Issue
Block a user