mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-12-25 02:18:07 +11:00
Just make everything *better*.
This commit is contained in:
parent
36afa760c4
commit
c2b373f261
@ -3,59 +3,48 @@
|
||||
|
||||
-- app-claw: Package manager.
|
||||
|
||||
-- HTTP-only because OCEmu SUCKS
|
||||
local source = "http://20kdc.duckdns.org/neo/"
|
||||
|
||||
local primaryINet = neo.requestAccess("c.internet")
|
||||
if primaryINet then primaryINet = primaryINet.list()() end
|
||||
|
||||
local function pkgExists(pkg, isApp)
|
||||
local b = {}
|
||||
if isApp then
|
||||
b = neo.listApps()
|
||||
else
|
||||
b = neo.listLibs()
|
||||
end
|
||||
for _, v in ipairs(b) do
|
||||
if v == pkg then return true end
|
||||
end
|
||||
end
|
||||
|
||||
-- global app variables
|
||||
-- elements:
|
||||
-- {
|
||||
-- description,
|
||||
-- dlURL/nil,
|
||||
-- localPath,
|
||||
-- isApp,
|
||||
-- }
|
||||
local packages = {}
|
||||
local packageList = {}
|
||||
local libList = {} -- removed after scan
|
||||
local windows = 1
|
||||
local searchTx = ""
|
||||
local primaryWindowRegen
|
||||
--
|
||||
|
||||
-- libs & such
|
||||
local event = require("event")(neo)
|
||||
local neoux, err = require("neoux")
|
||||
if not neoux then error(err) end
|
||||
neoux = neoux(event, neo)
|
||||
local claw = require("claw")()
|
||||
|
||||
local function download(url)
|
||||
-- HTTP-only because OCEmu SUCKS
|
||||
local source = "http://20kdc.duckdns.org/neo/"
|
||||
local disks = neo.requireAccess("c.filesystem", "searching disks for packages")
|
||||
local primaryDisk = disks.primary
|
||||
local primaryINet = neo.requestAccess("c.internet")
|
||||
if primaryINet then primaryINet = primaryINet.list()() end
|
||||
|
||||
--
|
||||
|
||||
local function yielder()
|
||||
-- slightly dangerous, but what can we do?
|
||||
event.sleepTo(os.uptime() + 0.05)
|
||||
end
|
||||
|
||||
local function download(url, cb)
|
||||
if not primaryINet then return nil, "no internet" end
|
||||
local req, err = primaryINet.request(url)
|
||||
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)
|
||||
end
|
||||
local dt = ""
|
||||
while true do
|
||||
local n, n2 = req.read()
|
||||
local o, r = cb(n)
|
||||
if not o then
|
||||
req.close()
|
||||
return nil, r
|
||||
end
|
||||
if not n then
|
||||
req.close()
|
||||
if n2 then
|
||||
@ -65,274 +54,280 @@ local function download(url)
|
||||
end
|
||||
else
|
||||
if n == "" then
|
||||
-- slightly dangerous, but what can we do?
|
||||
event.sleepTo(os.uptime() + 0.05)
|
||||
yielder()
|
||||
end
|
||||
dt = dt .. n
|
||||
end
|
||||
end
|
||||
req.close()
|
||||
return dt
|
||||
return true
|
||||
end
|
||||
|
||||
local function readLocal()
|
||||
-- Read apps & libs
|
||||
local function isLua(v)
|
||||
if v:sub(#v - 3) == ".lua" then
|
||||
return v:sub(1, #v - 4)
|
||||
local function fsSrc(disk)
|
||||
return function (url, cb)
|
||||
local h, e = disk.open(url, "rb")
|
||||
if not h then cb(nil) return nil, tostring(e) end
|
||||
local c = ""
|
||||
while c do
|
||||
c = disk.read(h, neo.readBufSize)
|
||||
local o, r = cb(c)
|
||||
if not o then return nil, r end
|
||||
end
|
||||
end
|
||||
for _, pkg in ipairs(neo.listApps()) do
|
||||
table.insert(packageList, pkg)
|
||||
packages[pkg] = {
|
||||
"A pre-installed or self-written process.",
|
||||
nil,
|
||||
"apps/" .. pkg .. ".lua",
|
||||
true
|
||||
}
|
||||
end
|
||||
for _, pkg in ipairs(neo.listLibs()) do
|
||||
table.insert(libList, pkg)
|
||||
packages[pkg] = {
|
||||
"A pre-installed or self-written library.",
|
||||
nil,
|
||||
"libs/" .. pkg .. ".lua",
|
||||
false
|
||||
}
|
||||
disk.close(h)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function getEntry(name, isApp)
|
||||
if packages[name] then
|
||||
if packages[name][4] ~= isApp then
|
||||
return
|
||||
end
|
||||
else
|
||||
local path = "libs/" .. name .. ".lua"
|
||||
if isApp then
|
||||
path = "apps/" .. name .. ".lua"
|
||||
end
|
||||
packages[name] = {"An unknown entry, lost to time.", nil, path, isApp}
|
||||
if isApp then
|
||||
table.insert(packageList, name)
|
||||
else
|
||||
table.insert(libList, name)
|
||||
end
|
||||
end
|
||||
return packages[name]
|
||||
end
|
||||
|
||||
local function readWeb()
|
||||
local listData, err = download(source .. "list")
|
||||
if not listData then
|
||||
neoux.startDialog("Couldn't get web index: " .. err, "web", true)
|
||||
return
|
||||
end
|
||||
--neoux.startDialog(listData, "web", false)
|
||||
listData = (listData .. "\n"):gmatch(".-\n")
|
||||
local function listDataStrip()
|
||||
local l = listData()
|
||||
if not l then
|
||||
return
|
||||
end
|
||||
l = l:sub(1, #l - 1)
|
||||
return l
|
||||
end
|
||||
while true do
|
||||
local l = listDataStrip()
|
||||
if not l then return end
|
||||
if l == "end" then return end
|
||||
local ent = getEntry(l:sub(5), l:sub(1, 4) == "app ")
|
||||
if ent then
|
||||
ent[1] = listDataStrip() or "PARSE ERROR"
|
||||
ent[2] = source .. l:sub(5) .. ".lua"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
readLocal()
|
||||
if source then
|
||||
readWeb()
|
||||
end
|
||||
|
||||
table.sort(packageList)
|
||||
table.sort(libList)
|
||||
for _, v in ipairs(libList) do
|
||||
table.insert(packageList, v)
|
||||
end
|
||||
libList = nil
|
||||
|
||||
local function startPackageWindow(pkg)
|
||||
windows = windows + 1
|
||||
local downloading = false
|
||||
local desc = packages[pkg][1]
|
||||
local isApp = packages[pkg][4]
|
||||
local isSysSvc = isApp and (pkg:sub(1, 4) == "sys-")
|
||||
local isSvc = isSysSvc or (isApp and (pkg:sub(1, 4) == "svc-"))
|
||||
local settings
|
||||
if isSvc then
|
||||
settings = neo.requestAccess("x.neo.sys.manage")
|
||||
end
|
||||
local function update(w)
|
||||
if downloading then return end
|
||||
downloading = true
|
||||
local fd = download(packages[pkg][2])
|
||||
local msg = "Success!"
|
||||
if fd then
|
||||
local primaryDisk = neo.requestAccess("c.filesystem").primary
|
||||
local f = primaryDisk.open(packages[pkg][3], "wb")
|
||||
primaryDisk.write(f, fd)
|
||||
primaryDisk.close(f)
|
||||
else
|
||||
msg = "Couldn't download."
|
||||
end
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
primaryWindowRegen()
|
||||
-- Another event loop so the program won't exit too early.
|
||||
neoux.startDialog(msg, pkg, true)
|
||||
downloading = false
|
||||
end
|
||||
|
||||
local elems = {
|
||||
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(desc), 30)),
|
||||
}
|
||||
-- {txt, run}
|
||||
local buttonbar = {}
|
||||
if pkgExists(pkg, isApp) then
|
||||
if isApp then
|
||||
if not isSvc then
|
||||
table.insert(buttonbar, {"Start", function (w)
|
||||
neo.executeAsync(pkg)
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
end})
|
||||
local function fsDst(disk)
|
||||
return {function (url)
|
||||
local h, e = disk.open(url, "wb")
|
||||
if not h then return nil, tostring(e) end
|
||||
return function (d)
|
||||
local ok, r = true
|
||||
if d then
|
||||
ok, r = disk.write(h, d)
|
||||
else
|
||||
if not isSysSvc then
|
||||
table.insert(buttonbar, {"Start", function (w)
|
||||
neo.executeAsync(pkg)
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
end})
|
||||
end
|
||||
if settings.getSetting("run." .. pkg) == "yes" then
|
||||
table.insert(buttonbar, {"Disable", function (w)
|
||||
settings.setSetting("run." .. pkg, "no")
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
end})
|
||||
else
|
||||
table.insert(buttonbar, {"Enable", function (w)
|
||||
settings.setSetting("run." .. pkg, "yes")
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
end})
|
||||
end
|
||||
disk.close(h)
|
||||
end
|
||||
if not ok then return nil, tostring(r) end
|
||||
return true
|
||||
end
|
||||
if packages[pkg][2] then
|
||||
table.insert(buttonbar, {"Update", update})
|
||||
end, disk.makeDirectory, disk.exists, disk.isDirectory, disk.remove, disk.rename}
|
||||
end
|
||||
|
||||
local function checked(...)
|
||||
local res, res2, err = pcall(...)
|
||||
if not res then
|
||||
neoux.startDialog(tostring(res2), "error!", true)
|
||||
elseif not res2 then
|
||||
neoux.startDialog(tostring(err), "failed!", true)
|
||||
else
|
||||
return res2
|
||||
end
|
||||
end
|
||||
|
||||
-- Beginning Of The App (well, the actual one)
|
||||
|
||||
local genCurrent, genPrimary, genPackage, primaryWindow
|
||||
local windows = 1
|
||||
|
||||
-- primary
|
||||
local primarySearchTx = ""
|
||||
local primaryPage = 1
|
||||
local primaryList = {}
|
||||
-- package
|
||||
local packageLock = nil
|
||||
local packageId = "FIXME"
|
||||
|
||||
local function describe(pkg)
|
||||
local weHave = claw.getInfo(pkg, "local")
|
||||
local theyHave = claw.getInfo(pkg, "local")
|
||||
local someoneHas = claw.getInfo(pkg, nil, true)
|
||||
if weHave then
|
||||
if theyHave.v > weHave.v then
|
||||
return pkg .. " [v" .. weHave.v .. "!]"
|
||||
end
|
||||
table.insert(buttonbar, {"Delete", function (w)
|
||||
local primaryDisk = neo.requestAccess("c.filesystem").primary
|
||||
primaryDisk.remove(packages[pkg][3])
|
||||
if someoneHas.v < weHave.v then
|
||||
return pkg .. " (v" .. weHave.v .. ") R<"
|
||||
end
|
||||
return pkg .. " (v" .. weHave.v .. ")"
|
||||
end
|
||||
return pkg
|
||||
end
|
||||
|
||||
local function primaryWindowRegenCore()
|
||||
return neoux.tcwindow(25, 12, genCurrent(), function (w)
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
primaryWindowRegen()
|
||||
end})
|
||||
else
|
||||
if packages[pkg][2] then
|
||||
table.insert(buttonbar, {"Install", update})
|
||||
end, 0xFF8F00, 0)
|
||||
end
|
||||
local function primaryWindowRegen()
|
||||
primaryWindow.reset(25, 12, primaryWindowRegenCore())
|
||||
end
|
||||
|
||||
-- Use all non-primary filesystems
|
||||
for pass = 1, 3 do
|
||||
for v in disks.list() do
|
||||
local nam = nil
|
||||
if v == primaryDisk then
|
||||
nam = (pass == 1) and "local"
|
||||
elseif v == disks.temporary then
|
||||
nam = (pass == 2) and "ramfs"
|
||||
elseif pass == 3 then
|
||||
nam = v.address
|
||||
end
|
||||
if nam then
|
||||
local ok, r = claw.addSource(nam, fsSrc(v), (not v.isReadOnly()) and fsDst(v))
|
||||
if not ok and nam == "local" then
|
||||
claw.unlock()
|
||||
error(r)
|
||||
end
|
||||
end
|
||||
end
|
||||
local x = 1
|
||||
for _, v in ipairs(buttonbar) do
|
||||
local b = neoux.tcbutton(x, 10, v[1], v[2])
|
||||
x = x + (#v[1]) + 2
|
||||
table.insert(elems, b)
|
||||
end
|
||||
neoux.create(30, 10, pkg, neoux.tcwindow(30, 10, elems, function (w)
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
end, 0xFFFFFF, 0))
|
||||
end
|
||||
|
||||
local genwin, primaryWindow
|
||||
local primaryWindowPage = 1
|
||||
local primaryWindowList = packageList
|
||||
|
||||
function primaryWindowRegen()
|
||||
primaryWindow.reset(20, 8, genwin(primaryWindowPage, primaryWindowList))
|
||||
if primaryINet then
|
||||
checked(claw.addSource, "inet", download)
|
||||
end
|
||||
|
||||
genwin = function (page, efList)
|
||||
local pages = math.ceil(#efList / 6)
|
||||
primaryList = claw.getList()
|
||||
|
||||
-- Sections
|
||||
|
||||
function genPrimary()
|
||||
local pgs = 10
|
||||
local pages = math.ceil(#primaryList / pgs)
|
||||
local elems = {
|
||||
neoux.tcbutton(18, 1, "+", function (w)
|
||||
if page < pages then
|
||||
primaryWindowPage = page + 1
|
||||
neoux.tcbutton(23, 1, "+", function (w)
|
||||
if primaryPage < pages then
|
||||
primaryPage = primaryPage + 1
|
||||
primaryWindowRegen()
|
||||
end
|
||||
end),
|
||||
neoux.tcrawview(4, 1, {neoux.pad(page .. " / " .. pages, 14, true, true)}),
|
||||
neoux.tcrawview(4, 1, {neoux.pad(primaryPage .. " / " .. pages, 19, true, true)}),
|
||||
neoux.tcbutton(1, 1, "-", function (w)
|
||||
if page > 1 then
|
||||
primaryWindowPage = page - 1
|
||||
if primaryPage > 1 then
|
||||
primaryPage = primaryPage - 1
|
||||
primaryWindowRegen()
|
||||
end
|
||||
end)
|
||||
}
|
||||
local base = (page - 1) * 6
|
||||
for i = 1, 6 do
|
||||
local ent = efList[base + i]
|
||||
local base = (primaryPage - 1) * pgs
|
||||
for i = 1, pgs do
|
||||
local ent = primaryList[base + i]
|
||||
if ent then
|
||||
local enttx = ent
|
||||
if packages[ent][4] then
|
||||
enttx = "A " .. enttx
|
||||
else
|
||||
enttx = "L " .. enttx
|
||||
end
|
||||
if pkgExists(ent, packages[ent][4]) then
|
||||
if packages[ent][2] then
|
||||
enttx = "I" .. enttx
|
||||
else
|
||||
enttx = "i" .. enttx
|
||||
end
|
||||
else
|
||||
enttx = " " .. enttx
|
||||
end
|
||||
local enttx = describe(ent)
|
||||
table.insert(elems, neoux.tcbutton(1, i + 1, unicode.safeTextFormat(enttx), function (w)
|
||||
-- Start a dialog
|
||||
startPackageWindow(ent)
|
||||
packageId = ent
|
||||
genCurrent = genPackage
|
||||
primaryWindowRegen()
|
||||
end))
|
||||
end
|
||||
end
|
||||
table.insert(elems, neoux.tcfield(1, 8, 11, function (s)
|
||||
if s then searchTx = s end
|
||||
return searchTx
|
||||
table.insert(elems, neoux.tcfield(1, 12, 16, function (s)
|
||||
if s then primarySearchTx = s end
|
||||
return primarySearchTx
|
||||
end))
|
||||
table.insert(elems, neoux.tcbutton(12, 8, "Search!", function (w)
|
||||
table.insert(elems, neoux.tcbutton(17, 12, "Search!", function (w)
|
||||
local n = {}
|
||||
for _, v in ipairs(packageList) do
|
||||
for _, v in ipairs(claw.getList()) do
|
||||
for i = 1, #v do
|
||||
if v:sub(i, i + #searchTx - 1) == searchTx then
|
||||
if v:sub(i, i + #primarySearchTx - 1) == primarySearchTx then
|
||||
table.insert(n, v)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
primaryWindowPage = 1
|
||||
primaryWindowList = n
|
||||
primaryPage = 1
|
||||
primaryList = n
|
||||
primaryWindowRegen()
|
||||
end))
|
||||
return neoux.tcwindow(20, 8, elems, function (w)
|
||||
w.close()
|
||||
windows = windows - 1
|
||||
end, 0xFFFFFF, 0)
|
||||
return elems
|
||||
end
|
||||
|
||||
primaryWindow = neoux.create(20, 8, "claw", genwin(1, packageList))
|
||||
--
|
||||
|
||||
local function packageGetBB(src, lclI, srcI, srcW)
|
||||
local buttons = {}
|
||||
if srcI and srcW then
|
||||
table.insert(buttons, {
|
||||
"Del",
|
||||
function ()
|
||||
if packageLock then return end
|
||||
packageLock = ""
|
||||
checked(claw.remove, src, packageId, true)
|
||||
packageLock = nil
|
||||
primaryWindowRegen()
|
||||
end
|
||||
})
|
||||
end
|
||||
if srcI and ((not lclI) or (lclI.v < srcI.v)) then
|
||||
table.insert(buttons, {
|
||||
"Get",
|
||||
function ()
|
||||
if packageLock then return end
|
||||
packageLock = "installing from " .. src
|
||||
primaryWindowRegen()
|
||||
checked(claw.installTo, "local", packageId, src, true, yielder)
|
||||
packageLock = nil
|
||||
primaryWindowRegen()
|
||||
end
|
||||
})
|
||||
end
|
||||
if srcW and lclI and not srcI then
|
||||
table.insert(buttons, {
|
||||
"All",
|
||||
function ()
|
||||
if packageLock then return end
|
||||
packageLock = "storing w/ dependencies at " .. src
|
||||
primaryWindowRegen()
|
||||
checked(claw.installTo, src, packageId, "local", true, yielder)
|
||||
packageLock = nil
|
||||
primaryWindowRegen()
|
||||
end
|
||||
})
|
||||
table.insert(buttons, {
|
||||
"Put",
|
||||
function ()
|
||||
if packageLock then return end
|
||||
packageLock = "storing at " .. src
|
||||
primaryWindowRegen()
|
||||
checked(claw.installTo, src, packageId, "local", false, yielder)
|
||||
packageLock = nil
|
||||
primaryWindowRegen()
|
||||
end
|
||||
})
|
||||
end
|
||||
return buttons
|
||||
end
|
||||
|
||||
function genPackage()
|
||||
if packageLock then
|
||||
return {neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(packageId .. "\n" .. packageLock), 25))}
|
||||
end
|
||||
-- concept:
|
||||
-- mtd <back>
|
||||
-- Multi-Track Drifting
|
||||
--
|
||||
-- local v20 <del> <run>
|
||||
-- inet v21 <pull>
|
||||
-- dir v22 <pull> <push>
|
||||
-- crockett <push>
|
||||
local info = claw.getInfo(packageId)
|
||||
local infoL = claw.getInfo(packageId, "local")
|
||||
local elems = {
|
||||
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(packageId .. "\n" .. info.desc .. "\nv" .. info.v .. " deps " .. table.concat(info.deps, ", ")), 25)),
|
||||
neoux.tcbutton(20, 1, "Back", function ()
|
||||
if packageLock then return end
|
||||
genCurrent = genPrimary
|
||||
primaryWindowRegen()
|
||||
end)
|
||||
}
|
||||
local srcs = claw.getSources()
|
||||
for k, v in ipairs(srcs) do
|
||||
local lI = claw.getInfo(packageId, v[1])
|
||||
local row = 12 + k - #srcs
|
||||
local pfx = " "
|
||||
if lI then
|
||||
pfx = "v" .. string.format("%04i", lI.v) .. " "
|
||||
end
|
||||
table.insert(elems, neoux.tcrawview(1, row, {neoux.pad(pfx .. v[1], 14, false, true)}))
|
||||
local col = 26
|
||||
for _, bv in ipairs(packageGetBB(v[1], infoL, lI, v[2])) do
|
||||
local b = neoux.tcbutton(col, row, bv[1], bv[2])
|
||||
col = col - b.w
|
||||
b.x = col
|
||||
table.insert(elems, b)
|
||||
end
|
||||
end
|
||||
return elems
|
||||
end
|
||||
|
||||
--
|
||||
|
||||
genCurrent = genPrimary
|
||||
primaryWindow = neoux.create(25, 12, "claw", primaryWindowRegenCore())
|
||||
|
||||
while windows > 0 do
|
||||
event.pull()
|
||||
end
|
||||
claw.unlock()
|
||||
|
@ -36,7 +36,8 @@ local ctrlFlag = false
|
||||
local dialogLock = false
|
||||
local appendFlag = false
|
||||
local sW, sH = 37, #lines + 2
|
||||
local window = neo.requestAccess("x.neo.pub.window")(sW, sH)
|
||||
local windows = neo.requestAccess("x.neo.pub.window")
|
||||
local window = windows(sW, sH)
|
||||
local flush
|
||||
|
||||
local function splitCur()
|
||||
@ -55,13 +56,24 @@ local function clampCursorX()
|
||||
return false
|
||||
end
|
||||
|
||||
local cbs = {}
|
||||
|
||||
local function fileDialog(writing, callback)
|
||||
local tag = neo.requestAccess("x.neo.pub.base").showFileDialogAsync(writing)
|
||||
local f
|
||||
function f(_, evt, tag2, res)
|
||||
if evt == "filedialog" then
|
||||
if tag == tag2 then
|
||||
callback(res)
|
||||
local ok, e = pcall(callback, res)
|
||||
if not ok then
|
||||
e = unicode.safeTextFormat(tostring(e))
|
||||
local wnd = windows(unicode.len(e), 1, "ERROR")
|
||||
cbs[wnd.id] = {
|
||||
wnd.close,
|
||||
wnd.span,
|
||||
e
|
||||
}
|
||||
end
|
||||
event.ignore(f)
|
||||
end
|
||||
end
|
||||
@ -410,6 +422,14 @@ while true do
|
||||
ev_clipboard(e[4])
|
||||
flush()
|
||||
end
|
||||
elseif cbs[e[2]] then
|
||||
if e[3] == "line" then
|
||||
cbs[e[2]][2](1, 1, cbs[e[2]][3], 0, 0xFFFFFF)
|
||||
end
|
||||
if e[3] == "close" then
|
||||
cbs[e[2]][1]()
|
||||
cbs[e[2]] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -26,9 +26,7 @@
|
||||
-- or this is a screensaver host, and has a saving-throw to start Bristol if it dies unexpectedly.
|
||||
-- In any case, this eventually returns to 2 or 4.
|
||||
|
||||
local everestProvider = neo.requestAccess("r.neo.pub.window", "registering npw")
|
||||
if not everestProvider then return end
|
||||
|
||||
local everestProvider = neo.requireAccess("r.neo.pub.window", "registering npw")
|
||||
local everestSessionProvider = neo.requireAccess("r.neo.sys.session", "registering nsse")
|
||||
|
||||
-- Got mutexes. Now setup saving throw and shutdown callback
|
||||
@ -57,6 +55,9 @@ monitors[0] = {nil, nil, 160, 50}
|
||||
-- line y
|
||||
local surfaces = {}
|
||||
|
||||
-- Last Interact Monitor
|
||||
local lIM = 1
|
||||
|
||||
-- Stops the main loop
|
||||
local shuttingDown = false
|
||||
|
||||
@ -98,7 +99,7 @@ local function surfaceAt(monitor, x, y)
|
||||
end
|
||||
end
|
||||
|
||||
-- Always use the first sometime before the second
|
||||
-- Always use the first if the GPU has been rebound
|
||||
local function monitorResetBF(m)
|
||||
m[5] = -1
|
||||
m[6] = -1
|
||||
@ -136,9 +137,11 @@ end
|
||||
local function updateRegion(monitorId, x, y, w, h, surfaceSpanCache)
|
||||
if not renderingAllowed() then return end
|
||||
local m = monitors[monitorId]
|
||||
local mg = m[1]()
|
||||
local mg, rb = m[1]()
|
||||
if not mg then return end
|
||||
monitorResetBF(m)
|
||||
if rb then
|
||||
monitorResetBF(m)
|
||||
end
|
||||
-- The input region is the one that makes SENSE.
|
||||
-- Considering WC handling, that's not an option.
|
||||
-- WCHAX: start
|
||||
@ -198,7 +201,7 @@ local function ensureOnscreen(monitor, x, y, w, h)
|
||||
-- Failing anything else, revert to monitor 0
|
||||
if #monitors == 0 then monitor = 0 end
|
||||
x = math.min(math.max(1, x), monitors[monitor][3] - (w - 1))
|
||||
y = math.min(math.max(1, y), monitors[monitor][4] - (h - 1))
|
||||
y = math.max(1, math.min(monitors[monitor][4] - (h - 1), y))
|
||||
return monitor, x, y
|
||||
end
|
||||
|
||||
@ -209,7 +212,10 @@ local function reconcileAll()
|
||||
v[1], v[2], v[3] = ensureOnscreen(v[1], v[2], v[3], v[4], v[5])
|
||||
end
|
||||
for k, v in ipairs(monitors) do
|
||||
local mon = v[1]()
|
||||
local mon, rb = v[1]()
|
||||
if rb then
|
||||
monitorResetBF(v)
|
||||
end
|
||||
if mon then
|
||||
v[3], v[4] = mon.getResolution()
|
||||
end
|
||||
@ -218,7 +224,8 @@ local function reconcileAll()
|
||||
updateStatus()
|
||||
end
|
||||
|
||||
local function moveSurface(surface, m, x, y, w, h)
|
||||
-- NOTE: If the M, X, Y, W and H are the same, this function ignores you, unless you put , true on the end.
|
||||
local function moveSurface(surface, m, x, y, w, h, force)
|
||||
local om, ox, oy, ow, oh = table.unpack(surface, 1, 5)
|
||||
m = m or om
|
||||
x = x or ox
|
||||
@ -227,24 +234,18 @@ local function moveSurface(surface, m, x, y, w, h)
|
||||
h = h or oh
|
||||
surface[1], surface[2], surface[3], surface[4], surface[5] = m, x, y, w, h
|
||||
local cache = {}
|
||||
if om == m then
|
||||
if ow == w then
|
||||
if oh == h then
|
||||
-- Cheat - perform a GPU copy
|
||||
-- this increases "apparent" performance while we're inevitably waiting for the app to catch up,
|
||||
-- CANNOT glitch since we're going to draw over this later,
|
||||
-- and will usually work since the user can only move focused surfaces
|
||||
if renderingAllowed() then
|
||||
local cb = monitors[m][1]()
|
||||
if cb then
|
||||
cb.copy(ox, oy, w, h, x - ox, y - oy)
|
||||
end
|
||||
end
|
||||
--because OC's widechar support sucks, comment out this perf. opt.
|
||||
--if surfaces[1] == surface then
|
||||
-- updateRegion(om, ox, oy, ow, oh, cache)
|
||||
-- return
|
||||
--end
|
||||
if om == m and ow == w and oh == h then
|
||||
if ox == x and oy == y and not force then
|
||||
return
|
||||
end
|
||||
-- note: this doesn't always work due to WC support
|
||||
if renderingAllowed() then
|
||||
local cb, b = monitors[m][1]()
|
||||
if b then
|
||||
monitorResetBF(b)
|
||||
end
|
||||
if cb then
|
||||
cb.copy(ox, oy, w, h, x - ox, y - oy)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -266,9 +267,11 @@ end
|
||||
local function handleSpan(target, x, y, text, bg, fg)
|
||||
if not renderingAllowed() then return end
|
||||
local m = monitors[target[1]]
|
||||
local cb = m[1]()
|
||||
local cb, rb = m[1]()
|
||||
if not cb then return end
|
||||
monitorResetBF(m)
|
||||
if rb then
|
||||
monitorResetBF(m)
|
||||
end
|
||||
-- It is assumed basic type checks were handled earlier.
|
||||
if y < 1 then return end
|
||||
if y > target[5] then return end
|
||||
@ -366,8 +369,7 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
end
|
||||
local m = 0
|
||||
if renderingAllowed() then m = 1 end
|
||||
if surfaces[1] then m = surfaces[1][1] end
|
||||
local surf = {m, 1, 2, w, h}
|
||||
local surf = {math.min(#monitors, math.max(1, lIM)), 1, 2, w, h}
|
||||
local focusState = false
|
||||
local llid = lid
|
||||
lid = lid + 1
|
||||
@ -380,6 +382,10 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
if ev == "touch" then
|
||||
specialDragHandler = nil
|
||||
if math.floor(b) == 1 then
|
||||
if e == 1 then
|
||||
sendSig(llid, "close")
|
||||
return
|
||||
end
|
||||
specialDragHandler = function (x, y)
|
||||
local ofsX, ofsY = math.floor(x) - math.floor(a), math.floor(y) - math.floor(b)
|
||||
if (ofsX == 0) and (ofsY == 0) then return end
|
||||
@ -397,6 +403,7 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
b = b - 1
|
||||
end
|
||||
if ev == "scroll" or ev == "drop" then
|
||||
specialDragHandler = nil
|
||||
b = b - 1
|
||||
end
|
||||
if ev == "line" then
|
||||
@ -435,7 +442,7 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
w = math.floor(math.max(w, 8))
|
||||
h = math.floor(math.max(h, 1)) + 1
|
||||
local _, x, y = ensureOnscreen(surf[1], surf[2], surf[3], w, h)
|
||||
moveSurface(surf, nil, x, y, w, h)
|
||||
moveSurface(surf, nil, x, y, w, h, true)
|
||||
return w, (h - 1)
|
||||
end,
|
||||
span = function (x, y, text, bg, fg)
|
||||
@ -538,6 +545,7 @@ local function key(ka, kc, down)
|
||||
end
|
||||
end
|
||||
if focus then
|
||||
lIM = focus[1]
|
||||
focus[6]("key", ka, kc, down)
|
||||
end
|
||||
end
|
||||
@ -577,6 +585,7 @@ while not shuttingDown do
|
||||
if s[1] == "h.touch" then
|
||||
for k, v in ipairs(monitors) do
|
||||
if v[2] == s[2] then
|
||||
lIM = k
|
||||
local x, y = math.floor(s[3]), math.floor(s[4])
|
||||
local ix, iy = s[3] - x, s[4] - y
|
||||
local sid, lx, ly = surfaceAt(k, x, y)
|
||||
@ -586,6 +595,8 @@ while not shuttingDown do
|
||||
table.insert(surfaces, 1, ns)
|
||||
changeFocus(os)
|
||||
ns[6]("touch", lx, ly, ix, iy, s[5])
|
||||
else
|
||||
if s[5] == 1 and not waitingShutdownCallback then neo.executeAsync("app-launcher") end
|
||||
end
|
||||
break
|
||||
end
|
||||
|
@ -263,11 +263,13 @@ donkonitRDProvider(function (pkg, pid, sendSig)
|
||||
return function ()
|
||||
for v in gpus.list() do
|
||||
if v.address == gpu then
|
||||
local didBind = false
|
||||
if currentGPUBinding[gpu] ~= address then
|
||||
v.bind(address, false)
|
||||
didBind = true
|
||||
end
|
||||
currentGPUBinding[gpu] = address
|
||||
return v
|
||||
return v, didBind
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -110,27 +110,24 @@ end)
|
||||
local rootAccess = neo.requireAccess("k.root", "installing GUI integration")
|
||||
local backup = rootAccess.securityPolicyINIT or rootAccess.securityPolicy
|
||||
rootAccess.securityPolicyINIT = backup
|
||||
rootAccess.securityPolicy = function (pid, proc, req)
|
||||
rootAccess.securityPolicy = function (pid, proc, perm, req)
|
||||
if neo.dead then
|
||||
return backup(pid, proc, req)
|
||||
return backup(pid, proc, perm, req)
|
||||
end
|
||||
req.result = proc.pkg:sub(1, 4) == "sys-"
|
||||
local def = proc.pkg:sub(1, 4) == "sys-"
|
||||
local secpol, err = require("sys-secpolicy")
|
||||
if not secpol then
|
||||
-- Failsafe.
|
||||
neo.emergency("Used fallback policy because of load-err: " .. err)
|
||||
req.service()
|
||||
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, req.perm, function (r)
|
||||
req.result = r
|
||||
req.service()
|
||||
end)
|
||||
local ok, err = pcall(secpol, neoux, settings, proc.pkg, pid, perm, req)
|
||||
if not ok then
|
||||
neo.emergency("Used fallback policy because of run-err: " .. err)
|
||||
req.service()
|
||||
req(def)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@ -153,6 +153,9 @@ local function finalPrompt()
|
||||
local password = ""
|
||||
if nsm then
|
||||
password = nsm.getSetting("password")
|
||||
if nsm.getSetting("sys-init.nologin") == "yes" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
warnings[1] = "TAB to change option,"
|
||||
warnings[2] = "ENTER to select..."
|
||||
|
@ -2,7 +2,6 @@ return {
|
||||
["neo"] = {
|
||||
desc = "KittenOS NEO Kernel & Base Libs",
|
||||
v = 0,
|
||||
app = false,
|
||||
deps = {
|
||||
},
|
||||
dirs = {
|
||||
@ -12,6 +11,7 @@ return {
|
||||
},
|
||||
files = {
|
||||
"init.lua",
|
||||
"apps/sys-glacier.lua",
|
||||
"libs/event.lua",
|
||||
"libs/serial.lua",
|
||||
"libs/neoux.lua",
|
||||
@ -21,10 +21,8 @@ return {
|
||||
["neo-init"] = {
|
||||
desc = "KittenOS NEO / sys-init (startup)",
|
||||
v = 0,
|
||||
app = "app-launcher",
|
||||
deps = {
|
||||
"neo",
|
||||
"neo-glacier",
|
||||
"neo-icecap",
|
||||
"neo-everest"
|
||||
},
|
||||
@ -38,7 +36,6 @@ return {
|
||||
["neo-launcher"] = {
|
||||
desc = "KittenOS NEO / Default app-launcher",
|
||||
v = 0,
|
||||
app = "app-launcher",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -50,9 +47,8 @@ return {
|
||||
},
|
||||
},
|
||||
["neo-everest"] = {
|
||||
desc = "KittenOS NEO / Everest (settings & monitor management)",
|
||||
desc = "KittenOS NEO / Everest (windowing)",
|
||||
v = 0,
|
||||
app = "sys-everest",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -66,7 +62,6 @@ return {
|
||||
["neo-icecap"] = {
|
||||
desc = "KittenOS NEO / Icecap",
|
||||
v = 0,
|
||||
app = "sys-icecap",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -81,24 +76,21 @@ return {
|
||||
"apps/app-fm.lua"
|
||||
},
|
||||
},
|
||||
["neo-glacier"] = {
|
||||
desc = "KittenOS NEO / Glacier (settings & monitor management)",
|
||||
["neo-secpolicy"] = {
|
||||
desc = "KittenOS NEO / Secpolicy",
|
||||
v = 0,
|
||||
app = "sys-glacier",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
dirs = {
|
||||
"apps"
|
||||
"libs"
|
||||
},
|
||||
files = {
|
||||
"apps/sys-glacier.lua"
|
||||
},
|
||||
"libs/sys-secpolicy.lua"
|
||||
}
|
||||
},
|
||||
["app-textedit"] = {
|
||||
desc = "KittenOS NEO Text Editor (Neolithic)",
|
||||
["neo-coreapps"] = {
|
||||
desc = "KittenOS NEO Core Apps",
|
||||
v = 0,
|
||||
app = "app-textedit",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -106,13 +98,14 @@ return {
|
||||
"apps"
|
||||
},
|
||||
files = {
|
||||
"apps/app-textedit.lua"
|
||||
},
|
||||
"apps/app-textedit.lua",
|
||||
"apps/app-pass.lua",
|
||||
"apps/app-taskmgr.lua"
|
||||
}
|
||||
},
|
||||
["app-flash"] = {
|
||||
desc = "KittenOS NEO EEPROM Flasher",
|
||||
v = 0,
|
||||
app = "app-flash",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -123,38 +116,9 @@ return {
|
||||
"apps/app-flash.lua"
|
||||
},
|
||||
},
|
||||
["app-pass"] = {
|
||||
desc = "KittenOS NEO Password Setter & Logout",
|
||||
v = 0,
|
||||
app = "app-pass",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
dirs = {
|
||||
"apps"
|
||||
},
|
||||
files = {
|
||||
"apps/app-pass.lua"
|
||||
},
|
||||
},
|
||||
["app-taskmgr"] = {
|
||||
desc = "KittenOS NEO Task Manager",
|
||||
v = 0,
|
||||
app = "app-taskmgr",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
dirs = {
|
||||
"apps"
|
||||
},
|
||||
files = {
|
||||
"apps/app-taskmgr.lua"
|
||||
},
|
||||
},
|
||||
["app-claw"] = {
|
||||
desc = "KittenOS NEO Package Manager",
|
||||
v = 0,
|
||||
app = "app-claw",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -166,5 +130,24 @@ return {
|
||||
"apps/app-claw.lua",
|
||||
"libs/claw.lua"
|
||||
},
|
||||
},
|
||||
["neo-meta"] = {
|
||||
desc = "KittenOS NEO: Use 'All' to install to other disks",
|
||||
v = 0,
|
||||
deps = {
|
||||
"neo",
|
||||
"neo-init",
|
||||
"neo-launcher",
|
||||
"neo-everest",
|
||||
"neo-icecap",
|
||||
"neo-secpolicy",
|
||||
"neo-coreapps",
|
||||
"app-flash",
|
||||
"app-claw"
|
||||
},
|
||||
dirs = {
|
||||
},
|
||||
files = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,7 @@ primaryDisk = component.proxy(computer.getBootAddress())
|
||||
timers = {}
|
||||
|
||||
libraries = {}
|
||||
setmetatable(libraries, {
|
||||
__mode = "v"
|
||||
})
|
||||
setmetatable(libraries, {__mode = "v"})
|
||||
|
||||
-- proc.co = coroutine.create(appfunc)
|
||||
-- proc.pkg = "pkg"
|
||||
@ -89,7 +87,7 @@ function unicode.undoSafeTextFormat(s)
|
||||
end
|
||||
|
||||
local function loadfile(s, e)
|
||||
local h = primaryDisk.open(s)
|
||||
local h, er = primaryDisk.open(s)
|
||||
if h then
|
||||
local ch = ""
|
||||
local c = primaryDisk.read(h, readBufSize)
|
||||
@ -100,7 +98,7 @@ local function loadfile(s, e)
|
||||
primaryDisk.close(h)
|
||||
return load(ch, "=" .. s, "t", e)
|
||||
end
|
||||
return nil, "File Unreadable"
|
||||
return nil, tostring(er)
|
||||
end
|
||||
|
||||
local wrapMeta = nil
|
||||
@ -320,6 +318,7 @@ function loadLibraryInner(library)
|
||||
library = "libs/" .. library .. ".lua"
|
||||
ensurePath(library, "libs/")
|
||||
if libraries[library] then return libraries[library] end
|
||||
emergencyFunction("loading " .. library)
|
||||
local l, r = loadfile(library, baseProcEnv())
|
||||
if l then
|
||||
local ok, al = pcall(l)
|
||||
@ -335,10 +334,9 @@ end
|
||||
|
||||
-- These two are hooks for k.root level applications to change policy.
|
||||
-- Only a k.root application is allowed to do this for obvious reasons.
|
||||
function securityPolicy(pid, proc, req)
|
||||
function securityPolicy(pid, proc, perm, req)
|
||||
-- Important safety measure : only sys-* gets anything at first
|
||||
req.result = proc.pkg:sub(1, 4) == "sys-"
|
||||
req.service()
|
||||
req(proc.pkg:sub(1, 4) == "sys-")
|
||||
end
|
||||
function runProgramPolicy(ipkg, pkg, pid, ...)
|
||||
-- VERY specific injunction here:
|
||||
@ -489,13 +487,11 @@ function start(pkg, ...)
|
||||
local requestAccessAsync = function (perm)
|
||||
ensureType(perm, "string")
|
||||
-- Safety-checked, prepare security event.
|
||||
local req = {}
|
||||
req.perm = perm
|
||||
req.service = function ()
|
||||
local req = function (res)
|
||||
if processes[pid] then
|
||||
local n = nil
|
||||
local n2 = nil
|
||||
if req.result then
|
||||
if res then
|
||||
proc.access[perm] = true
|
||||
proc.denied[perm] = nil
|
||||
n, n2 = retrieveAccess(perm, pkg, pid)
|
||||
@ -509,16 +505,14 @@ function start(pkg, ...)
|
||||
end
|
||||
end
|
||||
-- outer security policy:
|
||||
req.result = proc.access["k.root"] or not proc.denied[perm]
|
||||
|
||||
if proc.access["k.root"] or proc.access[perm] or proc.denied[perm] then
|
||||
-- Use cached result to prevent possible unintentional security service spam
|
||||
req.service()
|
||||
req(proc.access["k.root"] or not proc.denied[perm])
|
||||
return
|
||||
end
|
||||
-- Denied goes to on to prevent spam
|
||||
proc.denied[perm] = true
|
||||
securityPolicy(pid, proc, req)
|
||||
securityPolicy(pid, proc, perm, req)
|
||||
end
|
||||
local env = baseProcEnv()
|
||||
env.neo.pid = pid
|
||||
@ -558,7 +552,7 @@ function start(pkg, ...)
|
||||
if not appfunc then
|
||||
return nil, r
|
||||
end
|
||||
proc.co = coroutine.create(appfunc)
|
||||
proc.co = coroutine.create(function (...) local r = {xpcall(appfunc, debug.traceback)} if not r[1] then error(table.unpack(r, 2)) end return table.unpack(r, 2) end)
|
||||
proc.pkg = pkg
|
||||
proc.access = {
|
||||
-- These permissions are the "critical set".
|
||||
|
@ -2,3 +2,182 @@
|
||||
-- No warranty is provided, implied or otherwise.
|
||||
|
||||
-- claw: assistant to app-claw
|
||||
-- should only ever be one app-claw at a time
|
||||
local lock = false
|
||||
return function ()
|
||||
if lock then
|
||||
error("libclaw safety lock in use")
|
||||
end
|
||||
lock = true
|
||||
local sourceList = {}
|
||||
local sources = {}
|
||||
-- 1 2 3 4 5 6
|
||||
-- dst entries: writeFile(fn), mkdir(fn), exists(fn), isDirectory(fn), remove(fn), rename(fna, fnb)
|
||||
-- writeFile(fn) -> function (data/nil to close)
|
||||
local function saveInfo(dn)
|
||||
sources[dn][2][2]("data")
|
||||
sources[dn][2][2]("data/app-claw")
|
||||
local cb, _, r = sources[dn][2][1]("data/app-claw/local.lua")
|
||||
if not cb then return false, r end
|
||||
_, r = cb(require("serial").serialize(sources[dn][3]))
|
||||
if not _ then return false, r end
|
||||
_, r = cb(nil)
|
||||
if not _ then return false, r end
|
||||
return true
|
||||
end
|
||||
local remove, installTo
|
||||
-- NOTE: Functions in this must return something due to the checked-call wrapper,
|
||||
-- but should all use error() for consistency.
|
||||
-- Operations
|
||||
installTo = function (dstName, pkg, srcName, checked, yielder)
|
||||
local installed = {pkg}
|
||||
local errs = {}
|
||||
if srcName == dstName then
|
||||
error("Invalid API use")
|
||||
end
|
||||
-- preliminary checks
|
||||
if checked then
|
||||
for _, v in ipairs(sources[srcName][3][pkg].deps) do
|
||||
if not sources[dstName][3][v] then
|
||||
if not sources[srcName][3][v] then
|
||||
table.insert(errs, pkg .. " depends on " .. v .. "\n")
|
||||
elseif #errs == 0 then
|
||||
installTo(dstName, v, srcName, checked, yielder)
|
||||
else
|
||||
table.insert(errs, pkg .. " depends on " .. v .. " (can autoinstall)\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Files from previous versions to get rid of
|
||||
local ignFiles = {}
|
||||
if sources[dstName][3][pkg] then
|
||||
for _, v in ipairs(sources[dstName][3][pkg].files) do
|
||||
ignFiles[v] = true
|
||||
end
|
||||
end
|
||||
for _, v in ipairs(sources[srcName][3][pkg].files) do
|
||||
if not ignFiles[v] then
|
||||
if sources[dstName][2][3](v) then
|
||||
table.insert(errs, v .. " already exists (corrupt system?)")
|
||||
end
|
||||
end
|
||||
end
|
||||
if #errs > 0 then
|
||||
error(table.concat(errs))
|
||||
end
|
||||
for _, v in ipairs(sources[srcName][3][pkg].dirs) do
|
||||
sources[dstName][2][2](v)
|
||||
if not sources[dstName][2][4](v) then
|
||||
error("Unable to create directory " .. v)
|
||||
end
|
||||
end
|
||||
for _, v in ipairs(sources[srcName][3][pkg].files) do
|
||||
local ok, r = sources[srcName][1](v, sources[dstName][2][1](v .. ".claw-tmp"))
|
||||
if ok then
|
||||
yielder()
|
||||
else
|
||||
-- Cleanup...
|
||||
for _, v in ipairs(sources[srcName][3][pkg].files) do
|
||||
sources[dstName][2][5](v .. ".claw-tmp")
|
||||
end
|
||||
error(r)
|
||||
end
|
||||
end
|
||||
-- PAST THIS POINT, ERRORS CORRUPT!
|
||||
sources[dstName][3][pkg] = nil
|
||||
saveInfo(dstName)
|
||||
for k, _ in pairs(ignFiles) do
|
||||
yielder()
|
||||
sources[dstName][2][5](k)
|
||||
end
|
||||
for _, v in ipairs(sources[srcName][3][pkg].files) do
|
||||
yielder()
|
||||
sources[dstName][2][6](v .. ".claw-tmp", v)
|
||||
end
|
||||
sources[dstName][3][pkg] = sources[srcName][3][pkg]
|
||||
saveInfo(dstName)
|
||||
return true
|
||||
end
|
||||
remove = function (dstName, pkg, checked)
|
||||
if checked then
|
||||
local errs = {}
|
||||
for dpsName, dpsV in pairs(sources[dstName][3]) do
|
||||
for _, v in ipairs(dpsV.deps) do
|
||||
if v == pkg then
|
||||
table.insert(errs, dpsName .. " depends on " .. pkg .. "\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
if #errs > 0 then
|
||||
return nil, table.concat(errs)
|
||||
end
|
||||
end
|
||||
for _, v in ipairs(sources[dstName][3][pkg].files) do
|
||||
sources[dstName][2][5](v)
|
||||
end
|
||||
sources[dstName][3][pkg] = nil
|
||||
saveInfo(dstName)
|
||||
return true
|
||||
end
|
||||
return {
|
||||
-- Gets the latest info, or if given a source just gives that source's info.
|
||||
-- Do not modify output.
|
||||
getInfo = function (pkg, source, oldest)
|
||||
if source then return sources[source][3][pkg] end
|
||||
local bestI = {
|
||||
v = -1,
|
||||
desc = "An unknown package.",
|
||||
deps = {}
|
||||
}
|
||||
if oldest then bestI.v = 10000 end
|
||||
for _, v in pairs(sources) do
|
||||
if v[3][pkg] then
|
||||
if ((not oldest) and (v[3][pkg].v > bestI.v)) or (oldest and (v[3][pkg].v > bestI.v)) then
|
||||
bestI = v[3][pkg]
|
||||
end
|
||||
end
|
||||
end
|
||||
return bestI
|
||||
end,
|
||||
-- Provides an ordered list of sources, with writable.
|
||||
-- Do not modify output.
|
||||
getSources = function ()
|
||||
return sourceList
|
||||
end,
|
||||
-- NOTE: If a source is writable, it's added anyway despite any problems.
|
||||
addSource = function (name, src, dst)
|
||||
local ifo = ""
|
||||
local ifok, e = src("data/app-claw/local.lua", function (t)
|
||||
ifo = ifo .. (t or "")
|
||||
return true
|
||||
end)
|
||||
ifo = ifok and require("serial").deserialize(ifo)
|
||||
if not (dst or ifo) then return false, e end
|
||||
table.insert(sourceList, {name, not not dst})
|
||||
sources[name] = {src, dst, ifo or {}}
|
||||
return not not ifo, e or "local.lua parse error"
|
||||
end,
|
||||
remove = remove,
|
||||
installTo = installTo,
|
||||
|
||||
-- Gets a total list of packages, as a table of strings. You can modify output.
|
||||
getList = function ()
|
||||
local n = {}
|
||||
local seen = {}
|
||||
for k, v in pairs(sources) do
|
||||
for kb, vb in pairs(v[3]) do
|
||||
if not seen[kb] then
|
||||
seen[kb] = true
|
||||
table.insert(n, kb)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(n)
|
||||
return n
|
||||
end,
|
||||
unlock = function ()
|
||||
lock = false
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -7,7 +7,8 @@
|
||||
-- This function needs access to the caller's NEO in order to ensure that NEO system functions are covered.
|
||||
-- This can do less checks than usual as it only affects the caller.
|
||||
|
||||
return function (neo)
|
||||
-- Global forces reference to prevent duplication
|
||||
newEvent = function (neo)
|
||||
local listeners = {}
|
||||
local translations = {}
|
||||
local timers = {}
|
||||
@ -102,3 +103,4 @@ return function (neo)
|
||||
end
|
||||
}
|
||||
end
|
||||
return newEvent
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
-- neoux: Implements utilities on top of Everest & event:
|
||||
-- Everest crash protection
|
||||
return function (event, neo)
|
||||
|
||||
-- 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")
|
||||
@ -448,8 +450,8 @@ return function (event, neo)
|
||||
}
|
||||
end
|
||||
neoux.startDialog = function (fmt, title, wait)
|
||||
fmt = neoux.fmtText(unicode.safeTextFormat(fmt), 20)
|
||||
neoux.create(20, #fmt, title, function (window, ev, a, b, c)
|
||||
fmt = neoux.fmtText(unicode.safeTextFormat(fmt), 40)
|
||||
neoux.create(40, #fmt, title, function (window, ev, a, b, c)
|
||||
if ev == "line" then
|
||||
window.span(1, a, fmt[a], 0xFFFFFF, 0)
|
||||
end
|
||||
@ -464,3 +466,4 @@ return function (event, neo)
|
||||
end
|
||||
return neoux
|
||||
end
|
||||
return newNeoux
|
||||
|
@ -4,17 +4,26 @@ local doSerialize = nil
|
||||
function doSerialize(s)
|
||||
if type(s) == "table" then
|
||||
local str = "{\n"
|
||||
local p = 1
|
||||
for k, v in pairs(s) do
|
||||
str = str .. "[" .. doSerialize(k) .. "]=" .. doSerialize(v) .. ",\n"
|
||||
if k == p then
|
||||
str = str .. doSerialize(v) .. ",\n"
|
||||
p = p + 1
|
||||
else
|
||||
str = str .. "[" .. doSerialize(k) .. "]=" .. doSerialize(v) .. ",\n"
|
||||
end
|
||||
end
|
||||
return str .. "}"
|
||||
end
|
||||
if type(s) == "string" then
|
||||
return string.format("%q", s)
|
||||
end
|
||||
if type(s) == "number" then
|
||||
if type(s) == "number" or type(s) == "boolean" then
|
||||
return tostring(s)
|
||||
end
|
||||
if s == nil then
|
||||
return "nil"
|
||||
end
|
||||
error("Cannot serialize " .. type(s))
|
||||
end
|
||||
return neo.wrapMeta({
|
||||
|
@ -130,6 +130,19 @@ local function prepareNodeI(node)
|
||||
if evt == "key" then
|
||||
key(wnd, a, b, c)
|
||||
end
|
||||
if evt == "touch" then
|
||||
local ns = b + math.max(1, selection - 4) - 2
|
||||
local max = #l
|
||||
if node.unknownAvailable then
|
||||
max = max + 1
|
||||
end
|
||||
if ns == selection and selection ~= #l + 1 then
|
||||
key(wnd, 13, 0, true)
|
||||
else
|
||||
selection = math.min(math.max(1, ns), max)
|
||||
flush(wnd)
|
||||
end
|
||||
end
|
||||
if evt == "line" then
|
||||
updateLine(wnd, a)
|
||||
end
|
||||
|
@ -113,7 +113,11 @@ getFsNode = function (fs, parent, fsc, path, mode)
|
||||
end,
|
||||
unknownAvailable = mode ~= nil,
|
||||
selectUnknown = function (text)
|
||||
return true, require("sys-filewrap")(fsc, path .. text, mode)
|
||||
local rt, re = require("sys-filewrap")(fsc, path .. text, mode)
|
||||
if not rt then
|
||||
return false, dialog("Open Error: " .. tostring(re), parent)
|
||||
end
|
||||
return true, rt
|
||||
end
|
||||
}
|
||||
return t
|
||||
@ -127,11 +131,19 @@ getFsNode = function (fs, parent, fsc, path, mode)
|
||||
end})
|
||||
if mode ~= nil then
|
||||
table.insert(n, {"Open", function ()
|
||||
return true, require("sys-filewrap")(fsc, path, mode)
|
||||
local rt, re = require("sys-filewrap")(fsc, path, mode)
|
||||
if not rt then
|
||||
return false, dialog("Open Error: " .. tostring(re), parent)
|
||||
end
|
||||
return true, rt
|
||||
end})
|
||||
end
|
||||
table.insert(n, {"Copy", function ()
|
||||
return nil, setupCopyVirtualEnvironment(fs, parent, require("sys-filewrap")(fsc, path, false))
|
||||
local rt, re = require("sys-filewrap")(fsc, path, false)
|
||||
if not rt then
|
||||
return false, dialog("Open Error: " .. tostring(re), parent)
|
||||
end
|
||||
return nil, setupCopyVirtualEnvironment(fs, parent, rt)
|
||||
end})
|
||||
table.insert(n, {"Delete", function ()
|
||||
fsc.remove(path)
|
||||
|
@ -4,7 +4,8 @@
|
||||
return function(dev, file, mode)
|
||||
local n = "rb"
|
||||
if mode then n = "wb" end
|
||||
local handle = dev.open(file, n)
|
||||
local handle, r = dev.open(file, n)
|
||||
if not handle then return nil, r end
|
||||
local open = true
|
||||
local function closer()
|
||||
if not open then return end
|
||||
@ -35,7 +36,8 @@ return function(dev, file, mode)
|
||||
close = closer,
|
||||
write = function (txt)
|
||||
if type(txt) ~= "string" then error("Write data must be string-bytearray") end
|
||||
return dev.write(handle, txt)
|
||||
local ok, b = dev.write(handle, txt)
|
||||
if not ok then error(tostring(b)) end
|
||||
end
|
||||
}, closer
|
||||
end
|
||||
|
@ -28,7 +28,6 @@ for k, v in pairs(f) do
|
||||
end
|
||||
os.execute("mkdir -p work/data/app-claw")
|
||||
os.execute("cp code/data/app-claw/local.lua work/data/app-claw/local.lua")
|
||||
os.execute("cp code/libs/sys-secpolicy.lua work/libs/sys-secpolicy.lua")
|
||||
os.execute("cd code ; find . > ../imitclaw.treecode")
|
||||
os.execute("cd work ; find . > ../imitclaw.treework")
|
||||
os.execute("diff -u imitclaw.treecode imitclaw.treework")
|
||||
|
@ -11,13 +11,8 @@
|
||||
local event = require("event")(neo)
|
||||
local neoux = require("neoux")(event, neo)
|
||||
|
||||
local eeprom = neo.requestAccess("c.eeprom")
|
||||
if eeprom then
|
||||
eeprom = eeprom.list()()
|
||||
end
|
||||
if not eeprom then
|
||||
error("No EEPROM access")
|
||||
end
|
||||
local eeprom = neo.requireAccess("c.eeprom", "EEPROM access")
|
||||
eeprom = eeprom.list()()
|
||||
|
||||
neoux.startDialog("NOTE: If this program is used improperly, it can require EEPROM replacement.\nOnly use trusted EEPROMs.", "eeprom-flash", true)
|
||||
|
||||
|
@ -2,7 +2,6 @@ return {
|
||||
["app-eeprog"] = {
|
||||
desc = "EEPROM programmer / copier",
|
||||
v = 0,
|
||||
app = "app-eeprog",
|
||||
deps = {
|
||||
"neo"
|
||||
},
|
||||
@ -12,5 +11,17 @@ return {
|
||||
files = {
|
||||
"apps/app-eeprog.lua"
|
||||
},
|
||||
},
|
||||
["mtd"] = {
|
||||
desc = "Multi-Track Drifting",
|
||||
v = 1337,
|
||||
deps = {
|
||||
"app-eeprog"
|
||||
},
|
||||
dirs = {
|
||||
},
|
||||
files = {
|
||||
"oreproc.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1
repository/oreproc.txt
Normal file
1
repository/oreproc.txt
Normal file
@ -0,0 +1 @@
|
||||
Hello new world
|
Loading…
Reference in New Issue
Block a user