From 70a98e33d7a53ab903e1ad5f7a8cb0cac4977a83 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 8 Dec 2018 14:10:46 -0500 Subject: [PATCH 001/231] switch branch to develop-1.8 --- sys/boot/opus.boot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index 990def6..8c5c413 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -2,7 +2,7 @@ local fs = _G.fs local http = _G.http -_G.OPUS_BRANCH = 'master-1.8' +_G.OPUS_BRANCH = 'develop-1.8' local GIT_REPO = 'kepler155c/opus/' .. _G.OPUS_BRANCH local BASE = 'https://raw.githubusercontent.com/' .. GIT_REPO From 3c9f03477a1d8d6d7612d849e0c8dd4807beeef9 Mon Sep 17 00:00:00 2001 From: sorucoder <40341154+sorucoder@users.noreply.github.com> Date: Sun, 9 Dec 2018 00:37:23 -0500 Subject: [PATCH 002/231] Added util.signum, util.clamp, and fixed util.round Added commonly used math operations. Fixed bug where util.round(-0.5) returns 0. --- sys/apis/util.lua | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 40f3cb2..7d275a7 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -109,10 +109,30 @@ function Util.checkMinecraftVersion(minVersion) return convert(version) >= convert(tostring(minVersion)) end +function Util.signum(num) + if num > 0 then + return 1 + elseif num < 0 then + return -1 + else + return 0 + end +end + +function Util.clamp(lo, n, hi) + if num <= lo then + return lo + elseif num >= hi then + return hi + else + return n + end +end + -- http://lua-users.org/wiki/SimpleRound function Util.round(num, idp) local mult = 10^(idp or 0) - return math.floor(num * mult + 0.5) / mult + return util.signum(num) * math.floor(math.abs(num) * mult + 0.5) / mult end function Util.random(max, min) From 3f3a2deaa8534890939df24087dcd169a9049fb9 Mon Sep 17 00:00:00 2001 From: sorucoder <40341154+sorucoder@users.noreply.github.com> Date: Sun, 9 Dec 2018 00:58:05 -0500 Subject: [PATCH 003/231] Removed util.random, added util.randomFloat Removed util.random as it is a duplicate of math.random. Added util.randomFloat, which returns a random floating point number. --- sys/apis/util.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 7d275a7..7638613 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -135,9 +135,9 @@ function Util.round(num, idp) return util.signum(num) * math.floor(math.abs(num) * mult + 0.5) / mult end -function Util.random(max, min) +function Util.randomFloat(max, min) min = min or 0 - return math.random(0, max-min) + min + return (max-min) * math.random() + min end --[[ Table functions ]] -- From 30640fd415e8b7d636bdc5995fd73275039d6eae Mon Sep 17 00:00:00 2001 From: sorucoder <40341154+sorucoder@users.noreply.github.com> Date: Sun, 9 Dec 2018 01:01:20 -0500 Subject: [PATCH 004/231] Fixed util.randomFloat Fixed if max is nil, that it behaves like math.random() --- sys/apis/util.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 7638613..cc59848 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -137,6 +137,7 @@ end function Util.randomFloat(max, min) min = min or 0 + max = max or 0 return (max-min) * math.random() + min end From 2e94b61dff84886bdc30378a2e3a546c3a028dbe Mon Sep 17 00:00:00 2001 From: sorucoder <40341154+sorucoder@users.noreply.github.com> Date: Sun, 9 Dec 2018 01:04:24 -0500 Subject: [PATCH 005/231] Fixed util.randomFloat Fixed if both max or min is nil, it returns a number between 0 and 1 --- sys/apis/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index cc59848..b77d444 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -137,7 +137,7 @@ end function Util.randomFloat(max, min) min = min or 0 - max = max or 0 + max = max or 1 return (max-min) * math.random() + min end From eb8b8236744f9efde02d3d3838421ab735a31cb4 Mon Sep 17 00:00:00 2001 From: sorucoder <40341154+sorucoder@users.noreply.github.com> Date: Sun, 9 Dec 2018 14:52:52 -0500 Subject: [PATCH 006/231] Fixed util.signum --- sys/apis/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index b77d444..7f87230 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -132,7 +132,7 @@ end -- http://lua-users.org/wiki/SimpleRound function Util.round(num, idp) local mult = 10^(idp or 0) - return util.signum(num) * math.floor(math.abs(num) * mult + 0.5) / mult + return Util.signum(num) * math.floor(math.abs(num) * mult + 0.5) / mult end function Util.randomFloat(max, min) From abec4a9740671440b182a48f45a98f6d91e72a03 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 10 Dec 2018 10:33:56 -0500 Subject: [PATCH 007/231] dynamic overview shortcuts --- sys/apps/Network.lua | 8 ++ sys/apps/Overview.lua | 222 ++++++++++++++++++++++++------------------ 2 files changed, 133 insertions(+), 97 deletions(-) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 0fceb8c..49aeed5 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -108,6 +108,14 @@ function page:eventHandler(event) args = { t.id }, title = t.label, }) + os.queueEvent('overview_shortcut', { + title = t.label, + category = "VNC", + icon = "\ + \031e\\\031 \031e/\031dn\ + \031e\\/\031 \0319c", + run = "vnc.lua " .. t.id, + }) elseif event.type == 'clear' then Util.clear(network) page.grid:update() diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 14740fc..a1751ea 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -23,6 +23,9 @@ if not _ENV.multishell then end local REGISTRY_DIR = 'usr/.registry' +local DEFAULT_ICON = NFT.parse("\03180\031711\03180\ +\031800\03171\03180\ +\03171\031800\03171") UI:configure('Overview', ...) @@ -32,9 +35,86 @@ local config = { } Config.load('Overview', config) -local applications = { } local extSupport = Util.getVersion() >= 1.76 +local applications = { } +local buttons = { } + +local sx, sy = term.current().getSize() +local maxRecent = math.ceil(sx * sy / 62) + +local function elipse(s, len) + if #s > len then + s = s:sub(1, len - 2) .. '..' + end + return s +end + +local function parseIcon(iconText) + local icon + + local s, m = pcall(function() + icon = NFT.parse(iconText) + if icon then + if icon.height > 3 or icon.width > 8 then + error('Must be an NFT image - 3 rows, 8 cols max') + end + end + return icon + end) + + if s then + return icon + end + + return s, m +end + +UI.VerticalTabBar = class(UI.TabBar) +function UI.VerticalTabBar:setParent() + self.x = 1 + self.width = 8 + self.height = nil + self.ey = -1 + UI.TabBar.setParent(self) + for k,c in pairs(self.children) do + c.x = 1 + c.y = k + 1 + c.ox, c.oy = c.x, c.y + c.ow = 8 + c.width = 8 + end +end + +local cx = 9 +local cy = 1 +if sx < 30 then + UI.VerticalTabBar = UI.TabBar + cx = 1 + cy = 2 +end + +local page = UI.Page { + container = UI.Viewport { + x = cx, + y = cy, + }, + notification = UI.Notification(), + accelerators = { + r = 'refresh', + e = 'edit', + f = 'files', + s = 'shell', + l = 'lua', + [ 'control-n' ] = 'new', + delete = 'delete', + }, +} + +if extSupport then + page.container.backgroundColor = colors.black +end + local function loadApplications() local requirements = { turtle = not not turtle, @@ -81,102 +161,32 @@ local function loadApplications() return true -- Util.startsWith(a.run, 'http') or shell.resolveProgram(a.run) end) -end -loadApplications() - -local defaultIcon = NFT.parse("\03180\031711\03180\ -\031800\03171\03180\ -\03171\031800\03171") - -local sx, sy = term.current().getSize() -local maxRecent = math.ceil(sx * sy / 62) - -local function elipse(s, len) - if #s > len then - s = s:sub(1, len - 2) .. '..' - end - return s -end - -local buttons = { } -local categories = { } -for _,f in pairs(applications) do - if not categories[f.category] then - categories[f.category] = true - table.insert(buttons, { text = f.category }) - end -end -table.sort(buttons, function(a, b) return a.text < b.text end) -table.insert(buttons, 1, { text = 'Recent' }) -table.insert(buttons, { text = '+', event = 'new' }) - -local function parseIcon(iconText) - local icon - - local s, m = pcall(function() - icon = NFT.parse(iconText) - if icon then - if icon.height > 3 or icon.width > 8 then - error('Must be an NFT image - 3 rows, 8 cols max') - end + local categories = { } + buttons = { } + for _,f in pairs(applications) do + if not categories[f.category] then + categories[f.category] = true + table.insert(buttons, { + text = f.category, + selected = config.currentCategory == f.category + }) end - return icon - end) - - if s then - return icon end + table.sort(buttons, function(a, b) return a.text < b.text end) + table.insert(buttons, 1, { text = 'Recent' }) + table.insert(buttons, { text = '+', event = 'new' }) - return s, m -end + Util.removeByValue(page.children, page.tabBar) -UI.VerticalTabBar = class(UI.TabBar) -function UI.VerticalTabBar:setParent() - self.x = 1 - self.width = 8 - self.height = nil - self.ey = -1 - UI.TabBar.setParent(self) - for k,c in pairs(self.children) do - c.x = 1 - c.y = k + 1 - c.ox, c.oy = c.x, c.y - c.ow = 8 - c.width = 8 - end -end + page:add { + tabBar = UI.VerticalTabBar { + buttons = buttons, + }, + } -local cx = 9 -local cy = 1 -if sx < 30 then - UI.VerticalTabBar = UI.TabBar - cx = 1 - cy = 2 -end - -local page = UI.Page { - tabBar = UI.VerticalTabBar { - buttons = buttons, - }, - container = UI.Viewport { - x = cx, - y = cy, - }, - notification = UI.Notification(), - accelerators = { - r = 'refresh', - e = 'edit', - f = 'files', - s = 'shell', - l = 'lua', - [ 'control-n' ] = 'new', - delete = 'delete', - }, -} - -if extSupport then - page.container.backgroundColor = colors.black + --page.tabBar:selectTab(config.currentCategory or 'Apps') + page.container:setCategory(config.currentCategory or 'Apps') end UI.Icon = class(UI.Window) @@ -242,7 +252,7 @@ function page.container:setCategory(categoryName, animate) icon = parseIcon(program.icon) end if not icon then - icon = defaultIcon + icon = DEFAULT_ICON end local title = elipse(program.title, 8) @@ -537,8 +547,11 @@ function editor:eventHandler(event) local values = self.form.values UI:setPreviousPage() self:updateApplications(values) - page:refresh() - page:draw() + --page:refresh() + --page:draw() + config.currentCategory = values.category + Config.update('Overview', config) + os.queueEvent('overview_refresh') else return UI.Dialog.eventHandler(self, event) end @@ -550,15 +563,30 @@ UI:setPages({ main = page, }) -Event.on('os_register_app', function() +local function reload() loadApplications() page:refresh() page:draw() page:sync() +end + +Event.on('overview_shortcut', function(_, app) + if not app.key then + app.key = SHA1.sha1(app.title) + end + local filename = app.filename or fs.combine(REGISTRY_DIR, app.key) + if not fs.exists(filename) then + Util.writeTable(filename, app) + reload() + end end) -page.tabBar:selectTab(config.currentCategory or 'Apps') -page.container:setCategory(config.currentCategory or 'Apps') +Event.on('overview_refresh', function() + reload() +end) + +loadApplications() + UI:setPage(page) UI:pullEvents() From bd5cba8656d52785d3bf700c34857e3fb40a3da8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 16 Dec 2018 02:28:16 -0500 Subject: [PATCH 008/231] better turtle.condense --- sys/extensions/6.tl3.lua | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index d82930a..04e248a 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -873,23 +873,27 @@ end function turtle.condense() local slots = turtle.getInventory() - for i = 16, 1, -1 do - if slots[i].count > 0 then - for j = 1, i - 1 do - if slots[j].count == 0 or slots[i].key == slots[j].key then - turtle.select(i) - turtle.transferTo(j, 64) - local transferred = slots[i].qty - turtle.getItemCount(i) - slots[j].count = slots[j].count + transferred - slots[i].count = slots[i].count - transferred - slots[j].key = slots[i].key - if slots[i].count == 0 then + for i = 1, 16 do + if slots[i].count < 64 then + for j = 16, i + 1, -1 do + if slots[j].count > 0 and (slots[i].count == 0 or slots[i].key == slots[j].key) then + turtle.select(j) + if turtle.transferTo(i) then + local transferred = turtle.getItemCount(i) - slots[i].qty + slots[j].count = slots[j].count - transferred + slots[i].count = slots[i].count + transferred + slots[i].key = slots[j].key + if slots[i].count == 64 then + break + end + else break end end end end end + turtle.select(1) return true end From 0aa0841b764b0f784373c89990b470d352f93cb7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 16 Dec 2018 02:44:01 -0500 Subject: [PATCH 009/231] better turtle.condense --- sys/extensions/6.tl3.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 04e248a..f231f4b 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -883,6 +883,9 @@ function turtle.condense() slots[j].count = slots[j].count - transferred slots[i].count = slots[i].count + transferred slots[i].key = slots[j].key + if slots[j].count == 0 then + slots[j].key = nil + end if slots[i].count == 64 then break end From 7d64b0c6dbc6ca7cb398d67dd975ee69a9209a56 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 16 Dec 2018 22:17:19 -0500 Subject: [PATCH 010/231] update shell with require --- sys/apis/injector.lua | 15 ++++- sys/apps/shell | 107 +++++++++++++++++++++++++++++++++- sys/extensions/4.user.lua | 15 ++++- sys/extensions/6.packages.lua | 15 ++--- sys/kernel.lua | 4 ++ 5 files changed, 143 insertions(+), 13 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 15fc8b7..74fda7f 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -1,6 +1,6 @@ local PASTEBIN_URL = 'http://pastebin.com/raw' local GIT_URL = 'https://raw.githubusercontent.com' -local DEFAULT_PATH = 'sys/apis' +local DEFAULT_PATH = '/sys/apis/?;/sys/apis/?.lua' local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'master' local DEFAULT_UPATH = GIT_URL .. '/kepler155c/opus/' .. DEFAULT_BRANCH .. '/sys/apis' @@ -80,14 +80,25 @@ local function requireWrapper(env) end local function pathSearcher(modname) - local fname = modname:gsub('%.', '/') .. '.lua' + local fname = modname:gsub('%.', '/') + for pattern in string.gmatch(env.package.path, "[^;]+") do + local sPath = string.gsub(pattern, "%?", fname) + if env.shell and env.shell.dir and sPath:sub(1, 1) ~= "/" then + sPath = fs.combine(env.shell.dir(), sPath) + end + if fs.exists(sPath) and not fs.isDir(sPath) then + return loadfile(sPath, env) + end + end + --[[ for dir in string.gmatch(env.package.path, "[^:]+") do local path = fs.combine(dir, fname) if fs.exists(path) and not fs.isDir(path) then return loadfile(path, env) end end + ]] end -- require('BniCQPVf') diff --git a/sys/apps/shell b/sys/apps/shell index 31ce233..69f8ca5 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -77,6 +77,107 @@ local function run(env, ...) return table.unpack(r) end +local function createShellEnv(sDir) + local tEnv = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + + --[[ + package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" + if turtle then + package.path = package.path..";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" + elseif command then + package.path = package.path..";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" + end + ]] + + local package + + package = { + loaded = { + _G = _G, + bit32 = bit32, + coroutine = coroutine, + math = math, + package = package, + string = string, + table = table, + }, + path = _G.LUA_PATH, + config = "/\n;\n?\n!\n-", + preload = { }, + loaders = { + function( name ) +_G._p = _ENV + if package.preload[name] then + return package.preload[name] + else + return nil, "no field package.preload['" .. name .. "']" + end + end, + function( name ) + local fname = string.gsub(name, "%.", "/") + local sError = "" + for pattern in string.gmatch(package.path, "[^;]+") do + local sPath = string.gsub(pattern, "%?", fname) + if sPath:sub(1,1) ~= "/" then + sPath = fs.combine(sDir, sPath) + end + if fs.exists(sPath) and not fs.isDir(sPath) then + local fnFile, sError = loadfile( sPath, tEnv ) + if fnFile then + return fnFile, sPath + else + return nil, sError + end + else + if #sError > 0 then + sError = sError .. "\n" + end + sError = sError .. "no file '" .. sPath .. "'" + end + end + return nil, sError + end + } + } + + local sentinel = {} + local function require( name ) + if type( name ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 2 ) + end + if package.loaded[name] == sentinel then + error("Loop detected requiring '" .. name .. "'", 0) + end + if package.loaded[name] then + return package.loaded[name] + end + + local sError = "Error loading module '" .. name .. "':" + for _,searcher in ipairs(package.loaders) do + local loader, err = searcher(name) + if loader then + package.loaded[name] = sentinel + local result = loader( err ) + if result ~= nil then + package.loaded[name] = result + return result + else + package.loaded[name] = true + return true + end + else + sError = sError .. "\n" .. err + end + end + error(sError, 2) + end + + tEnv["package"] = package + tEnv["require"] = require + + return tEnv + end + -- Install shell API function shell.run(...) local oldTitle @@ -85,7 +186,8 @@ function shell.run(...) oldTitle = _ENV.multishell.getTitle(_ENV.multishell.getCurrent()) end - local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + local env = createShellEnv(shell.dir()) + -- local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) local r = { pcall(run, env, ...) } if _ENV.multishell then @@ -349,7 +451,8 @@ end local tArgs = { ... } if #tArgs > 0 then - local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + local env = createShellEnv(shell.dir()) +-- local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) return run(env, ...) end diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 662fc6f..dbdbe35 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -16,11 +16,21 @@ end -- 'usr gitfs kepler155c/opus-apps/' .. _G.OPUS_BRANCH) --end +local lua_path = '?;?.lua;?/init.lua' +lua_path = lua_path .. ';/usr/apis/?;/usr/apis/?.lua' +lua_path = lua_path .. ';/sys/apis/?;/sys/apis/?.lua' +lua_path = lua_path .. ';/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua;' +if _G.turtle then + lua_path = lua_path..';/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua' +elseif _G.command then + lua_path = lua_path..';/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua' +end + if not fs.exists('usr/config/shell') then Util.writeTable('usr/config/shell', { aliases = shell.aliases(), path = 'usr/apps:sys/apps:' .. shell.path(), - lua_path = 'sys/apis:usr/apis', + lua_path = lua_path, }) end @@ -45,6 +55,7 @@ if config.aliases then end end shell.setPath(config.path) -_G.LUA_PATH = config.lua_path +--_G.LUA_PATH = config.lua_path +_G.LUA_PATH = lua_path fs.loadTab('usr/config/fstab') diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index 8fb598a..cc68ddd 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -6,20 +6,21 @@ local Util = require('util') local shell = _ENV.shell local fs = _G.fs -local appPaths = Util.split(shell.path(), '(.-):') -local luaPaths = Util.split(_G.LUA_PATH, '(.-):') +local appPaths = Util.split(shell.path(), '(.-);') +local luaPaths = Util.split(_G.LUA_PATH, '(.-);') -local function addPath(t, e) - local function hasEntry() +local function addPath(t, path) + local function addEntry(e) for _,v in ipairs(t) do if v == e then return true end end - end - if not hasEntry() then table.insert(t, 1, e) end + addEntry(string.format('/%s/?', path)) + addEntry(string.format('/%s/?.lua', path)) + addEntry(string.format('/%s/?/init.lua', path)) end -- dependency graph @@ -42,4 +43,4 @@ for name in pairs(Packages:installed()) do end shell.setPath(table.concat(appPaths, ':')) -_G.LUA_PATH = table.concat(luaPaths, ':') +_G.LUA_PATH = table.concat(luaPaths, ';') diff --git a/sys/kernel.lua b/sys/kernel.lua index b686bd8..cbd6806 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -115,6 +115,10 @@ function kernel.getCurrent() return kernel.running end +function kernel.getShell() + return shell +end + function kernel.newRoutine(args) kernel.UID = kernel.UID + 1 From 5d38c307b39dc3f4a9665808c652999faac4d2cc Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 20 Dec 2018 19:28:26 -0500 Subject: [PATCH 011/231] disable red server --- sys/apis/util.lua | 7 +++++++ sys/apps/Network.lua | 2 +- sys/apps/shell | 10 ---------- sys/network/redserver.lua | 2 ++ 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 7f87230..29a865e 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -296,6 +296,13 @@ function Util.filter(it, f) return ot end +function Util.reduce(t, fn, acc) + for _, v in pairs(t) do + fn(acc, v) + end + return acc +end + function Util.size(list) if type(list) == 'table' then local length = 0 diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 49aeed5..39cb2ce 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -206,7 +206,7 @@ function page.grid:getDisplayValues(row) end end if row.fuel then - row.fuel = Util.toBytes(row.fuel) + row.fuel = row.fuel > 0 and Util.toBytes(row.fuel) or '' end if row.distance then row.distance = Util.round(row.distance, 1) diff --git a/sys/apps/shell b/sys/apps/shell index 69f8ca5..1bcece8 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -80,15 +80,6 @@ end local function createShellEnv(sDir) local tEnv = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) - --[[ - package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" - if turtle then - package.path = package.path..";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" - elseif command then - package.path = package.path..";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" - end - ]] - local package package = { @@ -106,7 +97,6 @@ local function createShellEnv(sDir) preload = { }, loaders = { function( name ) -_G._p = _ENV if package.preload[name] then return package.preload[name] else diff --git a/sys/network/redserver.lua b/sys/network/redserver.lua index fda019c..8da25a4 100644 --- a/sys/network/redserver.lua +++ b/sys/network/redserver.lua @@ -79,6 +79,7 @@ local function getListing(path, recursive) return list end +--[[ Event.on('modem_message', function(_, _, dport, dhost, request) if dport == 80 and dhost == computerId and type(request) == 'table' then if request.method == 'GET' then @@ -111,3 +112,4 @@ Event.on('modem_message', function(_, _, dport, dhost, request) end end end) +]] From e14a71ab6a08c0b3ee2754be4becc8be25bb8317 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 21 Dec 2018 19:47:39 -0500 Subject: [PATCH 012/231] Pointt.iterateClosest --- sys/apis/point.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sys/apis/point.lua b/sys/apis/point.lua index 1d83eab..f36933b 100644 --- a/sys/apis/point.lua +++ b/sys/apis/point.lua @@ -189,6 +189,8 @@ function Point.closest(reference, pts) end function Point.eachClosest(spt, ipts, fn) + if not ipts then error('Point.eachClosest: invalid points', 2) end + local pts = Util.shallowCopy(ipts) while #pts > 0 do local pt = Point.closest(spt, pts) @@ -200,6 +202,17 @@ function Point.eachClosest(spt, ipts, fn) end end +function Point.iterateClosest(spt, ipts) + local pts = Util.shallowCopy(ipts) + return function() + local pt = Point.closest(spt, pts) + if pt then + Util.removeByValue(pts, pt) + return pt + end + end +end + function Point.adjacentPoints(pt) local pts = { } From 3de03bef22c6a9fa177b474b4e3fd3b9606d90c8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 21 Dec 2018 20:58:41 -0500 Subject: [PATCH 013/231] manipulator device :( --- sys/extensions/1.device.lua | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/sys/extensions/1.device.lua b/sys/extensions/1.device.lua index 003ae14..d580563 100644 --- a/sys/extensions/1.device.lua +++ b/sys/extensions/1.device.lua @@ -155,23 +155,22 @@ end drivers['manipulator'] = function(dev) if dev.getName then - local name pcall(function() - name = dev.getName() - end) - if name then - if dev.getInventory then - createDevice(name .. ':inventory', 'inventory', 'getInventory', dev) - end - if dev.getEquipment then - createDevice(name .. ':equipment', 'equipment', 'getEquipment', dev) - end - if dev.getEnder then - createDevice(name .. ':enderChest', 'enderChest', 'getEnder', dev) - end + local name = dev.getName() + if name then + if dev.getInventory then + createDevice(name .. ':inventory', 'inventory', 'getInventory', dev) + end + if dev.getEquipment then + createDevice(name .. ':equipment', 'equipment', 'getEquipment', dev) + end + if dev.getEnder then + createDevice(name .. ':enderChest', 'enderChest', 'getEnder', dev) + end - return dev._children - end + return dev._children + end + end) end end From 26564cbcc13e4478bac82b928c2f8c35ee5d8bd9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 22 Dec 2018 22:11:16 -0500 Subject: [PATCH 014/231] custom help files + redo System UI --- sys/apis/config.lua | 1 + sys/apis/turtle/home.lua | 42 +++++ sys/apis/ui.lua | 10 +- sys/apps/System.lua | 339 +++++----------------------------- sys/apps/system/aliases.lua | 66 +++++++ sys/apps/system/label.lua | 49 +++++ sys/apps/system/network.lua | 56 ++++++ sys/apps/system/password.lua | 53 ++++++ sys/apps/system/path.lua | 50 +++++ sys/apps/system/settings.lua | 47 +++++ sys/apps/system/turtle.lua | 62 +++++++ sys/extensions/5.network.lua | 8 +- sys/extensions/6.packages.lua | 13 +- sys/help/Opus Applications | 30 +++ sys/help/Wireless Networking | 7 + 15 files changed, 541 insertions(+), 292 deletions(-) create mode 100644 sys/apis/turtle/home.lua create mode 100644 sys/apps/system/aliases.lua create mode 100644 sys/apps/system/label.lua create mode 100644 sys/apps/system/network.lua create mode 100644 sys/apps/system/password.lua create mode 100644 sys/apps/system/path.lua create mode 100644 sys/apps/system/settings.lua create mode 100644 sys/apps/system/turtle.lua create mode 100644 sys/help/Opus Applications create mode 100644 sys/help/Wireless Networking diff --git a/sys/apis/config.lua b/sys/apis/config.lua index 13ab441..35f7310 100644 --- a/sys/apis/config.lua +++ b/sys/apis/config.lua @@ -7,6 +7,7 @@ local Config = { } function Config.load(fname, data) local filename = 'usr/config/' .. fname + data = data or { } if not fs.exists('usr/config') then fs.makeDir('usr/config') diff --git a/sys/apis/turtle/home.lua b/sys/apis/turtle/home.lua new file mode 100644 index 0000000..29a1cbc --- /dev/null +++ b/sys/apis/turtle/home.lua @@ -0,0 +1,42 @@ +local Config = require('config') +local GPS = require('gps') + +local turtle = _G.turtle + +local Home = { } + +function Home.go() + local config = { } + Config.load('gps', config) + + if config.home then + if turtle.enableGPS() then + return turtle.pathfind(config.home) + end + end +end + +function Home.set() + local config = { } + Config.load('gps', config) + + local pt = GPS.getPoint() + if pt then + local originalHeading = turtle.point.heading + local heading = GPS.getHeading() + if heading then + local turns = (turtle.point.heading - originalHeading) % 4 + pt.heading = (heading - turns) % 4 + config.home = pt + Config.update('gps', config) + + pt = GPS.getPoint() + pt.heading = heading + turtle.setPoint(pt, true) + turtle._goto(config.home) + return config.home + end + end +end + +return Home diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index dffb370..c9bcabc 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -2250,6 +2250,13 @@ function UI.Tabs:add(children) end end +function UI.Tabs:selectTab(tab) + local menuItem = Util.find(self.tabBar:getFocusables(), 'tabUid', tab.uid) + if menuItem then + self.tabBar:emit({ type = 'tab_select', button = { uid = menuItem.uid } }) + end +end + function UI.Tabs:enable() self.enabled = true self.tabBar:enable() @@ -2999,6 +3006,7 @@ function UI.Chooser:eventHandler(event) if event.key == 'right' or event.key == 'space' then local _,k = Util.find(self.choices, 'value', self.value) local choice + if not k then k = 1 end if k and k < #self.choices then choice = self.choices[k+1] else @@ -3021,7 +3029,7 @@ function UI.Chooser:eventHandler(event) self:draw() return true end - elseif event.type == 'mouse_click' then + elseif event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then if event.x == 1 then self:emit({ type = 'key', key = 'left' }) return true diff --git a/sys/apps/System.lua b/sys/apps/System.lua index ce2a2b1..ed742ef 100644 --- a/sys/apps/System.lua +++ b/sys/apps/System.lua @@ -1,16 +1,9 @@ -_G.requireInjector(_ENV) +local Config = require('config') +local UI = require('ui') +local Util = require('util') -local Config = require('config') -local Security = require('security') -local SHA1 = require('sha1') -local UI = require('ui') -local Util = require('util') - -local fs = _G.fs -local os = _G.os -local settings = _G.settings -local shell = _ENV.shell -local turtle = _G.turtle +local fs = _G.fs +local shell = _ENV.shell UI:configure('System', ...) @@ -23,116 +16,18 @@ Config.load('shell', env) local systemPage = UI.Page { tabs = UI.Tabs { - pathTab = UI.Window { - tabTitle = 'Path', - entry = UI.TextEntry { - x = 2, y = 2, ex = -2, - limit = 256, - value = shell.path(), - shadowText = 'enter system path', - accelerators = { - enter = 'update_path', - }, - }, + settings = UI.Window { + tabTitle = 'Category', grid = UI.Grid { - y = 4, - disableHeader = true, - columns = { { key = 'value' } }, + y = 2, + columns = { + { heading = 'Name', key = 'name' }, + { heading = 'Description', key = 'description' }, + }, + sortColumn = 'name', autospace = true, }, }, - - aliasTab = UI.Window { - tabTitle = 'Alias', - alias = UI.TextEntry { - x = 2, y = 2, ex = -2, - limit = 32, - shadowText = 'Alias', - }, - path = UI.TextEntry { - y = 3, x = 2, ex = -2, - limit = 256, - shadowText = 'Program path', - accelerators = { - enter = 'new_alias', - }, - }, - grid = UI.Grid { - y = 5, - sortColumn = 'alias', - columns = { - { heading = 'Alias', key = 'alias' }, - { heading = 'Program', key = 'path' }, - }, - accelerators = { - delete = 'delete_alias', - }, - }, - }, - - passwordTab = UI.Window { - tabTitle = 'Password', - oldPass = UI.TextEntry { - x = 2, y = 2, ex = -2, - limit = 32, - mask = true, - shadowText = 'old password', - inactive = not Security.getPassword(), - }, - newPass = UI.TextEntry { - y = 3, x = 2, ex = -2, - limit = 32, - mask = true, - shadowText = 'new password', - accelerators = { - enter = 'new_password', - }, - }, - button = UI.Button { - x = 2, y = 5, - text = 'Update', - event = 'update_password', - }, - info = UI.TextArea { - x = 2, ex = -2, - y = 7, - inactive = true, - value = 'Add a password to enable other computers to connect to this one.', - } - }, - - infoTab = UI.Window { - tabTitle = 'Info', - labelText = UI.Text { - x = 3, y = 2, - value = 'Label' - }, - label = UI.TextEntry { - x = 9, y = 2, ex = -4, - limit = 32, - value = os.getComputerLabel(), - accelerators = { - enter = 'update_label', - }, - }, - grid = UI.ScrollingGrid { - y = 3, - values = { - { name = '', value = '' }, - { name = 'CC version', value = Util.getVersion() }, - { name = 'Lua version', value = _VERSION }, - { name = 'MC version', value = Util.getMinecraftVersion() }, - { name = 'Disk free', value = Util.toBytes(fs.getFreeSpace('/')) }, - { name = 'Computer ID', value = tostring(os.getComputerID()) }, - { name = 'Day', value = tostring(os.day()) }, - }, - inactive = true, - columns = { - { key = 'name', width = 12 }, - { key = 'value' }, - }, - }, - }, }, notification = UI.Notification(), accelerators = { @@ -140,177 +35,15 @@ local systemPage = UI.Page { }, } -if turtle then - pcall(function() - local Home = require('turtle.home') --- TODO: dont rely on turtle.home - local values = { } - Config.load('gps', values.home and { values.home } or { }) - - systemPage.tabs:add({ - gpsTab = UI.Window { - tabTitle = 'GPS', - labelText = UI.Text { - x = 3, y = 2, - value = 'On restart, return to this location' - }, - grid = UI.Grid { - x = 3, ex = -3, y = 4, - height = 2, - values = values, - inactive = true, - columns = { - { heading = 'x', key = 'x' }, - { heading = 'y', key = 'y' }, - { heading = 'z', key = 'z' }, - }, - }, - button1 = UI.Button { - x = 3, y = 7, - text = 'Set home', - event = 'gps_set', - }, - button2 = UI.Button { - ex = -3, y = 7, width = 7, - text = 'Clear', - event = 'gps_clear', - }, - }, - }) - function systemPage.tabs.gpsTab:eventHandler(event) - if event.type == 'gps_set' then - systemPage.notification:info('Determining location', 10) - systemPage:sync() - if Home.set() then - Config.load('gps', values) - self.grid:setValues(values.home and { values.home } or { }) - self.grid:draw() - systemPage.notification:success('Location set') - else - systemPage.notification:error('Unable to determine location') - end - return true - elseif event.type == 'gps_clear' then - fs.delete('usr/config/gps') - self.grid:setValues({ }) - self.grid:draw() - return true - end +function systemPage.tabs.settings:eventHandler(event) + if event.type == 'grid_select' then + local tab = event.selected.tab + if not systemPage.tabs[tab.tabTitle] then + systemPage.tabs:add({ [ tab.tabTitle ] = tab }) + tab:disable() end - end) -end - -if settings then - local values = { } - for _,v in pairs(settings.getNames()) do - local value = settings.get(v) - if not value then - value = false - end - table.insert(values, { - name = v, - value = value, - }) - end - - systemPage.tabs:add({ - settingsTab = UI.Window { - tabTitle = 'Settings', - grid = UI.Grid { - y = 1, - values = values, - autospace = true, - sortColumn = 'name', - columns = { - { heading = 'Setting', key = 'name' }, - { heading = 'Value', key = 'value' }, - }, - }, - } - }) - function systemPage.tabs.settingsTab:eventHandler(event) - if event.type == 'grid_select' then - if not event.selected.value or type(event.selected.value) == 'boolean' then - event.selected.value = not event.selected.value - end - settings.set(event.selected.name, event.selected.value) - settings.save('.settings') - self.grid:draw() - return true - end - end -end - -function systemPage.tabs.pathTab.grid:draw() - self.values = { } - for _,v in ipairs(Util.split(env.path, '(.-):')) do - table.insert(self.values, { value = v }) - end - self:update() - UI.Grid.draw(self) -end - -function systemPage.tabs.pathTab:eventHandler(event) - if event.type == 'update_path' then - env.path = self.entry.value - self.grid:setIndex(self.grid:getIndex()) - self.grid:draw() - Config.update('shell', env) - systemPage.notification:success('reboot to take effect') - return true - end -end - -function systemPage.tabs.aliasTab.grid:draw() - self.values = { } - for k,v in pairs(env.aliases) do - table.insert(self.values, { alias = k, path = v }) - end - self:update() - UI.Grid.draw(self) -end - -function systemPage.tabs.aliasTab:eventHandler(event) - if event.type == 'delete_alias' then - env.aliases[self.grid:getSelected().alias] = nil - self.grid:setIndex(self.grid:getIndex()) - self.grid:draw() - Config.update('shell', env) - systemPage.notification:success('reboot to take effect') - return true - - elseif event.type == 'new_alias' then - env.aliases[self.alias.value] = self.path.value - self.alias:reset() - self.path:reset() - self:draw() - self:setFocus(self.alias) - Config.update('shell', env) - systemPage.notification:success('reboot to take effect') - return true - end -end - -function systemPage.tabs.passwordTab:eventHandler(event) - if event.type == 'update_password' then - if #self.newPass.value == 0 then - systemPage.notification:error('Invalid password') - elseif Security.getPassword() and not Security.verifyPassword(SHA1.sha1(self.oldPass.value)) then - systemPage.notification:error('Passwords do not match') - else - Security.updatePassword(SHA1.sha1(self.newPass.value)) - self.oldPass.inactive = false - systemPage.notification:success('Password updated') - end - - return true - end -end - -function systemPage.tabs.infoTab:eventHandler(event) - if event.type == 'update_label' then - os.setComputerLabel(self.label.value) - systemPage.notification:success('Label updated') + systemPage.tabs:selectTab(tab) + self.parent:draw() return true end end @@ -318,13 +51,43 @@ end function systemPage:eventHandler(event) if event.type == 'quit' then UI:exitPullEvents() + + elseif event.type == 'success_message' then + self.notification:success(event.message) + + elseif event.type == 'info_message' then + self.notification:info(event.message) + + elseif event.type == 'error_message' then + self.notification:error(event.message) + elseif event.type == 'tab_activate' then event.activated:focusFirst() + else return UI.Page.eventHandler(self, event) end return true end +local function loadDirectory(dir) + local plugins = { } + for _, file in pairs(fs.list(dir)) do + local s, m = Util.run(_ENV, fs.combine(dir, file)) + if not s and m then + _G.printError('Error loading: ' .. file) + error(m or 'Unknown error') + elseif s and m then + table.insert(plugins, { tab = m, name = m.tabTitle, description = m.description }) + end + end + return plugins +end + +local programDir = fs.getDir(shell.getRunningProgram()) +local plugins = loadDirectory(fs.combine(programDir, 'system'), { }) + +systemPage.tabs.settings.grid:setValues(plugins) + UI:setPage(systemPage) UI:pullEvents() diff --git a/sys/apps/system/aliases.lua b/sys/apps/system/aliases.lua new file mode 100644 index 0000000..cdb38ca --- /dev/null +++ b/sys/apps/system/aliases.lua @@ -0,0 +1,66 @@ +local Config = require('config') +local UI = require('ui') + +local aliasTab = UI.Window { + tabTitle = 'Aliases', + description = 'Shell aliases', + alias = UI.TextEntry { + x = 2, y = 2, ex = -2, + limit = 32, + shadowText = 'Alias', + }, + path = UI.TextEntry { + y = 3, x = 2, ex = -2, + limit = 256, + shadowText = 'Program path', + accelerators = { + enter = 'new_alias', + }, + }, + grid = UI.Grid { + y = 5, + sortColumn = 'alias', + columns = { + { heading = 'Alias', key = 'alias' }, + { heading = 'Program', key = 'path' }, + }, + accelerators = { + delete = 'delete_alias', + }, + }, +} + +function aliasTab.grid:draw() + self.values = { } + local env = Config.load('shell') + for k,v in pairs(env.aliases) do + table.insert(self.values, { alias = k, path = v }) + end + self:update() + UI.Grid.draw(self) +end + +function aliasTab:eventHandler(event) + if event.type == 'delete_alias' then + local env = Config.load('shell') + env.aliases[self.grid:getSelected().alias] = nil + self.grid:setIndex(self.grid:getIndex()) + self.grid:draw() + Config.update('shell', env) + self:emit({ type = 'success_message', message = 'reboot to take effect' }) + return true + + elseif event.type == 'new_alias' then + local env = Config.load('shell') + env.aliases[self.alias.value] = self.path.value + self.alias:reset() + self.path:reset() + self:draw() + self:setFocus(self.alias) + Config.update('shell', env) + self:emit({ type = 'success_message', message = 'reboot to take effect' }) + return true + end +end + +return aliasTab diff --git a/sys/apps/system/label.lua b/sys/apps/system/label.lua new file mode 100644 index 0000000..0d03425 --- /dev/null +++ b/sys/apps/system/label.lua @@ -0,0 +1,49 @@ +local UI = require('ui') +local Util = require('util') + +local fs = _G.fs +local os = _G.os + +local labelTab = UI.Window { + tabTitle = 'Label', + description = 'Set the computer label', + labelText = UI.Text { + x = 3, y = 2, + value = 'Label' + }, + label = UI.TextEntry { + x = 9, y = 2, ex = -4, + limit = 32, + value = os.getComputerLabel(), + accelerators = { + enter = 'update_label', + }, + }, + grid = UI.ScrollingGrid { + y = 3, + values = { + { name = '', value = '' }, + { name = 'CC version', value = Util.getVersion() }, + { name = 'Lua version', value = _VERSION }, + { name = 'MC version', value = Util.getMinecraftVersion() }, + { name = 'Disk free', value = Util.toBytes(fs.getFreeSpace('/')) }, + { name = 'Computer ID', value = tostring(os.getComputerID()) }, + { name = 'Day', value = tostring(os.day()) }, + }, + inactive = true, + columns = { + { key = 'name', width = 12 }, + { key = 'value' }, + }, + }, +} + +function labelTab:eventHandler(event) + if event.type == 'update_label' then + os.setComputerLabel(self.label.value) + self:emit({ type = 'success_message', message = 'Label updated' }) + return true + end +end + +return labelTab diff --git a/sys/apps/system/network.lua b/sys/apps/system/network.lua new file mode 100644 index 0000000..0b9737d --- /dev/null +++ b/sys/apps/system/network.lua @@ -0,0 +1,56 @@ +local Config = require('config') +local UI = require('ui') + +local device = _G.device + +local tab = UI.Window { + tabTitle = 'Network', + description = 'Networking options', + form = UI.Form { + x = 2, + manualControls = true, + modem = UI.Chooser { + formLabel = 'Modem', formKey = 'modem', + nochoice = 'auto', + }, + update = UI.Button { + x = 9, y = 4, + text = 'Update', event = 'form_complete', + }, + }, +} + +function tab:enable() + local width = 7 + local choices = { + { name = 'auto', value = 'auto' }, + { name = 'disable', value = 'none' }, + } + + for k,v in pairs(device) do + if v.isWireless and v.isWireless() and k ~= 'wireless_modem' then + table.insert(choices, { name = k, value = v.name }) + width = math.max(width, #k) + end + end + + self.form.modem.choices = choices + self.form.modem.width = width + 4 + + local config = Config.load('os') + self.form.modem.value = config.wirelessModem or 'auto' + + UI.Window.enable(self) +end + +function tab:eventHandler(event) + if event.type == 'form_complete' then + local config = Config.load('os') + config.wirelessModem = self.form.modem.value + Config.update('os', config) + self:emit({ type = 'success_message', message = 'reboot to take effect' }) + return true + end +end + +return tab diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua new file mode 100644 index 0000000..23524fd --- /dev/null +++ b/sys/apps/system/password.lua @@ -0,0 +1,53 @@ +local Security = require('security') +local SHA1 = require('sha1') +local UI = require('ui') + +local passwordTab = UI.Window { + tabTitle = 'Password', + description = 'Wireless network password', + oldPass = UI.TextEntry { + x = 2, y = 2, ex = -2, + limit = 32, + mask = true, + shadowText = 'old password', + inactive = not Security.getPassword(), + }, + newPass = UI.TextEntry { + y = 3, x = 2, ex = -2, + limit = 32, + mask = true, + shadowText = 'new password', + accelerators = { + enter = 'new_password', + }, + }, + button = UI.Button { + x = 2, y = 5, + text = 'Update', + event = 'update_password', + }, + info = UI.TextArea { + x = 2, ex = -2, + y = 7, + inactive = true, + value = 'Add a password to enable other computers to connect to this one.', + } +} +function passwordTab:eventHandler(event) + if event.type == 'update_password' then + if #self.newPass.value == 0 then + self:emit({ type = 'error_message', message = 'Invalid password' }) + + elseif Security.getPassword() and not Security.verifyPassword(SHA1.sha1(self.oldPass.value)) then + self:emit({ type = 'error_message', message = 'Passwords do not match' }) + + else + Security.updatePassword(SHA1.sha1(self.newPass.value)) + self.oldPass.inactive = false + self:emit({ type = 'success_message', message = 'Password updated' }) + end + return true + end +end + +return passwordTab diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua new file mode 100644 index 0000000..d55211a --- /dev/null +++ b/sys/apps/system/path.lua @@ -0,0 +1,50 @@ +local Config = require('config') +local UI = require('ui') +local Util = require('util') + +local shell = _ENV.shell + +local pathTab = UI.Window { + tabTitle = 'Path', + description = 'Set the shell path', + tabClose = true, + entry = UI.TextEntry { + x = 2, y = 2, ex = -2, + limit = 256, + value = shell.path(), + shadowText = 'enter system path', + accelerators = { + enter = 'update_path', + }, + }, + grid = UI.Grid { + y = 4, + disableHeader = true, + columns = { { key = 'value' } }, + autospace = true, + }, +} + +function pathTab.grid:draw() + self.values = { } + local env = Config.load('shell') + for _,v in ipairs(Util.split(env.path, '(.-):')) do + table.insert(self.values, { value = v }) + end + self:update() + UI.Grid.draw(self) +end + +function pathTab:eventHandler(event) + if event.type == 'update_path' then + local env = Config.load('shell') + env.path = self.entry.value + self.grid:setIndex(self.grid:getIndex()) + self.grid:draw() + Config.update('shell', env) + self:emit({ type = 'success_message', message = 'reboot to take effect' }) + return true + end +end + +return pathTab diff --git a/sys/apps/system/settings.lua b/sys/apps/system/settings.lua new file mode 100644 index 0000000..2722dab --- /dev/null +++ b/sys/apps/system/settings.lua @@ -0,0 +1,47 @@ +local UI = require('ui') + +local settings = _G.settings + +if settings then + + local values = { } + for _,v in pairs(settings.getNames()) do + local value = settings.get(v) + if not value then + value = false + end + table.insert(values, { + name = v, + value = value, + }) + end + + local settingsTab = UI.Window { + tabTitle = 'Settings', + description = 'Computercraft configurable settings', + grid = UI.Grid { + y = 1, + values = values, + autospace = true, + sortColumn = 'name', + columns = { + { heading = 'Setting', key = 'name' }, + { heading = 'Value', key = 'value' }, + }, + }, + } + + function settingsTab:eventHandler(event) + if event.type == 'grid_select' then + if not event.selected.value or type(event.selected.value) == 'boolean' then + event.selected.value = not event.selected.value + end + settings.set(event.selected.name, event.selected.value) + settings.save('.settings') + self.grid:draw() + return true + end + end + + return settingsTab +end diff --git a/sys/apps/system/turtle.lua b/sys/apps/system/turtle.lua new file mode 100644 index 0000000..18150de --- /dev/null +++ b/sys/apps/system/turtle.lua @@ -0,0 +1,62 @@ +local Config = require('config') +local UI = require('ui') + +local fs = _G.fs +local turtle = _G.turtle + +if turtle then + local Home = require('turtle.home') + local values = { } + Config.load('gps', values.home and { values.home } or { }) + + local gpsTab = UI.Window { + tabTitle = 'GPS', + labelText = UI.Text { + x = 3, y = 2, + value = 'On restart, return to this location' + }, + grid = UI.Grid { + x = 3, ex = -3, y = 4, + height = 2, + values = values, + inactive = true, + columns = { + { heading = 'x', key = 'x' }, + { heading = 'y', key = 'y' }, + { heading = 'z', key = 'z' }, + }, + }, + button1 = UI.Button { + x = 3, y = 7, + text = 'Set home', + event = 'gps_set', + }, + button2 = UI.Button { + ex = -3, y = 7, width = 7, + text = 'Clear', + event = 'gps_clear', + }, + } + function gpsTab:eventHandler(event) + if event.type == 'gps_set' then + self:emit({ type = 'info_message', message = 'Determining location' }) + self:sync() + if Home.set() then + Config.load('gps', values) + self.grid:setValues(values.home and { values.home } or { }) + self.grid:draw() + self:emit({ type = 'success_message', message = 'Location set' }) + else + self:emit({ type = 'error_message', message = 'Unable to determine location' }) + end + return true + elseif event.type == 'gps_clear' then + fs.delete('usr/config/gps') + self.grid:setValues({ }) + self.grid:draw() + return true + end + end + + return gpsTab +end diff --git a/sys/extensions/5.network.lua b/sys/extensions/5.network.lua index 3963ae2..417126e 100644 --- a/sys/extensions/5.network.lua +++ b/sys/extensions/5.network.lua @@ -18,8 +18,12 @@ end local function setModem(dev) if not device.wireless_modem and dev.isWireless() then - local config = Config.load('os', { }) - if not config.wirelessModem or dev.name == config.wirelessModem then + local config = Config.load('os') + + if not config.wirelessModem or + config.wirelessModem == 'auto' or + dev.name == config.wirelessModem then + device.wireless_modem = dev os.queueEvent('device_attach', 'wireless_modem') return dev diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index cc68ddd..876e2d6 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -3,8 +3,9 @@ _G.requireInjector(_ENV) local Packages = require('packages') local Util = require('util') +local fs = _G.fs +local help = _G.help local shell = _ENV.shell -local fs = _G.fs local appPaths = Util.split(shell.path(), '(.-);') local luaPaths = Util.split(_G.LUA_PATH, '(.-);') @@ -26,6 +27,9 @@ end -- dependency graph -- https://github.com/mpeterv/depgraph/blob/master/src/depgraph/init.lua +local helpPaths = Util.split(help.path(), '(.-):') +table.insert(helpPaths, '/sys/help') + for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) if fs.exists(fs.combine(packageDir, '.install')) then @@ -40,7 +44,14 @@ for name in pairs(Packages:installed()) do if fs.exists(apiPath) then addPath(luaPaths, apiPath) end + + local helpPath = fs.combine(fs.combine('packages', name), 'help') + if fs.exists(helpPath) then + table.insert(helpPaths, helpPath) + end end +help.setPath(table.concat(helpPaths, ':')) + shell.setPath(table.concat(appPaths, ':')) _G.LUA_PATH = table.concat(luaPaths, ';') diff --git a/sys/help/Opus Applications b/sys/help/Opus Applications new file mode 100644 index 0000000..a7747a3 --- /dev/null +++ b/sys/help/Opus Applications @@ -0,0 +1,30 @@ +Opus applications are grouped into packages with a common theme. + +To install a package, use either the System -> Packages program or the package command line program. + +Shell usage: + +> package list +> package install +> package update +> package uninstall + +Package definitions are located in usr/apps/packages. This file can be modified to add custom packages. + +Current stable packages +======================= + +* core +Programming and miscellaneous applications. Also contains drivers needed for other packages. + +* builder +A program for creating structures from schematic files using a turtle (requires core). + +* farms +Various programs for farming resources (wood, crops, animals). + +* milo +An A/E like storage implementation (requires core). + +* miners +Mining programs. diff --git a/sys/help/Wireless Networking b/sys/help/Wireless Networking new file mode 100644 index 0000000..9411058 --- /dev/null +++ b/sys/help/Wireless Networking @@ -0,0 +1,7 @@ +To establish one-way trust between two computers with modems, run the following in a shell prompt: + +On the target computer, run: +> password + +On the source computer, run: +> trust From 1264b0149bb50fd5e17ffecefa472c0a53d5d44f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 23 Dec 2018 17:32:06 -0500 Subject: [PATCH 015/231] require overhaul part 2 --- sys/apis/injector.lua | 31 +++++------ sys/apps/System.lua | 8 --- sys/apps/shell | 101 ++-------------------------------- sys/extensions/6.packages.lua | 34 ++++++------ 4 files changed, 37 insertions(+), 137 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 74fda7f..39ee742 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -4,9 +4,10 @@ local DEFAULT_PATH = '/sys/apis/?;/sys/apis/?.lua' local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'master' local DEFAULT_UPATH = GIT_URL .. '/kepler155c/opus/' .. DEFAULT_BRANCH .. '/sys/apis' -local fs = _G.fs -local http = _G.http -local os = _G.os +local fs = _G.fs +local http = _G.http +local os = _G.os +local string = _G.string if not http._patched then -- fix broken http get @@ -58,7 +59,7 @@ local function loadUrl(url) end -- Add require and package to the environment -local function requireWrapper(env) +return function(env) local function standardSearcher(modname) if env.package.loaded[modname] then @@ -71,10 +72,13 @@ local function requireWrapper(env) local function shellSearcher(modname) local fname = modname:gsub('%.', '/') .. '.lua' - if env.shell and type(env.shell.dir) == 'function' then - local path = env.shell.resolve(fname) - if fs.exists(path) and not fs.isDir(path) then - return loadfile(path, env) + if env.shell and type(env.shell.getRunningProgram) == 'function' then + local running = env.shell.getRunningProgram() + if running then + local path = fs.combine(fs.getDir(running), fname) + if fs.exists(path) and not fs.isDir(path) then + return loadfile(path, env) + end end end end @@ -145,11 +149,12 @@ local function requireWrapper(env) upath = env.LUA_UPATH or _G.LUA_UPATH or DEFAULT_UPATH, config = '/\n:\n?\n!\n-', loaded = { + coroutine = coroutine, + io = io, math = math, + os = os, string = string, table = table, - io = io, - os = os, }, loaders = { standardSearcher, @@ -181,9 +186,3 @@ local function requireWrapper(env) return env.require -- backwards compatible end - -return function(env) - env = env or getfenv(2) - --setfenv(requireWrapper, env) - return requireWrapper(env) -end diff --git a/sys/apps/System.lua b/sys/apps/System.lua index ed742ef..464f1f2 100644 --- a/sys/apps/System.lua +++ b/sys/apps/System.lua @@ -1,4 +1,3 @@ -local Config = require('config') local UI = require('ui') local Util = require('util') @@ -7,13 +6,6 @@ local shell = _ENV.shell UI:configure('System', ...) -local env = { - path = shell.path(), - aliases = shell.aliases(), - lua_path = _ENV.LUA_PATH, -} -Config.load('shell', env) - local systemPage = UI.Page { tabs = UI.Tabs { settings = UI.Window { diff --git a/sys/apps/shell b/sys/apps/shell index 1bcece8..24805dd 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -77,97 +77,6 @@ local function run(env, ...) return table.unpack(r) end -local function createShellEnv(sDir) - local tEnv = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) - - local package - - package = { - loaded = { - _G = _G, - bit32 = bit32, - coroutine = coroutine, - math = math, - package = package, - string = string, - table = table, - }, - path = _G.LUA_PATH, - config = "/\n;\n?\n!\n-", - preload = { }, - loaders = { - function( name ) - if package.preload[name] then - return package.preload[name] - else - return nil, "no field package.preload['" .. name .. "']" - end - end, - function( name ) - local fname = string.gsub(name, "%.", "/") - local sError = "" - for pattern in string.gmatch(package.path, "[^;]+") do - local sPath = string.gsub(pattern, "%?", fname) - if sPath:sub(1,1) ~= "/" then - sPath = fs.combine(sDir, sPath) - end - if fs.exists(sPath) and not fs.isDir(sPath) then - local fnFile, sError = loadfile( sPath, tEnv ) - if fnFile then - return fnFile, sPath - else - return nil, sError - end - else - if #sError > 0 then - sError = sError .. "\n" - end - sError = sError .. "no file '" .. sPath .. "'" - end - end - return nil, sError - end - } - } - - local sentinel = {} - local function require( name ) - if type( name ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 2 ) - end - if package.loaded[name] == sentinel then - error("Loop detected requiring '" .. name .. "'", 0) - end - if package.loaded[name] then - return package.loaded[name] - end - - local sError = "Error loading module '" .. name .. "':" - for _,searcher in ipairs(package.loaders) do - local loader, err = searcher(name) - if loader then - package.loaded[name] = sentinel - local result = loader( err ) - if result ~= nil then - package.loaded[name] = result - return result - else - package.loaded[name] = true - return true - end - else - sError = sError .. "\n" .. err - end - end - error(sError, 2) - end - - tEnv["package"] = package - tEnv["require"] = require - - return tEnv - end - -- Install shell API function shell.run(...) local oldTitle @@ -176,8 +85,9 @@ function shell.run(...) oldTitle = _ENV.multishell.getTitle(_ENV.multishell.getCurrent()) end - local env = createShellEnv(shell.dir()) - -- local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + _G.requireInjector(env) + local r = { pcall(run, env, ...) } if _ENV.multishell then @@ -441,8 +351,9 @@ end local tArgs = { ... } if #tArgs > 0 then - local env = createShellEnv(shell.dir()) --- local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) + _G.requireInjector(env) + return run(env, ...) end diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index 876e2d6..04c96be 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -9,26 +9,24 @@ local shell = _ENV.shell local appPaths = Util.split(shell.path(), '(.-);') local luaPaths = Util.split(_G.LUA_PATH, '(.-);') +local helpPaths = Util.split(help.path(), '(.-):') -local function addPath(t, path) - local function addEntry(e) - for _,v in ipairs(t) do - if v == e then - return true - end +table.insert(helpPaths, '/sys/help') + +local function addEntry(t, e) + for _,v in ipairs(t) do + if v == e then + return true end - table.insert(t, 1, e) end - addEntry(string.format('/%s/?', path)) - addEntry(string.format('/%s/?.lua', path)) - addEntry(string.format('/%s/?/init.lua', path)) + table.insert(t, 1, e) end --- dependency graph --- https://github.com/mpeterv/depgraph/blob/master/src/depgraph/init.lua - -local helpPaths = Util.split(help.path(), '(.-):') -table.insert(helpPaths, '/sys/help') +local function addRequirePath(t, path) + addEntry(t, string.format('/%s/?', path)) + addEntry(t, string.format('/%s/?.lua', path)) + addEntry(t, string.format('/%s/?/init.lua', path)) +end for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) @@ -39,13 +37,13 @@ for name in pairs(Packages:installed()) do end end - addPath(appPaths, packageDir) + addEntry(appPaths, packageDir) local apiPath = fs.combine(fs.combine('packages', name), 'apis') if fs.exists(apiPath) then - addPath(luaPaths, apiPath) + addRequirePath(luaPaths, apiPath) end - local helpPath = fs.combine(fs.combine('packages', name), 'help') + local helpPath = '/' .. fs.combine(fs.combine('packages', name), 'help') if fs.exists(helpPath) then table.insert(helpPaths, helpPath) end From 63435891833f64ccebbcc9dfa0b674ef3572b248 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 23 Dec 2018 19:49:28 -0500 Subject: [PATCH 016/231] javascript style table functions --- sys/apis/util.lua | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 29a865e..4630a6e 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -119,13 +119,13 @@ function Util.signum(num) end end -function Util.clamp(lo, n, hi) +function Util.clamp(lo, num, hi) if num <= lo then return lo elseif num >= hi then return hi else - return n + return num end end @@ -314,15 +314,33 @@ function Util.size(list) return 0 end +local function isArray(value) + -- dubious + return type(value) == "table" and (value[1] or next(value) == nil) +end + function Util.removeByValue(t, e) for k,v in pairs(t) do if v == e then - table.remove(t, k) + if isArray(t) then + table.remove(t, k) + else + t[k] = nil + end break end end end +function Util.every(t, fn) + for _,v in pairs(t) do + if not fn(v) then + return false + end + end + return true +end + function Util.each(list, func) for index, value in pairs(list) do func(value, index, list) From 0b326589c261593fd40c4f8c95ffa4bc29d7f442 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 26 Dec 2018 04:01:40 -0500 Subject: [PATCH 017/231] reorg app db --- sys/apps/Overview.lua | 9 +++------ sys/help/{Opus Applications => Opus-Applications} | 0 sys/help/{Wireless Networking => Wireless-Networking} | 0 3 files changed, 3 insertions(+), 6 deletions(-) rename sys/help/{Opus Applications => Opus-Applications} (100%) rename sys/help/{Wireless Networking => Wireless-Networking} (100%) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index a1751ea..46d1244 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -128,13 +128,10 @@ local function loadApplications() applications = Util.readTable('sys/etc/app.db') for dir in pairs(Packages:installed()) do - local path = fs.combine('packages/' .. dir, 'etc/apps') + local path = fs.combine('packages/' .. dir, 'etc/apps.db') if fs.exists(path) then - local dbs = fs.list(path) - for _, db in pairs(dbs) do - local apps = Util.readTable(fs.combine(path, db)) or { } - Util.merge(applications, apps) - end + local apps = Util.readTable(path) or { } + Util.merge(applications, apps) end end diff --git a/sys/help/Opus Applications b/sys/help/Opus-Applications similarity index 100% rename from sys/help/Opus Applications rename to sys/help/Opus-Applications diff --git a/sys/help/Wireless Networking b/sys/help/Wireless-Networking similarity index 100% rename from sys/help/Wireless Networking rename to sys/help/Wireless-Networking From 8cfeaad061932746d8f79d69a75657457347a650 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 27 Dec 2018 00:45:03 -0500 Subject: [PATCH 018/231] turtle.unequip + justified headings bug --- sys/apis/ui.lua | 5 +++++ sys/extensions/6.tl3.lua | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index c9bcabc..7911419 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -1490,6 +1490,7 @@ end function UI.Grid:drawHeadings() local x = 1 + local sb = UI.StringBuffer(self.width) for _,col in ipairs(self.columns) do local ind = ' ' if col.key == self.sortColumn then @@ -1499,13 +1500,17 @@ function UI.Grid:drawHeadings() ind = self.sortIndicator end end + sb:insert(ind .. col.heading, col.cw + 1) + --[[ self:write(x, 1, Util.widthify(ind .. col.heading, col.cw + 1), self.headerBackgroundColor, col.key == self.sortColumn and self.headerSortColor or self.headerTextColor) x = x + col.cw + 1 + ]] end + self:write(1, 1, sb:get(), self.headerBackgroundColor, self.headerTextColor) end function UI.Grid:sortCompare(a, b) diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index f231f4b..1ad1088 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -935,6 +935,13 @@ function turtle.isEquipped(item) end end +function turtle.unequip(side) + if not turtle.selectSlotWithQuantity(0) then + return false, 'No slots available' + end + return turtle.equip(side) +end + -- [[ ]] -- function turtle.run(fn, ...) local args = { ... } @@ -980,6 +987,12 @@ function turtle.addWorldBlock(pt) Pathing.addBlock(pt) end +function turtle.addWorldBlocks(pts) + Util.each(pts, function(pt) + Pathing.addBlock(pt) + end) +end + local movementStrategy = turtle.pathfind function turtle.setMovementStrategy(strategy) From e3a8e4e7901719046c57543367ac275705bb4c5b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 27 Dec 2018 03:05:12 -0500 Subject: [PATCH 019/231] env cleanup --- sys/apis/injector.lua | 4 ++-- sys/apps/system/path.lua | 6 ++---- sys/extensions/4.user.lua | 28 +++++++++++----------------- sys/extensions/6.packages.lua | 2 +- sys/extensions/6.tl3.lua | 2 +- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 39ee742..da6e434 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -1,7 +1,7 @@ local PASTEBIN_URL = 'http://pastebin.com/raw' local GIT_URL = 'https://raw.githubusercontent.com' -local DEFAULT_PATH = '/sys/apis/?;/sys/apis/?.lua' -local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'master' +local DEFAULT_PATH = (package and (package.path .. ':') or '') .. '/sys/apis/?;/sys/apis/?.lua' +local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'develop-1.8' local DEFAULT_UPATH = GIT_URL .. '/kepler155c/opus/' .. DEFAULT_BRANCH .. '/sys/apis' local fs = _G.fs diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index d55211a..5374634 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -2,8 +2,6 @@ local Config = require('config') local UI = require('ui') local Util = require('util') -local shell = _ENV.shell - local pathTab = UI.Window { tabTitle = 'Path', description = 'Set the shell path', @@ -11,7 +9,7 @@ local pathTab = UI.Window { entry = UI.TextEntry { x = 2, y = 2, ex = -2, limit = 256, - value = shell.path(), + value = Config.load('shell').path, shadowText = 'enter system path', accelerators = { enter = 'update_path', @@ -39,9 +37,9 @@ function pathTab:eventHandler(event) if event.type == 'update_path' then local env = Config.load('shell') env.path = self.entry.value + Config.update('shell', env) self.grid:setIndex(self.grid:getIndex()) self.grid:draw() - Config.update('shell', env) self:emit({ type = 'success_message', message = 'reboot to take effect' }) return true end diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index dbdbe35..49e5d91 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -11,25 +11,13 @@ end if not fs.exists('usr/autorun') then fs.makeDir('usr/autorun') end ---if not fs.exists('usr/config/fstab') then --- Util.writeFile('usr/config/fstab', --- 'usr gitfs kepler155c/opus-apps/' .. _G.OPUS_BRANCH) ---end -local lua_path = '?;?.lua;?/init.lua' -lua_path = lua_path .. ';/usr/apis/?;/usr/apis/?.lua' -lua_path = lua_path .. ';/sys/apis/?;/sys/apis/?.lua' -lua_path = lua_path .. ';/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua;' -if _G.turtle then - lua_path = lua_path..';/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua' -elseif _G.command then - lua_path = lua_path..';/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua' -end +local lua_path = package.path if not fs.exists('usr/config/shell') then Util.writeTable('usr/config/shell', { aliases = shell.aliases(), - path = 'usr/apps:sys/apps:' .. shell.path(), + path = 'usr/apps', lua_path = lua_path, }) end @@ -54,8 +42,14 @@ if config.aliases then shell.setAlias(k, v) end end -shell.setPath(config.path) ---_G.LUA_PATH = config.lua_path -_G.LUA_PATH = lua_path + +local path = config.path and Util.split(config.path, '(.-):') or { } +table.insert(path, 'sys/apps') +for _, v in pairs(Util.split(shell.path(), '(.-):')) do + table.insert(path, v) +end + +shell.setPath(table.concat(path, ':')) +_G.LUA_PATH = config.lua_path fs.loadTab('usr/config/fstab') diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index 04c96be..64ba8ab 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -7,7 +7,7 @@ local fs = _G.fs local help = _G.help local shell = _ENV.shell -local appPaths = Util.split(shell.path(), '(.-);') +local appPaths = Util.split(shell.path(), '(.-):') local luaPaths = Util.split(_G.LUA_PATH, '(.-);') local helpPaths = Util.split(help.path(), '(.-):') diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 1ad1088..33006b4 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -879,7 +879,7 @@ function turtle.condense() if slots[j].count > 0 and (slots[i].count == 0 or slots[i].key == slots[j].key) then turtle.select(j) if turtle.transferTo(i) then - local transferred = turtle.getItemCount(i) - slots[i].qty + local transferred = turtle.getItemCount(i) - slots[i].count slots[j].count = slots[j].count - transferred slots[i].count = slots[i].count + transferred slots[i].key = slots[j].key From 44d2d13e408765214cb97416ca2ac4a6ea6ce3f8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 27 Dec 2018 03:08:11 -0500 Subject: [PATCH 020/231] env cleanup --- sys/apis/injector.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index da6e434..16878e3 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -1,6 +1,6 @@ local PASTEBIN_URL = 'http://pastebin.com/raw' local GIT_URL = 'https://raw.githubusercontent.com' -local DEFAULT_PATH = (package and (package.path .. ':') or '') .. '/sys/apis/?;/sys/apis/?.lua' +local DEFAULT_PATH = (package and (package.path .. ';') or '?;?.lua;?/init.lua;') .. '/sys/apis/?;/sys/apis/?.lua' local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'develop-1.8' local DEFAULT_UPATH = GIT_URL .. '/kepler155c/opus/' .. DEFAULT_BRANCH .. '/sys/apis' From 89e47f8b93a17b3607ad1f962020baf13c1a5276 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Dec 2018 22:33:58 -0500 Subject: [PATCH 021/231] file associations --- sys/apps/Files.lua | 126 ++++++++++++++++++++++++++++++++++++++++++--- sys/apps/pain.lua | 1 + sys/etc/app.db | 2 +- 3 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 sys/apps/pain.lua diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 464ab75..c2a108a 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Config = require('config') local Event = require('event') local UI = require('ui') @@ -13,13 +11,14 @@ local shell = _ENV.shell UI:configure('Files', ...) -local config = { +local config = Config.load('Files', { showHidden = false, showDirSizes = false, +}) +config.associations = config.associations or { + nft = 'pain', } -Config.load('Files', config) - local copied = { } local marked = { } local directories = { } @@ -61,6 +60,11 @@ local Browser = UI.Page { { text = 'Hidden ^h', event = 'toggle_hidden' }, { text = 'Dir Size ^s', event = 'toggle_dirSize' }, } }, + { text = '\206', + x = -3, + dropdown = { + { text = 'Associations', event = 'associate' }, + } }, }, }, grid = UI.ScrollingGrid { @@ -78,6 +82,56 @@ local Browser = UI.Page { { key = 'totalSize', width = 6 }, }, }, + associations = UI.SlideOut { + backgroundColor = colors.cyan, + menuBar = UI.MenuBar { + buttons = { + { text = 'Save', event = 'save' }, + { text = 'Cancel', event = 'cancel' }, + }, + }, + grid = UI.ScrollingGrid { + x = 2, ex = -6, y = 3, ey = -5, + columns = { + { heading = 'Name', key = 'name' }, + { heading = 'Value', key = 'value' }, + }, + sortColumn = 'name', + accelerators = { + delete = 'remove_entry', + }, + }, + remove = UI.Button { + x = -4, y = 6, + text = '-', event = 'remove_entry', help = 'Remove', + }, + form = UI.Form { + x = 3, y = -3, ey = -2, + margin = 1, + manualControls = true, + [1] = UI.TextEntry { + width = 20, + formLabel = 'Name', formKey = 'name', + shadowText = 'extension', + required = true, + limit = 64, + }, + [2] = UI.TextEntry { + width = 20, + formLabel = 'Name', formKey = 'value', + shadowText = 'program', + required = true, + limit = 64, + }, + add = UI.Button { + x = -11, y = 1, + text = 'Add', event = 'add_association', + }, + }, + statusBar = UI.StatusBar { + backgroundColor = colors.cyan, + }, + }, accelerators = { q = 'quit', e = 'edit', @@ -294,6 +348,9 @@ function Browser:eventHandler(event) self.grid:draw() self:setStatus('Refreshed') + elseif event.type == 'associate' then + self.associations:show() + elseif event.type == 'toggle_hidden' then config.showHidden = not config.showHidden Config.update('Files', config) @@ -336,7 +393,12 @@ function Browser:eventHandler(event) if file.isDir then self:setDir(file.fullName) else - self:run(file.name) + local ext = file.name:match('%.(%w+)$') + if ext and config.associations[ext] then + self:run(config.associations[ext], '/' .. file.fullName) + else + self:run(file.name) + end end end @@ -405,6 +467,58 @@ function Browser:eventHandler(event) return true end +--[[ Associations slide out ]] -- +function Browser.associations:show() + self.grid.values = { } + for k, v in pairs(config.associations) do + table.insert(self.grid.values, { + name = k, + value = v, + }) + end + self.grid:update() + UI.SlideOut.show(self) + self:setFocus(self.form[1]) +end + +function Browser.associations:eventHandler(event) + if event.type == 'remove_entry' then + local row = self.grid:getSelected() + if row then + Util.removeByValue(self.grid.values, row) + self.grid:update() + self.grid:draw() + end + + elseif event.type == 'add_association' then + if self.form:save() then + local entry = Util.find(self.grid.values, 'name', self.form[1].value) or { } + entry.name = self.form[1].value + entry.value = self.form[2].value + table.insert(self.grid.values, entry) + self.form[1]:reset() + self.form[2]:reset() + self.grid:update() + self.grid:draw() + end + + elseif event.type == 'cancel' then + self:hide() + + elseif event.type == 'save' then + config.associations = { } + for _, v in pairs(self.grid.values) do + config.associations[v.name] = v.value + end + Config.update('Files', config) + self:hide() + + else + return UI.SlideOut.eventHandler(self, event) + end + return true +end + --[[-- Startup logic --]]-- local args = { ... } diff --git a/sys/apps/pain.lua b/sys/apps/pain.lua new file mode 100644 index 0000000..44f9ead --- /dev/null +++ b/sys/apps/pain.lua @@ -0,0 +1 @@ +require('util').runUrl(_ENV, 'http://pastebin.com/raw/wJQ7jav0', ...) \ No newline at end of file diff --git a/sys/etc/app.db b/sys/etc/app.db index 353b20b..643db6a 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -90,7 +90,7 @@ icon = "\030 \031f\0307\031f\159\030 \159\030 \ \030 \031f\0308\031f\135\0307\0318\144\140\030f\0317\159\143\031c\139\0302\135\030f\0312\157\ \030 \031f\030f\0318\143\133\0312\136\0302\031f\159\159\143\131\030f\0312\132", - run = "http://pastebin.com/raw/wJQ7jav0", + run = "pain", }, [ "48d6857f6b2869d031f463b13aa34df47e18c548" ] = { title = "Breakout", From 09f436a3c2c1ea167fb9276fc3d0274e59bdf699 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Dec 2018 00:07:29 -0500 Subject: [PATCH 022/231] more help --- sys/help/Opus | 39 ++++++++++++++++++++++++++++++++++++ sys/help/Overview | 15 ++++++++++++++ sys/help/Wireless-Networking | 7 ------- 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 sys/help/Opus create mode 100644 sys/help/Overview delete mode 100644 sys/help/Wireless-Networking diff --git a/sys/help/Opus b/sys/help/Opus new file mode 100644 index 0000000..e4c1fc3 --- /dev/null +++ b/sys/help/Opus @@ -0,0 +1,39 @@ +Shortcut Keys +============= + * Control-o: Show the Overview + * Control-tab: Cycle to next tab + * Control-shift-tab: Cycle to previous tab + * Control-d: Show/toggle logging screen + * Control-c: Copy (in most applications) + * Control-shift-v: Paste from internal clipboard + * Control-shift-doubleclick: Open in Lua the clicked UI element + +Wireless Networking +=================== +To establish one-way trust between two computers with modems, run the following in a shell prompt: + +On the target computer, run: +> password + +On the source computer, run: +> trust + +Running Custom Programs +======================= +To create a program that runs at startup, create a file in /usr/autorun to start the program. Example: + +In file: /usr/autorun/startup.lua +shell.openForegroundTab('myprogram') + +There are 3 different ways to open tabs: + + * shell.openTab : background tab + * shell.openForegroundTab : focused tab + * shell.openHiddenTab : appears only in the Tasks application + +Copy / Paste +============ +Opus can paste from both the system clipboard and the internal clipboard. + + * control-v: for normal clipboard + * control-shift-v: for internal clipboard diff --git a/sys/help/Overview b/sys/help/Overview new file mode 100644 index 0000000..d39a4dd --- /dev/null +++ b/sys/help/Overview @@ -0,0 +1,15 @@ +Overview is the main application launcher. + +Shortcut keys +============= + * s: Shell + * l: Lua application + * f: Files + * e: Edit an application (or right-click) + * control-n: Add a new application + * delete: Delete an application + +Adding a new application +======================== +The run entry can be either a disk file or a URL. +Icons must be in NFT format with a height of 3 and a width of 3 to 8 characters. \ No newline at end of file diff --git a/sys/help/Wireless-Networking b/sys/help/Wireless-Networking deleted file mode 100644 index 9411058..0000000 --- a/sys/help/Wireless-Networking +++ /dev/null @@ -1,7 +0,0 @@ -To establish one-way trust between two computers with modems, run the following in a shell prompt: - -On the target computer, run: -> password - -On the source computer, run: -> trust From f19d439314aa7b692964b8eda2431c814d93db0a Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Dec 2018 06:15:16 -0500 Subject: [PATCH 023/231] upgrade shell config file --- sys/apis/ui.lua | 2 +- sys/extensions/4.user.lua | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 7911419..03e52b0 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -3212,7 +3212,7 @@ function UI.TextArea:draw() -- self:setCursorPos(1, 1) self.cursorX, self.cursorY = 1, 1 self:print(self.value) - self.ymax = self.cursorY + 1 + self.ymax = self.cursorY for _,child in pairs(self.children) do if child.enabled then diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 49e5d91..c6d0d9e 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -14,11 +14,18 @@ end local lua_path = package.path +-- TODO: Temporary +local upgrade = Util.readTable('usr/config/shell') +if upgrade and not upgrade.upgraded then + fs.delete('usr/config/shell') +end + if not fs.exists('usr/config/shell') then Util.writeTable('usr/config/shell', { aliases = shell.aliases(), path = 'usr/apps', lua_path = lua_path, + upgraded = true, }) end From 852bf3f6a69b2473e64b123dee4d0016909d7035 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Dec 2018 06:50:59 -0500 Subject: [PATCH 024/231] require order issue --- sys/apis/injector.lua | 24 +++++++++++++++++++++++- sys/extensions/6.packages.lua | 10 +++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 16878e3..fa11bb1 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -1,6 +1,28 @@ local PASTEBIN_URL = 'http://pastebin.com/raw' local GIT_URL = 'https://raw.githubusercontent.com' -local DEFAULT_PATH = (package and (package.path .. ';') or '?;?.lua;?/init.lua;') .. '/sys/apis/?;/sys/apis/?.lua' + +local function split(str, pattern) + local t = { } + local function helper(line) table.insert(t, line) return "" end + helper((str:gsub(pattern, helper))) + return t +end + +local luaPaths = package and package.path and split(package.path, '(.-);') or { } +for i = 1, #luaPaths do + if luaPaths[i] == '?' or luaPaths[i] == '?.lua' then + luaPaths[i] = nil + end +end + +table.insert(luaPaths, 1, '?') +table.insert(luaPaths, 2, '?.lua') +table.insert(luaPaths, 3, '/usr/apis/?') +table.insert(luaPaths, 4, '/usr/apis/?.lua') +table.insert(luaPaths, 5, '/sys/apis/?') +table.insert(luaPaths, 6, '/sys/apis/?.lua') + +local DEFAULT_PATH = table.concat(luaPaths, ';') local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'develop-1.8' local DEFAULT_UPATH = GIT_URL .. '/kepler155c/opus/' .. DEFAULT_BRANCH .. '/sys/apis' diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index 64ba8ab..704299f 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -13,19 +13,19 @@ local helpPaths = Util.split(help.path(), '(.-):') table.insert(helpPaths, '/sys/help') -local function addEntry(t, e) +local function addEntry(t, e, n) for _,v in ipairs(t) do if v == e then return true end end - table.insert(t, 1, e) + table.insert(t, n or 1, e) end local function addRequirePath(t, path) - addEntry(t, string.format('/%s/?', path)) - addEntry(t, string.format('/%s/?.lua', path)) - addEntry(t, string.format('/%s/?/init.lua', path)) + addEntry(t, string.format('/%s/?/init.lua', path), 7) + addEntry(t, string.format('/%s/?.lua', path), 7) + addEntry(t, string.format('/%s/?', path), 7) end for name in pairs(Packages:installed()) do From 49849ecfea665a5021d8bd591afbb4dd2ec6f871 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Dec 2018 09:50:02 -0500 Subject: [PATCH 025/231] file associations --- sys/apps/Files.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index c2a108a..ee7d7b7 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -93,9 +93,10 @@ local Browser = UI.Page { grid = UI.ScrollingGrid { x = 2, ex = -6, y = 3, ey = -5, columns = { - { heading = 'Name', key = 'name' }, - { heading = 'Value', key = 'value' }, + { heading = 'Extension', key = 'name' }, + { heading = 'Program', key = 'value' }, }, + autospace = true, sortColumn = 'name', accelerators = { delete = 'remove_entry', @@ -111,14 +112,14 @@ local Browser = UI.Page { manualControls = true, [1] = UI.TextEntry { width = 20, - formLabel = 'Name', formKey = 'name', + formLabel = 'Extension', formKey = 'name', shadowText = 'extension', required = true, - limit = 64, + limit = 20, }, [2] = UI.TextEntry { - width = 20, - formLabel = 'Name', formKey = 'value', + width = 16, + formLabel = 'Program', formKey = 'value', shadowText = 'program', required = true, limit = 64, From 6143671dfb67393cb6d7668e818d71e2cd23a192 Mon Sep 17 00:00:00 2001 From: kepler155c Date: Sun, 30 Dec 2018 13:53:39 -0500 Subject: [PATCH 026/231] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b78a99..3a2d070 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,6 @@ ## Install ``` -pastebin run sj4VMVJj +pastebin run uzghlbnc reboot ``` From da20397b221fcdba45eee3806e5848ecca6bdf5f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Dec 2018 13:54:09 -0500 Subject: [PATCH 027/231] file associations --- sys/apps/Files.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index ee7d7b7..fa4493a 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -115,14 +115,14 @@ local Browser = UI.Page { formLabel = 'Extension', formKey = 'name', shadowText = 'extension', required = true, - limit = 20, + limit = 64, }, [2] = UI.TextEntry { - width = 16, + width = 20, formLabel = 'Program', formKey = 'value', shadowText = 'program', required = true, - limit = 64, + limit = 128, }, add = UI.Button { x = -11, y = 1, From c95c22ff4d17dcfee46024057550d94c63f20477 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 31 Dec 2018 11:35:13 -0500 Subject: [PATCH 028/231] inactivate tabs --- sys/apis/ui.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 03e52b0..972cf08 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -2262,6 +2262,13 @@ function UI.Tabs:selectTab(tab) end end +function UI.Tabs:setActive(tab, active) + local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) + if menuItem then + menuItem.inactive = not active + end +end + function UI.Tabs:enable() self.enabled = true self.tabBar:enable() From 6ef23908ded13038251f5c563c635998d1765be8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 1 Jan 2019 07:29:44 -0500 Subject: [PATCH 029/231] UI page not calling disable on window --- sys/apis/ui.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 972cf08..2dec4bf 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -1152,6 +1152,7 @@ function UI.Page:disable() if self.z then self.canvas.visible = false end + UI.Window.disable(self) end function UI.Page:capture(child) From 0e921edaf54c2408637e3d48ece4ba48d272eb61 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 2 Jan 2019 03:04:24 -0500 Subject: [PATCH 030/231] add util.any --- sys/apis/util.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 4630a6e..2150840 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -332,6 +332,14 @@ function Util.removeByValue(t, e) end end +function Util.any(t, fn) + for _,v in pairs(t) do + if fn(v) then + return true + end + end +end + function Util.every(t, fn) for _,v in pairs(t) do if not fn(v) then From 02b12d87dcc495634b49a69e4df52086dc9907cb Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 2 Jan 2019 10:33:47 -0500 Subject: [PATCH 031/231] multi-device input support in UI --- sys/apis/ui.lua | 201 +++++++++++++++++++++++------------------------- 1 file changed, 98 insertions(+), 103 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 2dec4bf..068b7d9 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -45,14 +45,31 @@ end --[[-- Top Level Manager --]]-- local Manager = class() function Manager:init() + self.devices = { } +_G._pp = self local function keyFunction(event, code, held) local ie = Input:translate(event, code, held) - if ie and self.currentPage then - local target = self.currentPage.focused or self.currentPage + local currentPage = self:getActivePage() + if ie and currentPage then + local target = currentPage.focused or currentPage self:inputEvent(target, { type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target }) - self.currentPage:sync() + currentPage:sync() + end + end + + local function resize(_, side) + local dev = self.devices[side or 'terminal'] + if dev and dev.currentPage then + -- the parent doesn't have any children set... + -- that's why we have to resize both the parent and the current page + -- kinda makes sense + dev.currentPage.parent:resize() + + dev.currentPage:resize() + dev.currentPage:draw() + dev.currentPage:sync() end end @@ -60,25 +77,13 @@ function Manager:init() char = keyFunction, key_up = keyFunction, key = keyFunction, - - term_resize = function(_, side) - if self.currentPage then - -- the parent doesn't have any children set... - -- that's why we have to resize both the parent and the current page - -- kinda makes sense - if self.currentPage.parent.device.side == side then - self.currentPage.parent:resize() - - self.currentPage:resize() - self.currentPage:draw() - self.currentPage:sync() - end - end - end, + term_resize = resize, + monitor_resize = resize, mouse_scroll = function(_, direction, x, y) - if self.currentPage then - local event = self.currentPage:pointToChild(x, y) + local currentPage = self:getActivePage() + if currentPage then + local event = currentPage:pointToChild(x, y) local directions = { [ -1 ] = 'up', [ 1 ] = 'down' @@ -87,30 +92,29 @@ function Manager:init() -- let the element convert them to up / down self:inputEvent(event.element, { type = 'key', key = directions[direction] }) - self.currentPage:sync() + currentPage:sync() end end, - -- this should be moved to the device ! monitor_touch = function(_, side, x, y) Input:translate('mouse_click', 1, x, y) local ie = Input:translate('mouse_up', 1, x, y) - if self.currentPage then - if self.currentPage.parent.device.side == side then - self:click(ie.code, 1, x, y) - end + local dev = self.devices[side] + if dev and dev.currentPage then + self:click(dev.currentPage, ie.code, 1, x, y) end end, mouse_click = function(_, button, x, y) Input:translate('mouse_click', button, x, y) - if self.currentPage then - if not self.currentPage.parent.device.side then - local event = self.currentPage:pointToChild(x, y) + local currentPage = self:getActivePage() + if currentPage then + if not currentPage.parent.device.side then + local event = currentPage:pointToChild(x, y) if event.element.focus and not event.element.inactive then - self.currentPage:setFocus(event.element) - self.currentPage:sync() + currentPage:setFocus(event.element) + currentPage:sync() end end end @@ -119,40 +123,43 @@ function Manager:init() mouse_up = function(_, button, x, y) local ie = Input:translate('mouse_up', button, x, y) + local currentPage = self:getActivePage() + if ie.code == 'control-shift-mouse_click' then -- hack - local event = self.currentPage:pointToChild(x, y) + local event = currentPage:pointToChild(x, y) _ENV.multishell.openTab({ path = 'sys/apps/Lua.lua', args = { event.element }, focused = true }) - elseif ie and self.currentPage then + elseif ie and currentPage then --if not self.currentPage.parent.device.side then - self:click(ie.code, button, x, y) + self:click(currentPage, ie.code, button, x, y) --end end end, mouse_drag = function(_, button, x, y) local ie = Input:translate('mouse_drag', button, x, y) - if ie and self.currentPage then - local event = self.currentPage:pointToChild(x, y) + local currentPage = self:getActivePage() + if ie and currentPage then + local event = currentPage:pointToChild(x, y) event.type = ie.code self:inputEvent(event.element, event) - self.currentPage:sync() + currentPage:sync() end end, paste = function(_, text) Input:translate('paste') self:emitEvent({ type = 'paste', text = text }) - self.currentPage:sync() + self:getActivePage():sync() end, } -- use 1 handler to single thread all events Event.on({ - 'char', 'key_up', 'key', 'term_resize', + 'char', 'key_up', 'key', 'term_resize', 'monitor_resize', 'mouse_scroll', 'monitor_touch', 'mouse_click', 'mouse_up', 'mouse_drag', 'paste' }, function(event, ...) @@ -227,8 +234,9 @@ function Manager:loadTheme(filename) end function Manager:emitEvent(event) - if self.currentPage and self.currentPage.focused then - return self.currentPage.focused:emit(event) + local currentPage = self:getActivePage() + if currentPage and currentPage.focused then + return currentPage.focused:emit(event) end end @@ -251,54 +259,27 @@ function Manager:inputEvent(parent, event) end end -function Manager:click(code, button, x, y) - if self.currentPage then +function Manager:click(target, code, button, x, y) + local clickEvent = target:pointToChild(x, y) - local target = self.currentPage - - -- need to add offsets into this check - --[[ - if x < target.x or y < target.y or - x > target.x + target.width - 1 or - y > target.y + target.height - 1 then - target:emit({ type = 'mouse_out' }) - - target = self.currentPage + if code == 'mouse_doubleclick' then + if self.doubleClickElement ~= clickEvent.element then + return end - --]] - - local clickEvent = target:pointToChild(x, y) - - if code == 'mouse_doubleclick' then - if self.doubleClickElement ~= clickEvent.element then - return - end - else - self.doubleClickElement = clickEvent.element - end - - clickEvent.button = button - clickEvent.type = code - clickEvent.key = code - - if clickEvent.element.focus then - self.currentPage:setFocus(clickEvent.element) - end - if not self:inputEvent(clickEvent.element, clickEvent) then - --[[ - if button == 3 then - -- if the double-click was not captured - -- send through a single-click - clickEvent.button = 1 - clickEvent.type = events[1] - clickEvent.key = events[1] - self:inputEvent(clickEvent.element, clickEvent) - end - ]] - end - - self.currentPage:sync() + else + self.doubleClickElement = clickEvent.element end + + clickEvent.button = button + clickEvent.type = code + clickEvent.key = code + + if clickEvent.element.focus then + target:setFocus(clickEvent.element) + end + self:inputEvent(clickEvent.element, clickEvent) + + target:sync() end function Manager:setDefaultDevice(dev) @@ -327,6 +308,17 @@ function Manager:getPage(pageName) return page end +function Manager:getActivePage(page) + if page then + return page.parent.currentPage + end + return self.defaultDevice.currentPage +end + +function Manager:setActivePage(page) + page.parent.currentPage = page +end + function Manager:setPage(pageOrName, ...) local page = pageOrName @@ -334,27 +326,28 @@ function Manager:setPage(pageOrName, ...) page = self.pages[pageOrName] or error('Invalid page: ' .. pageOrName) end - if page == self.currentPage then + local currentPage = self:getActivePage(page) + if page == currentPage then page:draw() else local needSync - if self.currentPage then - if self.currentPage.focused then - self.currentPage.focused.focused = false - self.currentPage.focused:focus() + if currentPage then + if currentPage.focused then + currentPage.focused.focused = false + currentPage.focused:focus() end - self.currentPage:disable() - page.previousPage = self.currentPage + currentPage:disable() + page.previousPage = currentPage else needSync = true end - self.currentPage = page - self.currentPage:clear(page.backgroundColor) + self:setActivePage(page) + page:clear(page.backgroundColor) page:enable(...) page:draw() - if self.currentPage.focused then - self.currentPage.focused.focused = true - self.currentPage.focused:focus() + if page.focused then + page.focused.focused = true + page.focused:focus() end if needSync then page:sync() -- first time a page has been set @@ -363,14 +356,14 @@ function Manager:setPage(pageOrName, ...) end function Manager:getCurrentPage() - return self.currentPage + return self.defaultDevice.currentPage end function Manager:setPreviousPage() - if self.currentPage.previousPage then - local previousPage = self.currentPage.previousPage.previousPage - self:setPage(self.currentPage.previousPage) - self.currentPage.previousPage = previousPage + if self.defaultDevice.currentPage.previousPage then + local previousPage = self.defaultDevice.currentPage.previousPage.previousPage + self:setPage(self.defaultDevice.currentPage.previousPage) + self.defaultDevice.currentPage.previousPage = previousPage end end @@ -941,6 +934,8 @@ function UI.Device:postInit() isColor = self.isColor, }) self.canvas:clear(self.backgroundColor, self.textColor) + + UI.devices[self.device.side or 'terminal'] = self end function UI.Device:resize() From aef22987fa1321883f597f62ca13f61fb450b788 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 2 Jan 2019 23:56:01 -0500 Subject: [PATCH 032/231] stereo sound! --- sys/apis/sound.lua | 7 +++---- sys/apis/ui.lua | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sys/apis/sound.lua b/sys/apis/sound.lua index b4dab46..18dad1c 100644 --- a/sys/apis/sound.lua +++ b/sys/apis/sound.lua @@ -5,10 +5,9 @@ local Sound = { } function Sound.play(sound, vol) - local speaker = peripheral.find('speaker') - if speaker then - speaker.playSound('minecraft:' .. sound, vol or Sound._volume) - end + peripheral.find('speaker', function(_, s) + s.playSound('minecraft:' .. sound, vol or Sound._volume) + end) end function Sound.setVolume(volume) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 068b7d9..dcc0ae8 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -46,7 +46,7 @@ end local Manager = class() function Manager:init() self.devices = { } -_G._pp = self + local function keyFunction(event, code, held) local ie = Input:translate(event, code, held) From 5ae6434d62cb6950127151ed24bde7db24d48491 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 3 Jan 2019 12:54:14 -0500 Subject: [PATCH 033/231] fix ui setTab --- sys/apis/git.lua | 24 ------------------------ sys/apis/ui.lua | 12 +++++++----- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/sys/apis/git.lua b/sys/apis/git.lua index 77c398c..c7a5ccc 100644 --- a/sys/apis/git.lua +++ b/sys/apis/git.lua @@ -1,20 +1,10 @@ local json = require('json') local Util = require('util') --- Limit queries to once per minecraft day --- TODO: will not work if time is stopped - local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1' local FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s' local git = { } -local fs = _G.fs -local os = _G.os - -if not _G.GIT then - _G.GIT = { } -end - function git.list(repository) local t = Util.split(repository, '(.-)/') @@ -27,17 +17,7 @@ function git.list(repository) path = table.concat(t, '/') .. '/' end - local cacheKey = table.concat({ user, repo, branch }, '-') - local fname = fs.combine('.git', cacheKey) - local function getContents() - if fs.exists(fname) then - local contents = Util.readTable(fname) - if contents and contents.data == os.day() then - return contents.data - end - fs.delete(fname) - end local dataUrl = string.format(TREE_URL, user, repo, branch) local contents = Util.download(dataUrl) if contents then @@ -55,10 +35,6 @@ function git.list(repository) error("Invalid repository") end - if not fs.exists(fname) then - Util.writeTable('.git/' .. cacheKey, { day = os.day(), data = data }) - end - local list = { } for _,v in pairs(data.tree) do if v.type == "blob" then diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index dcc0ae8..09ef448 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -2196,13 +2196,15 @@ end function UI.TabBar:eventHandler(event) if event.type == 'tab_select' then - local selected, si = Util.find(self:getFocusables(), 'uid', event.button.uid) - local previous, pi = Util.find(self:getFocusables(), 'selected', true) + local selected, si = Util.find(self.children, 'uid', event.button.uid) + local previous, pi = Util.find(self.children, 'selected', true) if si ~= pi then selected.selected = true - previous.selected = false - self:emit({ type = 'tab_change', current = si, last = pi, tab = selected }) + if previous then + previous.selected = false + self:emit({ type = 'tab_change', current = si, last = pi, tab = selected }) + end end UI.MenuBar.draw(self) end @@ -2252,7 +2254,7 @@ function UI.Tabs:add(children) end function UI.Tabs:selectTab(tab) - local menuItem = Util.find(self.tabBar:getFocusables(), 'tabUid', tab.uid) + local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) if menuItem then self.tabBar:emit({ type = 'tab_select', button = { uid = menuItem.uid } }) end From f5294d4fce5e45de939465a57d7f5b2a9483785e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 5 Jan 2019 10:35:25 -0500 Subject: [PATCH 034/231] better options icon --- sys/apps/Files.lua | 2 +- sys/apps/Network.lua | 2 +- sys/extensions/6.tl3.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index fa4493a..24f8c78 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -60,7 +60,7 @@ local Browser = UI.Page { { text = 'Hidden ^h', event = 'toggle_hidden' }, { text = 'Dir Size ^s', event = 'toggle_dirSize' }, } }, - { text = '\206', + { text = '\187', x = -3, dropdown = { { text = 'Associations', event = 'associate' }, diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 39cb2ce..85f6502 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -45,7 +45,7 @@ local page = UI.Page { } }, { text = 'Help', event = 'help', noCheck = true }, { - text = '\206', + text = '\187', x = -3, dropdown = { { text = 'Show all', event = 'show_all', noCheck = true }, diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 33006b4..fea55e2 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -802,7 +802,7 @@ function turtle.has(item, count) return slot and slot.count >= (count or 1) end local slot = turtle.getSlot(item) - return slot and slot.count > 0 + return slot and slot.count >= (count or 1) end function turtle.getFilledSlots(startSlot) From b761b3429a02c25b8a1256fa26f8e33698f1fa63 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 8 Jan 2019 04:40:58 -0500 Subject: [PATCH 035/231] dont require heading for point.closest --- sys/apis/point.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/apis/point.lua b/sys/apis/point.lua index f36933b..690b446 100644 --- a/sys/apis/point.lua +++ b/sys/apis/point.lua @@ -177,7 +177,12 @@ function Point.closest(reference, pts) local lm, lpt = math.huge for _,pt in pairs(pts) do local distance = Point.turtleDistance(reference, pt) - if distance < lm then + if not reference.heading then + if distance < lm then + lpt = pt + lm = distance + end + elseif distance < lm then local _, _, m = Point.calculateMoves(reference, pt, distance) if m < lm then lpt = pt From 4387264960d8c2d2fe760ddb91607427103b6ac8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 8 Jan 2019 11:38:19 -0500 Subject: [PATCH 036/231] package manager updates --- sys/apps/PackageManager.lua | 40 +++++++++++++++++++++---------------- sys/apps/package.lua | 22 +++++++++++++++----- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index fd05cf0..322f22a 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -1,18 +1,16 @@ -_G.requireInjector(_ENV) - local Ansi = require('ansi') local Packages = require('packages') local UI = require('ui') +local Util = require('util') local colors = _G.colors -local shell = _ENV.shell local term = _G.term UI:configure('PackageManager', ...) local page = UI.Page { grid = UI.ScrollingGrid { - y = 2, ey = 7, x = 2, ex = -6, + y = 2, ey = 7, x = 2, ex = -12, values = { }, columns = { { heading = 'Package', key = 'name' }, @@ -22,14 +20,14 @@ local page = UI.Page { help = 'Select a package', }, add = UI.Button { - x = -4, y = 4, - text = '+', + x = -10, y = 4, + text = 'Install', event = 'action', help = 'Install or update', }, remove = UI.Button { - x = -4, y = 6, - text = '-', + x = -10, y = 6, + text = 'Remove ', event = 'action', operation = 'uninstall', operationText = 'Remove', @@ -46,8 +44,8 @@ local page = UI.Page { event = 'hide-action', }, button = UI.Button { - ex = -4, y = 4, width = 7, - text = 'Begin', event = 'begin', + x = -10, y = 4, + text = ' Begin ', event = 'begin', }, output = UI.Embedded { y = 6, ey = -2, x = 2, ex = -2, @@ -75,16 +73,15 @@ function page:run(operation, name) local oterm = term.redirect(self.action.output.win) self.action.output:clear() local cmd = string.format('package %s %s', operation, name) - --for _ = 1, 3 do - -- print(cmd .. '\n') - -- os.sleep(1) - --end term.setCursorPos(1, 1) term.clear() term.setTextColor(colors.yellow) print(cmd .. '\n') term.setTextColor(colors.white) - shell.run(cmd) + local s, m = Util.run(_ENV, '/sys/apps/package.lua', operation, name) + if not s and m then + _G.printError(m) + end term.redirect(oterm) self.action.output:draw() end @@ -92,6 +89,10 @@ end function page:updateSelection(selected) self.add.operation = selected.installed and 'update' or 'install' self.add.operationText = selected.installed and 'Update' or 'Install' + self.add.text = selected.installed and 'Update' or 'Install' + self.remove.inactive = not selected.installed + self.add:draw() + self.remove:draw() end function page:eventHandler(event) @@ -113,7 +114,7 @@ function page:eventHandler(event) self.operation = event.button.operation self.action.button.text = event.button.operationText self.action.titleBar.title = selected.manifest.title - self.action.button.text = 'Begin' + self.action.button.text = ' Begin ' self.action.button.event = 'begin' self.action:show() end @@ -127,7 +128,7 @@ function page:eventHandler(event) selected.installed = Packages:isInstalled(selected.name) self:updateSelection(selected) - self.action.button.text = 'Done' + self.action.button.text = ' Done ' self.action.button.event = 'hide-action' self.action.button:draw() @@ -153,6 +154,11 @@ for k in pairs(Packages:list()) do }) end page.grid:update() +page.grid:emit({ + type = 'grid_focus_row', + selected = page.grid:getSelected(), + element = page.grid, +}) UI:setPage(page) UI:pullEvents() diff --git a/sys/apps/package.lua b/sys/apps/package.lua index 1f0d212..b377134 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Git = require('git') local Packages = require('packages') local Util = require('util') @@ -36,8 +34,21 @@ local function progress(max) end end -local function install(name) +local function install(name, isUpdate) local manifest = Packages:getManifest(name) or error('Invalid package') + + if manifest.required then + for _, v in pairs(manifest.required) do + if isUpdate or not Packages:isInstalled(v) then + install(v, isUpdate) + end + end + end + + print(string.format('%s: %s', + isUpdate and 'Updating' or 'Installing', + name)) + local packageDir = fs.combine('packages', name) local method = args[2] or 'local' if method == 'remote' then @@ -69,7 +80,8 @@ if action == 'install' then error('Package is already installed') end install(name) - print('installation complete') + print('installation complete\n') + _G.printError('Reboot is required') return end @@ -78,7 +90,7 @@ if action == 'update' then if not Packages:isInstalled(name) then error('Package is not installed') end - install(name) + install(name, true) print('update complete') return end From 4977ea94d755de1067a89b33332c87977dffa313 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 9 Jan 2019 06:59:19 -0500 Subject: [PATCH 037/231] package manager --- sys/apis/packages.lua | 11 ++++++ sys/apps/PackageManager.lua | 68 ++++++++++++++++++++++------------- sys/extensions/4.user.lua | 13 ------- sys/extensions/6.packages.lua | 7 ++-- 4 files changed, 59 insertions(+), 40 deletions(-) diff --git a/sys/apis/packages.lua b/sys/apis/packages.lua index ae7375a..7f39255 100644 --- a/sys/apis/packages.lua +++ b/sys/apis/packages.lua @@ -33,6 +33,17 @@ function Packages:isInstalled(package) return self:installed()[package] end +function Packages:downloadList() + local packages = { + [ 'develop-1.8' ] = 'https://pastebin.com/raw/WhEiNGZE', + [ 'master-1.8' ] = 'https://pastebin.com/raw/pexZpAxt', + } + + if packages[_G.OPUS_BRANCH] then + Util.download(packages[_G.OPUS_BRANCH], 'usr/config/packages') + end +end + function Packages:getManifest(package) local fname = 'packages/' .. package .. '/.package' if fs.exists(fname) then diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index 322f22a..29f3db4 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -10,7 +10,7 @@ UI:configure('PackageManager', ...) local page = UI.Page { grid = UI.ScrollingGrid { - y = 2, ey = 7, x = 2, ex = -12, + x = 2, ex = -12, y = 2, ey = 7, values = { }, columns = { { heading = 'Package', key = 'name' }, @@ -34,10 +34,15 @@ local page = UI.Page { help = 'Remove', }, description = UI.TextArea { - x = 2, y = 9, ey = -2, + x = 2, y = 9, ey = -4, --backgroundColor = colors.white, }, - statusBar = UI.StatusBar { }, + load = UI.Button { + x = 2, y = -3, + text = 'Update package list', + event = 'reload', + help = 'Download the latest package list', + }, action = UI.SlideOut { backgroundColor = colors.cyan, titleBar = UI.TitleBar { @@ -54,8 +59,39 @@ local page = UI.Page { backgroundColor = colors.cyan, }, }, + statusBar = UI.StatusBar { }, } +function page:loadPackages() + self.grid.values = { } + self.statusBar:setStatus('Downloading...') + self:sync() + + for k in pairs(Packages:list()) do + local manifest = Packages:getManifest(k) + if not manifest then + manifest = { + invalid = true, + description = 'Unable to download manifest', + title = '', + } + end + table.insert(self.grid.values, { + installed = not not Packages:isInstalled(k), + name = k, + manifest = manifest, + }) + end + self.grid:update() + self.grid:setIndex(1) + self.grid:emit({ + type = 'grid_focus_row', + selected = self.grid:getSelected(), + element = self.grid, + }) + self.statusBar:setStatus('Updated packages') +end + function page.grid:getRowTextColor(row, selected) if row.installed then return colors.yellow @@ -108,6 +144,10 @@ function page:eventHandler(event) self.description:draw() self:updateSelection(event.selected) + elseif event.type == 'reload' then + Packages:downloadList() + self:loadPackages() + elseif event.type == 'action' then local selected = self.grid:getSelected() if selected then @@ -138,27 +178,7 @@ function page:eventHandler(event) UI.Page.eventHandler(self, event) end -for k in pairs(Packages:list()) do - local manifest = Packages:getManifest(k) - if not manifest then - manifest = { - invalid = true, - description = 'Unable to download manifest', - title = '', - } - end - table.insert(page.grid.values, { - installed = not not Packages:isInstalled(k), - name = k, - manifest = manifest, - }) -end -page.grid:update() -page.grid:emit({ - type = 'grid_focus_row', - selected = page.grid:getSelected(), - element = page.grid, -}) +page:loadPackages() UI:setPage(page) UI:pullEvents() diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index c6d0d9e..89a7000 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Util = require('util') local fs = _G.fs @@ -29,17 +27,6 @@ if not fs.exists('usr/config/shell') then }) end -if not fs.exists('usr/config/packages') then - local packages = { - [ 'develop-1.8' ] = 'https://pastebin.com/raw/WhEiNGZE', - [ 'master-1.8' ] = 'https://pastebin.com/raw/pexZpAxt', - } - - if packages[_G.OPUS_BRANCH] then - Util.download(packages[_G.OPUS_BRANCH], 'usr/config/packages') - end -end - local config = Util.readTable('usr/config/shell') if config.aliases then for k in pairs(shell.aliases()) do diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index 704299f..c7203b3 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Packages = require('packages') local Util = require('util') @@ -7,6 +5,10 @@ local fs = _G.fs local help = _G.help local shell = _ENV.shell +if not fs.exists('usr/config/packages') then + Packages:downloadList() +end + local appPaths = Util.split(shell.path(), '(.-):') local luaPaths = Util.split(_G.LUA_PATH, '(.-);') local helpPaths = Util.split(help.path(), '(.-):') @@ -50,6 +52,5 @@ for name in pairs(Packages:installed()) do end help.setPath(table.concat(helpPaths, ':')) - shell.setPath(table.concat(appPaths, ':')) _G.LUA_PATH = table.concat(luaPaths, ';') From f0a65d87ce7008184571e8beb2bc72a7c5ab56d6 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 9 Jan 2019 08:50:42 -0500 Subject: [PATCH 038/231] kiosk mode --- startup | 1 + sys/apis/ui.lua | 4 ++-- sys/boot/kiosk.boot | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 sys/boot/kiosk.boot diff --git a/startup b/startup index 917ddab..a6631fb 100644 --- a/startup +++ b/startup @@ -7,6 +7,7 @@ local bootOptions = { { prompt = os.version() }, { prompt = 'Opus' , args = { '/sys/boot/opus.boot' } }, { prompt = 'Opus Shell' , args = { '/sys/boot/opus.boot', 'sys/apps/shell' } }, + { prompt = 'Opus Kiosk' , args = { '/sys/boot/kiosk.boot' } }, } local bootOption = 2 if settings then diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 09ef448..13b7187 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -97,10 +97,10 @@ function Manager:init() end, monitor_touch = function(_, side, x, y) - Input:translate('mouse_click', 1, x, y) - local ie = Input:translate('mouse_up', 1, x, y) local dev = self.devices[side] if dev and dev.currentPage then + Input:translate('mouse_click', 1, x, y) + local ie = Input:translate('mouse_up', 1, x, y) self:click(dev.currentPage, ie.code, 1, x, y) end end, diff --git a/sys/boot/kiosk.boot b/sys/boot/kiosk.boot new file mode 100644 index 0000000..ad4da1a --- /dev/null +++ b/sys/boot/kiosk.boot @@ -0,0 +1,34 @@ +local os = _G.os +local parallel = _G.parallel +local peripheral = _G.peripheral +local settings = _G.settings +local term = _G.term + + +local mon = peripheral.find('monitor') +if mon then + term.redirect(mon) + if not settings.get('opus.kiosk.textscale') then + settings.set('opus.kiosk.textscale', .5) + end + mon.setTextScale(settings.get('opus.kiosk.textscale') or .5) + + parallel.waitForAny( + function() + os.run(_ENV, '/sys/boot/opus.boot') + end, + + function() + while true do + local event, _, x, y = os.pullEventRaw('monitor_touch') + + if event == 'monitor_touch' then + os.queueEvent('mouse_click', 1, x, y) + os.queueEvent('mouse_up', 1, x, y) + end + end + end + ) +else + os.run(_ENV, '/sys/boot/opus.boot') +end From 3cc368f33a841d554c34f605230961499578e7f8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 10 Jan 2019 02:22:06 -0500 Subject: [PATCH 039/231] kiosk mode --- sys/apps/Overview.lua | 3 ++- sys/boot/kiosk.boot | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 46d1244..73fccd8 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -194,7 +194,8 @@ UI.Icon.defaults = { } function UI.Icon:eventHandler(event) if event.type == 'mouse_click' then - self:setFocus(self.button) + --self:setFocus(self.button) + self:emit({ type = self.button.event, button = self.button }) return true elseif event.type == 'mouse_doubleclick' then self:emit({ type = self.button.event, button = self.button }) diff --git a/sys/boot/kiosk.boot b/sys/boot/kiosk.boot index ad4da1a..cc79101 100644 --- a/sys/boot/kiosk.boot +++ b/sys/boot/kiosk.boot @@ -1,17 +1,16 @@ local os = _G.os local parallel = _G.parallel local peripheral = _G.peripheral -local settings = _G.settings +local settings = _G.settings local term = _G.term - local mon = peripheral.find('monitor') if mon then term.redirect(mon) - if not settings.get('opus.kiosk.textscale') then - settings.set('opus.kiosk.textscale', .5) + if not settings.get('kiosk.textscale') then + settings.set('kiosk.textscale', .5) end - mon.setTextScale(settings.get('opus.kiosk.textscale') or .5) + mon.setTextScale(settings.get('kiosk.textscale') or .5) parallel.waitForAny( function() From 7c26258f881df167f1fcf902eb9a48f53a6ab246 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 10 Jan 2019 02:27:02 -0500 Subject: [PATCH 040/231] kiosk mode --- sys/apps/Overview.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 73fccd8..be73986 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -194,7 +194,7 @@ UI.Icon.defaults = { } function UI.Icon:eventHandler(event) if event.type == 'mouse_click' then - --self:setFocus(self.button) + self:setFocus(self.button) self:emit({ type = self.button.event, button = self.button }) return true elseif event.type == 'mouse_doubleclick' then From 712ffdb97c43fcda11af0ce2379b78e4349222fd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 11 Jan 2019 10:01:06 -0500 Subject: [PATCH 041/231] package manager ui update --- sys/apps/PackageManager.lua | 13 +++++++------ sys/boot/kiosk.boot | 5 +---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index 29f3db4..f332f1a 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -10,7 +10,7 @@ UI:configure('PackageManager', ...) local page = UI.Page { grid = UI.ScrollingGrid { - x = 2, ex = -12, y = 2, ey = 7, + x = 2, ex = 14, y = 2, ey = -5, values = { }, columns = { { heading = 'Package', key = 'name' }, @@ -20,13 +20,13 @@ local page = UI.Page { help = 'Select a package', }, add = UI.Button { - x = -10, y = 4, + x = 2, y = -3, text = 'Install', event = 'action', help = 'Install or update', }, remove = UI.Button { - x = -10, y = 6, + x = 12, y = -3, text = 'Remove ', event = 'action', operation = 'uninstall', @@ -34,12 +34,13 @@ local page = UI.Page { help = 'Remove', }, description = UI.TextArea { - x = 2, y = 9, ey = -4, + x = 16, y = 3, ey = -5, + marginRight = 0, marginLeft = 0, --backgroundColor = colors.white, }, load = UI.Button { - x = 2, y = -3, - text = 'Update package list', + x = 22, y = -3, + text = 'Update packages', event = 'reload', help = 'Download the latest package list', }, diff --git a/sys/boot/kiosk.boot b/sys/boot/kiosk.boot index cc79101..26b6602 100644 --- a/sys/boot/kiosk.boot +++ b/sys/boot/kiosk.boot @@ -7,10 +7,7 @@ local term = _G.term local mon = peripheral.find('monitor') if mon then term.redirect(mon) - if not settings.get('kiosk.textscale') then - settings.set('kiosk.textscale', .5) - end - mon.setTextScale(settings.get('kiosk.textscale') or .5) + mon.setTextScale(tonumber(settings.get('kiosk.textscale')) or 1) parallel.waitForAny( function() From 25031bfdc2cd1aafe4d77b378ef10120b3772338 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 11 Jan 2019 16:04:31 -0500 Subject: [PATCH 042/231] ui grid header sizing --- sys/apis/ui.lua | 19 ++++++++++++------- sys/apps/PackageManager.lua | 4 ++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 13b7187..2d303c1 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -1256,6 +1256,7 @@ UI.Grid.defaults = { index = 1, inverseSort = false, disableHeader = false, + headerHeight = 1, marginRight = 0, textColor = colors.white, textSelectedColor = colors.white, @@ -1300,7 +1301,7 @@ function UI.Grid:setParent() if self.disableHeader then self.pageSize = self.height else - self.pageSize = self.height - 1 + self.pageSize = self.height - self.headerHeight end end end @@ -1311,7 +1312,7 @@ function UI.Grid:resize() if self.disableHeader then self.pageSize = self.height else - self.pageSize = self.height - 1 + self.pageSize = self.height - self.headerHeight end self:adjustWidth() end @@ -1506,7 +1507,11 @@ function UI.Grid:drawHeadings() x = x + col.cw + 1 ]] end - self:write(1, 1, sb:get(), self.headerBackgroundColor, self.headerTextColor) + local y = math.ceil(self.headerHeight / 2) + if self.headerHeight > 1 then + self:clear(self.headerBackgroundColor) + end + self:write(1, y, sb:get(), self.headerBackgroundColor, self.headerTextColor) end function UI.Grid:sortCompare(a, b) @@ -1524,7 +1529,7 @@ function UI.Grid:drawRows() local sb = UI.StringBuffer(self.width) if not self.disableHeader then - y = y + 1 + y = y + self.headerHeight end local lastRow = math.min(startRow + self.pageSize - 1, #self.sorted) @@ -1638,7 +1643,7 @@ function UI.Grid:eventHandler(event) event.type == 'mouse_rightclick' or event.type == 'mouse_doubleclick' then if not self.disableHeader then - if event.y == 1 then + if event.y <= self.headerHeight then local col = 2 for _,c in ipairs(self.columns) do if event.x < col + c.cw then @@ -1657,7 +1662,7 @@ function UI.Grid:eventHandler(event) end local row = self:getStartRow() + event.y - 1 if not self.disableHeader then - row = row - 1 + row = row - self.headerHeight end if row > 0 and row <= Util.size(self.values) then self:setIndex(row) @@ -1719,7 +1724,7 @@ end function UI.ScrollingGrid:getViewArea() local y = 1 if not self.disableHeader then - y = 2 + y = y + self.headerHeight end return { static = true, -- the container doesn't scroll diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index f332f1a..a52964f 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -50,11 +50,11 @@ local page = UI.Page { event = 'hide-action', }, button = UI.Button { - x = -10, y = 4, + x = -10, y = 3, text = ' Begin ', event = 'begin', }, output = UI.Embedded { - y = 6, ey = -2, x = 2, ex = -2, + y = 5, ey = -2, x = 2, ex = -2, }, statusBar = UI.StatusBar { backgroundColor = colors.cyan, From cb5f690cf472b90bf7df4443410e1e89ef8c5446 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 12 Jan 2019 10:17:56 -0500 Subject: [PATCH 043/231] add git api key support --- sys/apis/git.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/apis/git.lua b/sys/apis/git.lua index c7a5ccc..058f202 100644 --- a/sys/apis/git.lua +++ b/sys/apis/git.lua @@ -5,6 +5,10 @@ local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1' local FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s' local git = { } +if _G._GIT_API_KEY then + TREE_URL = TREE_URL .. '&access_token=' .. _G._GIT_API_KEY +end + function git.list(repository) local t = Util.split(repository, '(.-)/') From 9edb4e7d5b7f58f7604619361028c5c702f9431e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 12 Jan 2019 19:51:56 -0500 Subject: [PATCH 044/231] fix package preload (for cloud-catcher) --- sys/apis/injector.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index fa11bb1..d7ddfec 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -82,8 +82,13 @@ end -- Add require and package to the environment return function(env) - local function standardSearcher(modname) + -- Should this be 2 diff searchers ? if yes, installer would need an update + if env.package.preload[modname] then + return function() + return env.package.preload[modname](modname, env) + end + end if env.package.loaded[modname] then return function() return env.package.loaded[modname] @@ -170,6 +175,7 @@ return function(env) path = env.LUA_PATH or _G.LUA_PATH or DEFAULT_PATH, upath = env.LUA_UPATH or _G.LUA_UPATH or DEFAULT_UPATH, config = '/\n:\n?\n!\n-', + preload = { }, loaded = { coroutine = coroutine, io = io, From eabfde64e92544e9d8fc32bec3262cade9378824 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 13 Jan 2019 13:24:37 -0500 Subject: [PATCH 045/231] safe digging --- sys/apps/Files.lua | 4 ++++ sys/extensions/6.tl3.lua | 36 +++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 24f8c78..e40f538 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -135,6 +135,7 @@ local Browser = UI.Page { }, accelerators = { q = 'quit', + c = 'cedit', e = 'edit', s = 'shell', r = 'refresh', @@ -341,6 +342,9 @@ function Browser:eventHandler(event) elseif event.type == 'edit' and file then self:run('edit', file.name) + elseif event.type == 'cedit' and file then + self:run('cedit', file.name) + elseif event.type == 'shell' then self:run('sys/apps/shell') diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index fea55e2..dd8f522 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -71,10 +71,32 @@ end turtle.reset() +local function _dig(name, inspect, dig) + if name then + local s, b = inspect() + if not s or b.name ~= name then + return false + end + end + return dig() +end + +function turtle.dig(s) + return _dig(s, turtle.inspect, turtle.native.dig) +end + +function turtle.digUp(s) + return _dig(s, turtle.inspectUp, turtle.native.digUp) +end + +function turtle.digDown(s) + return _dig(s, turtle.inspectDown, turtle.native.digDown) +end + local actions = { up = { detect = turtle.native.detectUp, - dig = turtle.native.digUp, + dig = turtle.digUp, move = turtle.native.up, attack = turtle.native.attackUp, place = turtle.native.placeUp, @@ -86,7 +108,7 @@ local actions = { }, down = { detect = turtle.native.detectDown, - dig = turtle.native.digDown, + dig = turtle.digDown, move = turtle.native.down, attack = turtle.native.attackDown, place = turtle.native.placeDown, @@ -98,7 +120,7 @@ local actions = { }, forward = { detect = turtle.native.detect, - dig = turtle.native.dig, + dig = turtle.dig, move = turtle.native.forward, attack = turtle.native.attack, place = turtle.native.place, @@ -1164,10 +1186,10 @@ function turtle.detectDownAt(pt) return _actionDownAt(actionsAt.detect, function turtle.detectForwardAt(pt) return _actionForwardAt(actionsAt.detect, pt) end function turtle.detectUpAt(pt) return _actionUpAt(actionsAt.detect, pt) end -function turtle.digAt(pt) return _actionAt(actionsAt.dig, pt) end -function turtle.digDownAt(pt) return _actionDownAt(actionsAt.dig, pt) end -function turtle.digForwardAt(pt) return _actionForwardAt(actionsAt.dig, pt) end -function turtle.digUpAt(pt) return _actionUpAt(actionsAt.dig, pt) end +function turtle.digAt(pt, ...) return _actionAt(actionsAt.dig, pt, ...) end +function turtle.digDownAt(pt, ...) return _actionDownAt(actionsAt.dig, pt, ...) end +function turtle.digForwardAt(pt, ...) return _actionForwardAt(actionsAt.dig, pt, ...) end +function turtle.digUpAt(pt, ...) return _actionUpAt(actionsAt.dig, pt, ...) end function turtle.attackAt(pt) return _actionAt(actionsAt.attack, pt) end function turtle.attackDownAt(pt) return _actionDownAt(actionsAt.attack, pt) end From 644fd0352f36bce7eef12c98a478f9e5897dcfd4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 17 Jan 2019 13:31:05 -0500 Subject: [PATCH 046/231] rework turtle policies --- sys/autorun/gps.lua | 4 +- sys/etc/app.db | 5 + sys/extensions/6.tl3.lua | 203 ++++++++++++++++++++------------------- 3 files changed, 111 insertions(+), 101 deletions(-) diff --git a/sys/autorun/gps.lua b/sys/autorun/gps.lua index 8a51fea..856ebad 100644 --- a/sys/autorun/gps.lua +++ b/sys/autorun/gps.lua @@ -19,7 +19,7 @@ if turtle and modem then s = turtle.enableGPS(2) end if not s and config.destructive then - turtle.setPolicy('turtleSafe') + turtle.set({ attackPolicy = 'attack', digPolicy = 'turtleSafe' }) s = turtle.enableGPS(2) end @@ -28,7 +28,7 @@ if turtle and modem then end if config.destructive then - turtle.setPolicy('turtleSafe') + turtle.set({ attackPolicy = 'attack', digPolicy = 'turtleSafe' }) end if not turtle.pathfind(config.home) then diff --git a/sys/etc/app.db b/sys/etc/app.db index 643db6a..f36d4f9 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -103,6 +103,11 @@ \030 \031f\030f\0310\136\140\140\030 ", run = "https://gist.github.com/LDDestroier/c7528d95bc0103545c2a/raw", }, + [ "785af2a4ad3c4ee912623c6e0b6d4299ea305bf6" ] = { + title = "Pipes", + category = "Games", + run = "https://pastebin.com/raw/skcs9x1s", + }, [ "53a5d150062b1e03206b9e15854b81060e3c7552" ] = { title = "Minesweeper", category = "Games", diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index dd8f522..58ca25d 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -2,8 +2,6 @@ if not _G.turtle then return end -_G.requireInjector(_ENV) - local Pathing = require('turtle.pathfind') local GPS = require('gps') local Point = require('point') @@ -69,8 +67,6 @@ function turtle.reset() return true end -turtle.reset() - local function _dig(name, inspect, dig) if name then local s, b = inspect() @@ -158,6 +154,24 @@ if type(turtle.getFuelLevel()) ~= 'number' then end end +-- [[ Policies ]] -- +turtle.policies = { } + +function turtle.addPolicy(name, policy) + turtle.policies[name] = policy +end + +function turtle.getPolicy(policy) + if type(policy) == 'function' then + return policy + end + local p = turtle.policies[policy] + if not p then + error('Invalid policy: ' .. tostring(policy)) + end + return p +end + -- [[ Basic turtle actions ]] -- local function inventoryAction(fn, name, qty) local slots = turtle.getFilledSlots() @@ -191,18 +205,15 @@ local function _attack(action) return false end -turtle.attackPolicies = { - none = noop, - - attack = function(action) - return _attack(action) - end, -} - function turtle.attack() return _attack(actions.forward) end function turtle.attackUp() return _attack(actions.up) end function turtle.attackDown() return _attack(actions.down) end +turtle.addPolicy('attackNone', noop) +turtle.addPolicy('attack', function(action) + return _attack(action) +end) + function turtle.setAttackPolicy(policy) state.attackPolicy = policy end -- [[ Place ]] -- @@ -240,6 +251,7 @@ function turtle.place(slot) return _place(actions.forward, slot) end function turtle.placeUp(slot) return _place(actions.up, slot) end function turtle.placeDown(slot) return _place(actions.down, slot) end +-- [[ Drop ]] -- local function _drop(action, qtyOrName, qty) if not qtyOrName or type(qtyOrName) == 'number' then return action.drop(qtyOrName or 64) @@ -251,6 +263,64 @@ function turtle.drop(count, slot) return _drop(actions.forward, count, slot) function turtle.dropUp(count, slot) return _drop(actions.up, count, slot) end function turtle.dropDown(count, slot) return _drop(actions.down, count, slot) end +-- [[ Dig ]] -- +turtle.addPolicy('digNone', noop) + +turtle.addPolicy('dig', function(action) + return action.dig() +end) + +turtle.addPolicy('turtleSafe', function(action) + if action.side == 'back' then + return false + end + if not turtle.isTurtleAtSide(action.side) then + return action.dig() + end + return Util.tryTimes(6, function() + os.sleep(.25) + if not action.detect() then + return true + end + end) +end) + +turtle.addPolicy('digAndDrop', function(action) + if action.detect() then + local slots = turtle.getInventory() + if action.dig() then + turtle.reconcileInventory(slots) + return true + end + end + return false +end) + +function turtle.setDigPolicy(policy) state.digPolicy = policy end + +-- [[ Move ]] -- +turtle.addPolicy('moveNone', noop) +turtle.addPolicy('moveDefault', _defaultMove) +turtle.addPolicy('moveAssured', function(action) + if not _defaultMove(action) then + if action.side == 'back' then + return false + end + local oldStatus = state.status + print('assured move: stuck') + state.status = 'stuck' + repeat + os.sleep(1) + until _defaultMove(action) + state.status = oldStatus + end + return true +end) + +function turtle.setMoveCallback(cb) state.moveCallback = cb end +function turtle.clearMoveCallback() state.moveCallback = noop end +function turtle.getMoveCallback() return state.moveCallback end + function turtle.refuel(qtyOrName, qty) if not qtyOrName or type(qtyOrName) == 'number' then return turtle.native.refuel(qtyOrName or 64) @@ -263,104 +333,36 @@ function turtle.isTurtleAtSide(side) return sideType and sideType == 'turtle' end -turtle.digPolicies = { - none = noop, +function turtle.set(args) + for k,v in pairs(args) do - dig = function(action) - return action.dig() - end, + if k == 'attackPolicy' then + turtle.setAttackPolicy(turtle.getPolicy(v)) - turtleSafe = function(action) - if action.side == 'back' then - return false - end - if not turtle.isTurtleAtSide(action.side) then - return action.dig() - end - return Util.tryTimes(6, function() --- if not turtle.isTurtleAtSide(action.side) then --- return true --action.dig() --- end - os.sleep(.25) - if not action.detect() then - return true - end - end) - end, + elseif k == 'digPolicy' then + turtle.setDigPolicy(turtle.getPolicy(v)) - digAndDrop = function(action) - if action.detect() then - local slots = turtle.getInventory() - if action.dig() then - turtle.reconcileInventory(slots) - return true - end - end - return false - end -} + elseif k == 'movePolicy' then + turtle.setMovePolicy(turtle.getPolicy(v)) -turtle.movePolicies = { - none = noop, - default = _defaultMove, - assured = function(action) - if not _defaultMove(action) then - if action.side == 'back' then - return false - end - local oldStatus = state.status - print('assured move: stuck') - state.status = 'stuck' - repeat - os.sleep(1) - until _defaultMove(action) - state.status = oldStatus - end - return true - end, -} + elseif k == 'movementStrategy' then + turtle.setMovementStrategy(v) -turtle.policies = { - none = { dig = turtle.digPolicies.none, attack = turtle.attackPolicies.none }, - digOnly = { dig = turtle.digPolicies.dig, attack = turtle.attackPolicies.none }, - attackOnly = { dig = turtle.digPolicies.none, attack = turtle.attackPolicies.attack }, - digAttack = { dig = turtle.digPolicies.dig, attack = turtle.attackPolicies.attack }, - turtleSafe = { dig = turtle.digPolicies.turtleSafe, attack = turtle.attackPolicies.attack }, + elseif k == 'pathingBox' then + turtle.setPathingBox(v) - attack = { attack = turtle.attackPolicies.attack }, + elseif k == 'point' then + turtle.setPoint(v) - defaultMove = { move = turtle.movePolicies.default }, - assuredMove = { move = turtle.movePolicies.assured }, -} + elseif k == 'moveCallback' then + turtle.setMoveCallback(v) -function turtle.setPolicy(...) - local args = { ... } - for _, policy in pairs(args) do - if type(policy) == 'string' then - policy = turtle.policies[policy] - end - if not policy then - error('Invalid policy') - -- return false, 'Invalid policy' - end - if policy.dig then - state.digPolicy = policy.dig - end - if policy.attack then - state.attackPolicy = policy.attack - end - if policy.move then - state.movePolicy = policy.move + else + error('Invalid turle.set: ' .. tostring(k)) end end - return true end -function turtle.setDigPolicy(policy) state.digPolicy = policy end -function turtle.setMoveCallback(cb) state.moveCallback = cb end -function turtle.clearMoveCallback() state.moveCallback = noop end -function turtle.getMoveCallback() return state.moveCallback end - -- [[ Heading ]] -- function turtle.getHeading() return turtle.point.heading @@ -732,7 +734,7 @@ function turtle.gotoY(dy) return true end --- [[ Slot management ]] -- +-- [[ Inventory ]] -- function turtle.getSlot(indexOrId, slots) if type(indexOrId) == 'string' then slots = slots or turtle.getInventory() @@ -936,6 +938,7 @@ function turtle.getItemCount(idOrName) return count end +-- [[ Equipment ]] -- function turtle.equip(side, item) if item then if not turtle.select(item) then @@ -1235,3 +1238,5 @@ function turtle.addFeatures(...) require('turtle.' .. feature) end end + +turtle.reset() From 2fd2b552fcb36d0bf56b9086eb1894a9e290882c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 17 Jan 2019 23:33:19 -0500 Subject: [PATCH 047/231] cleanup + app changes --- sys/apis/packages.lua | 13 +++------ sys/apps/Overview.lua | 12 +++++--- sys/etc/app.db | 5 ---- sys/extensions/6.tl3.lua | 60 +++++++++++++++++++++------------------- 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/sys/apis/packages.lua b/sys/apis/packages.lua index 7f39255..ffbc803 100644 --- a/sys/apis/packages.lua +++ b/sys/apis/packages.lua @@ -8,25 +8,20 @@ local PACKAGE_DIR = 'packages' local Packages = { } function Packages:installed() - self.cache = { } + local list = { } if fs.exists(PACKAGE_DIR) then for _, dir in pairs(fs.list(PACKAGE_DIR)) do local path = fs.combine(fs.combine(PACKAGE_DIR, dir), '.package') - self.cache[dir] = Util.readTable(path) + list[dir] = Util.readTable(path) end end - return self.cache + return list end function Packages:list() - if self.packageList then - return self.packageList - end - self.packageList = Util.readTable('usr/config/packages') or { } - - return self.packageList + return Util.readTable('usr/config/packages') or { } end function Packages:isInstalled(package) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index be73986..309c2c1 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -195,7 +195,7 @@ UI.Icon.defaults = { function UI.Icon:eventHandler(event) if event.type == 'mouse_click' then self:setFocus(self.button) - self:emit({ type = self.button.event, button = self.button }) + --self:emit({ type = self.button.event, button = self.button }) return true elseif event.type == 'mouse_doubleclick' then self:emit({ type = self.button.event, button = self.button }) @@ -403,9 +403,13 @@ function page:eventHandler(event) elseif event.type == 'delete' then local focused = page:getFocused() if focused.app then - focused.app.disabled = true - local filename = focused.app.filename or fs.combine(REGISTRY_DIR, focused.app.key) - Util.writeTable(filename, focused.app) + if focused.app.filename then + fs.delete(focused.app.filename) + else + focused.app.disabled = true + local filename = focused.app.filename or fs.combine(REGISTRY_DIR, focused.app.key) + Util.writeTable(filename, focused.app) + end loadApplications() page:refresh() page:draw() diff --git a/sys/etc/app.db b/sys/etc/app.db index f36d4f9..643db6a 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -103,11 +103,6 @@ \030 \031f\030f\0310\136\140\140\030 ", run = "https://gist.github.com/LDDestroier/c7528d95bc0103545c2a/raw", }, - [ "785af2a4ad3c4ee912623c6e0b6d4299ea305bf6" ] = { - title = "Pipes", - category = "Games", - run = "https://pastebin.com/raw/skcs9x1s", - }, [ "53a5d150062b1e03206b9e15854b81060e3c7552" ] = { title = "Minesweeper", category = "Games", diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 58ca25d..7660732 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -19,7 +19,6 @@ local state = { } turtle.pathfind = Pathing.pathfind turtle.point = { x = 0, y = 0, z = 0, heading = 0 } -function turtle.getPoint() return turtle.point end function turtle.getState() return state end function turtle.isAborted() return state.abort end function turtle.getStatus() return state.status end @@ -34,6 +33,7 @@ local function _defaultMove(action) return true end +function turtle.getPoint() return turtle.point end function turtle.setPoint(pt, isGPS) turtle.point.x = pt.x turtle.point.y = pt.y @@ -77,6 +77,8 @@ local function _dig(name, inspect, dig) return dig() end +-- override dig +-- optionally check that the block is a certain type function turtle.dig(s) return _dig(s, turtle.inspect, turtle.native.dig) end @@ -147,11 +149,9 @@ function turtle.getHeadingInfo(heading) return headings[heading] end --- hackish way to support unlimited fuel -if type(turtle.getFuelLevel()) ~= 'number' then - function turtle.getFuelLevel() - return 10000000 - end +function turtle.isTurtleAtSide(side) + local sideType = peripheral.getType(side) + return sideType and sideType == 'turtle' end -- [[ Policies ]] -- @@ -228,7 +228,7 @@ local function _place(action, indexOrId) end end - if slot and slot.qty == 0 then + if slot and slot.count == 0 then return false, 'No items to place' end @@ -321,18 +321,7 @@ function turtle.setMoveCallback(cb) state.moveCallback = cb end function turtle.clearMoveCallback() state.moveCallback = noop end function turtle.getMoveCallback() return state.moveCallback end -function turtle.refuel(qtyOrName, qty) - if not qtyOrName or type(qtyOrName) == 'number' then - return turtle.native.refuel(qtyOrName or 64) - end - return inventoryAction(turtle.native.refuel, qtyOrName, qty or 64) -end - -function turtle.isTurtleAtSide(side) - local sideType = peripheral.getType(side) - return sideType and sideType == 'turtle' -end - +-- convenience method for setting multiple values function turtle.set(args) for k,v in pairs(args) do @@ -363,6 +352,22 @@ function turtle.set(args) end end +-- [[ Fuel ]] -- +if type(turtle.getFuelLevel()) ~= 'number' then + -- Support unlimited fuel + function turtle.getFuelLevel() + return 10000000 + end +end + +-- override to optionally specify a fuel +function turtle.refuel(qtyOrName, qty) + if not qtyOrName or type(qtyOrName) == 'number' then + return turtle.native.refuel(qtyOrName or 64) + end + return inventoryAction(turtle.native.refuel, qtyOrName, qty or 64) +end + -- [[ Heading ]] -- function turtle.getHeading() return turtle.point.heading @@ -740,9 +745,9 @@ function turtle.getSlot(indexOrId, slots) slots = slots or turtle.getInventory() local _,c = string.gsub(indexOrId, ':', '') if c == 2 then -- combined id and dmg .. ie. minecraft:coal:0 - return Util.find(slots, 'iddmg', indexOrId) + return Util.find(slots, 'key', indexOrId) end - return Util.find(slots, 'id', indexOrId) + return Util.find(slots, 'name', indexOrId) end local detail = turtle.getItemDetail(indexOrId) @@ -759,7 +764,6 @@ function turtle.getSlot(indexOrId, slots) qty = detail.count, dmg = detail.damage, id = detail.name, - iddmg = detail.name .. ':' .. detail.damage, } end @@ -798,7 +802,7 @@ function turtle.getSummedInventory() local slots = turtle.getFilledSlots() local t = { } for _,slot in pairs(slots) do - local entry = t[slot.iddmg] + local entry = t[slot.key] if not entry then entry = { count = 0, @@ -810,9 +814,8 @@ function turtle.getSummedInventory() qty = 0, dmg = slot.dmg, id = slot.id, - iddmg = slot.iddmg, } - t[slot.iddmg] = entry + t[slot.key] = entry end entry.qty = entry.qty + slot.qty entry.count = entry.qty @@ -931,8 +934,8 @@ function turtle.getItemCount(idOrName) local slots = turtle.getFilledSlots() local count = 0 for _,slot in pairs(slots) do - if slot.iddmg == idOrName or slot.name == idOrName then - count = count + slot.qty + if slot.key == idOrName or slot.name == idOrName then + count = count + slot.count end end return count @@ -967,7 +970,7 @@ function turtle.unequip(side) return turtle.equip(side) end --- [[ ]] -- +-- deprecate function turtle.run(fn, ...) local args = { ... } local s, m @@ -1233,6 +1236,7 @@ function turtle.enableGPS(timeout) end end +-- deprecate function turtle.addFeatures(...) for _,feature in pairs({ ... }) do require('turtle.' .. feature) From 5a758f02928275386956d3d3d03c59e11ca342b1 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 18 Jan 2019 08:48:30 -0500 Subject: [PATCH 048/231] specify kiosk monitor --- sys/boot/kiosk.boot | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/boot/kiosk.boot b/sys/boot/kiosk.boot index 26b6602..ce76342 100644 --- a/sys/boot/kiosk.boot +++ b/sys/boot/kiosk.boot @@ -4,7 +4,10 @@ local peripheral = _G.peripheral local settings = _G.settings local term = _G.term -local mon = peripheral.find('monitor') +local preferred = settings.get('kiosk.monitor') +local mon = preferred and peripheral.wrap(preferred) or + peripheral.find('monitor') + if mon then term.redirect(mon) mon.setTextScale(tonumber(settings.get('kiosk.textscale')) or 1) From db832025c95b847b23e5771b24a53cdd58ad59d5 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 19 Jan 2019 22:05:05 -0500 Subject: [PATCH 049/231] welcome screen --- sys/apis/ui.lua | 1 + sys/apps/Help.lua | 2 - sys/apps/Welcome.lua | 127 +++++++++++++++++++++++++++++++++++++++ sys/autorun/welcome.lua | 11 ++++ sys/boot/kiosk.boot | 16 +++-- sys/extensions/6.tl3.lua | 3 +- 6 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 sys/apps/Welcome.lua create mode 100644 sys/autorun/welcome.lua diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 2d303c1..666ddac 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -2425,6 +2425,7 @@ function UI.Wizard:eventHandler(event) end -- a new current view current:enable() + current:emit({ type = 'view_enabled', view = current }) self:draw() end end diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index c4b0c9f..cdb5de7 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local UI = require('ui') local Util = require('util') diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua new file mode 100644 index 0000000..737a999 --- /dev/null +++ b/sys/apps/Welcome.lua @@ -0,0 +1,127 @@ +local Ansi = require('ansi') +local Security = require('security') +local SHA1 = require('sha1') +local UI = require('ui') + +local colors = _G.colors +local os = _G.os +local shell = _ENV.shell + +local splashIntro = [[First Time Setup + +%sThanks for installing Opus OS. The next screens will prompt you for basic settings for this computer.]] +local labelIntro = [[Set a friendly name for this computer. + +%sNo spaces recommended.]] +local passwordIntro = [[A password is required for wireless access. + +%sLeave blank to skip.]] +local packagesIntro = [[Setup Complete + +%sOpen the package manager to add software to this computer.]] + +local page = UI.Page { + wizard = UI.Wizard { + ey = -2, + pages = { + splash = UI.Window { + index = 1, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 2, ey = -2, + value = string.format(splashIntro, Ansi.white), + }, + }, + label = UI.Window { + index = 2, + labelText = UI.Text { + x = 3, y = 2, + value = 'Label' + }, + label = UI.TextEntry { + x = 9, y = 2, ex = -3, + limit = 32, + value = os.getComputerLabel(), + }, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 4, ey = -3, + value = string.format(labelIntro, Ansi.white), + }, + }, + password = UI.Window { + index = 3, + labelText = UI.Text { + x = 3, y = 2, + value = 'Password' + }, + newPass = UI.TextEntry { + x = 12, ex = -3, y = 2, + limit = 32, + mask = true, + shadowText = 'password', + accelerators = { + enter = 'new_password', + }, + }, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 4, ey = -3, + value = string.format(passwordIntro, Ansi.white), + }, + }, + packages = UI.Window { + index = 4, + button = UI.Button { + x = 3, y = -3, + text = 'Open Package Manager', + event = 'packages', + }, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 2, ey = -3, + value = string.format(packagesIntro, Ansi.white), + }, + }, + }, + }, + notification = UI.Notification { }, +} + +function page.wizard.pages.label:validate() + os.setComputerLabel(self.label.value) + return true +end + +function page.wizard.pages.password:validate() + if #self.newPass.value > 0 then + Security.updatePassword(SHA1.sha1(self.newPass.value)) + end + return true +end + +function page:eventHandler(event) + if event.type == 'skip' then + self.wizard:emit({ type = 'nextView' }) + + elseif event.type == 'view_enabled' then + event.view:focusFirst() + + elseif event.type == 'packages' then + shell.openForegroundTab('PackageManager') + + elseif event.type == 'wizard_complete' or event.type == 'cancel' then + UI.exitPullEvents() + + else + return UI.Page.eventHandler(self, event) + end + return true +end + +UI:setPage(page) +UI:pullEvents() diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua new file mode 100644 index 0000000..c94e177 --- /dev/null +++ b/sys/autorun/welcome.lua @@ -0,0 +1,11 @@ +local Config = require('config') + +local shell = _ENV.shell + +local config = Config.load('os') +if not config.welcomed then + config.welcomed = true + Config.update('os', config) + + shell.openForegroundTab('Welcome') +end diff --git a/sys/boot/kiosk.boot b/sys/boot/kiosk.boot index ce76342..ea36162 100644 --- a/sys/boot/kiosk.boot +++ b/sys/boot/kiosk.boot @@ -4,9 +4,15 @@ local peripheral = _G.peripheral local settings = _G.settings local term = _G.term -local preferred = settings.get('kiosk.monitor') -local mon = preferred and peripheral.wrap(preferred) or - peripheral.find('monitor') +local name = settings.get('kiosk.monitor') + +if not name then + peripheral.find('monitor', function(s) + name = s + end) +end + +local mon = name and peripheral.wrap(name) if mon then term.redirect(mon) @@ -19,9 +25,9 @@ if mon then function() while true do - local event, _, x, y = os.pullEventRaw('monitor_touch') + local event, side, x, y = os.pullEventRaw('monitor_touch') - if event == 'monitor_touch' then + if event == 'monitor_touch' and side == name then os.queueEvent('mouse_click', 1, x, y) os.queueEvent('mouse_up', 1, x, y) end diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 7660732..a134e78 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -218,7 +218,6 @@ function turtle.setAttackPolicy(policy) state.attackPolicy = policy end -- [[ Place ]] -- local function _place(action, indexOrId) - local slot if indexOrId then @@ -356,7 +355,7 @@ end if type(turtle.getFuelLevel()) ~= 'number' then -- Support unlimited fuel function turtle.getFuelLevel() - return 10000000 + return 100000 end end From 8c794d91077fd437ed2ded171dc28bf11cf2cb70 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 20 Jan 2019 01:28:23 -0500 Subject: [PATCH 050/231] use mounts for web apps --- sys/apps/pain.lua | 1 - sys/autorun/apps.lua | 3 +++ sys/etc/app.db | 33 +++------------------------------ 3 files changed, 6 insertions(+), 31 deletions(-) delete mode 100644 sys/apps/pain.lua create mode 100644 sys/autorun/apps.lua diff --git a/sys/apps/pain.lua b/sys/apps/pain.lua deleted file mode 100644 index 44f9ead..0000000 --- a/sys/apps/pain.lua +++ /dev/null @@ -1 +0,0 @@ -require('util').runUrl(_ENV, 'http://pastebin.com/raw/wJQ7jav0', ...) \ No newline at end of file diff --git a/sys/autorun/apps.lua b/sys/autorun/apps.lua new file mode 100644 index 0000000..3d711d6 --- /dev/null +++ b/sys/autorun/apps.lua @@ -0,0 +1,3 @@ +fs.mount('sys/apps/pain.lua', 'urlfs', 'http://pastebin.com/raw/wJQ7jav0') +fs.mount('sys/apps/update.lua', 'urlfs', 'http://pastebin.com/raw/UzGHLbNC') +fs.mount('sys/apps/Enchat.lua', 'urlfs', 'https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua') diff --git a/sys/etc/app.db b/sys/etc/app.db index 643db6a..29b2b19 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -38,7 +38,7 @@ iconExt = "\031f\128\0313\152\131\131\132\031f\128\ \0313\139\159\129\0303\031f\159\129\139\ \031f\128\0313\136\0303\031f\143\143\030f\0313\134\031f\128", - run = "http://pastebin.com/raw/UzGHLbNC", + run = "update", }, c47ae15370cfe1ed2781eedc1dc2547d12d9e972 = { title = "Help", @@ -60,7 +60,7 @@ iconExt = "\0300\031f\151\030f\128\0300\159\159\159\030f\0310\144\0304\031f\159\030f\128\ \0300\031f\149\030f\128\0300\149\149\151\145\030f\128\0314\153\ \130\131\130\131\130\131\0314\130\031f\128", - run = "sys/apps/Lua.lua", + run = "Lua.lua", }, bc0792d8dc81e8aa30b987246a5ce97c40cd6833 = { title = "System", @@ -92,32 +92,13 @@ \030 \031f\030f\0318\143\133\0312\136\0302\031f\159\159\143\131\030f\0312\132", run = "pain", }, - [ "48d6857f6b2869d031f463b13aa34df47e18c548" ] = { - title = "Breakout", - category = "Games", - icon = "\0301\031f \0309 \030c \030b \030e \030c \0306 \ -\030 \031f \ -\030 \031f \0300 \0310 ", - iconExt = "\030 \031f\030f\0319\144\030d\031f\159\030b\159\030f\0311\144\031b\144\030c\031f\159\030f\0311\144\ -\030 \031f\030f\0311\130\031b\129\0319\130\031e\130\0310\144\031d\129\0316\129\ -\030 \031f\030f\0310\136\140\140\030 ", - run = "https://gist.github.com/LDDestroier/c7528d95bc0103545c2a/raw", - }, - [ "53a5d150062b1e03206b9e15854b81060e3c7552" ] = { - title = "Minesweeper", - category = "Games", - icon = "\030f\031f \03131\0308\031f \030f\031d2\ -\030f\031f \031d2\03131\0308\031f \030f\03131\ -\030f\03131\0308\031f \030f\03131\031e3", - run = "https://pastebin.com/raw/nsKrHTbN", - }, [ "01c933b2a36ad8ed2d54089cb2903039046c1216" ] = { title = "Enchat", icon = "\030e\031f\151\030f\031e\156\0311\140\0314\140\0315\140\031d\140\031b\140\031a\132\ \030f\0314\128\030e\031f\132\030f\031e\132\0318nchat\ \030f\031e\138\141\0311\140\0314\140\0315\132\0317v\03183\031a\132", category = "Apps", - run = "https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua", + run = "Enchat", }, [ "6ce6c512ea433a7fc5c8841628e7696cd0ff7f2b" ] = { title = "Files", @@ -200,12 +181,4 @@ \0317\130\143\0307\128\128\128\128\030f\143\129", run = "/rom/programs/fun/dj", }, - [ "76b849f460640bc789c433894382fb5acbac42a2" ] = { - title = "Tron", - category = "Games", - iconExt = "\030 \031f\030b\031f\143\030f\128\128\030b\143\143\143\030f\128\128\ -\030 \031f\0309\031b\140\030b\031f\151\030f\031b\131\0307\148\0317\128\030b\151\030f\031b\131\148\ -\030 \031f\030f\031b\131\031f\128\031b\131\0317\131\031f\128\0317\131\031b\131\031f\128", - run = "https://raw.githubusercontent.com/LDDestroier/CC/master/tron.lua", - }, } From dc915337a0b71f63d59caa969c4d5d229766017d Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 20 Jan 2019 19:20:13 -0500 Subject: [PATCH 051/231] optional label for checkboxes --- sys/apis/ui.lua | 21 ++++++++++++++++----- sys/autorun/gpshost.lua | 19 ------------------- 2 files changed, 16 insertions(+), 24 deletions(-) delete mode 100644 sys/autorun/gpshost.lua diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 666ddac..1813f40 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -3069,12 +3069,18 @@ UI.Checkbox.defaults = { backgroundColor = colors.black, backgroundFocusColor = colors.lightGray, height = 1, - width = 3, accelerators = { space = 'checkbox_toggle', mouse_click = 'checkbox_toggle', } } +function UI.Checkbox:setParent() + if not self.width and not self.ex then + self.width = (self.label and #self.label or 0) + 3 + end + UI.Window.setParent(self) +end + function UI.Checkbox:draw() local bg = self.backgroundColor if self.focused then @@ -3084,10 +3090,15 @@ function UI.Checkbox:draw() self.value = nil -- TODO: fix form end local text = string.format('[%s]', not self.value and ' ' or self.checkedIndicator) - self:write(1, 1, text, bg) - self:write(1, 1, self.leftMarker, self.backgroundColor, self.textColor) - self:write(2, 1, not self.value and ' ' or self.checkedIndicator, bg) - self:write(3, 1, self.rightMarker, self.backgroundColor, self.textColor) + local x = 1 + if self.label then + self:write(1, 1, self.label) + x = #self.label + 2 + end + self:write(x, 1, text, bg) + self:write(x, 1, self.leftMarker, self.backgroundColor, self.textColor) + self:write(x + 1, 1, not self.value and ' ' or self.checkedIndicator, bg) + self:write(x + 2, 1, self.rightMarker, self.backgroundColor, self.textColor) end function UI.Checkbox:focus() diff --git a/sys/autorun/gpshost.lua b/sys/autorun/gpshost.lua deleted file mode 100644 index 188d009..0000000 --- a/sys/autorun/gpshost.lua +++ /dev/null @@ -1,19 +0,0 @@ -if _G.device.wireless_modem then - - _G.requireInjector(_ENV) - local Config = require('config') - - local kernel = _G.kernel - - local config = { } - Config.load('gps', config) - - if config.host and type(config.host) == 'table' then - kernel.run({ - title = 'GPS Daemon', - hidden = true, - path = '/rom/programs/gps', - args = { 'host', config.host.x, config.host.y, config.host.z }, - }) - end -end From 073f4c1a6dbe97db50db0b6782ae3db6e1075f50 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 23 Jan 2019 15:28:43 -0500 Subject: [PATCH 052/231] cloud edit + logger removal --- sys/apis/logger.lua | 133 ------------------------------------------ sys/apis/socket.lua | 12 ++-- sys/apps/Overview.lua | 4 +- sys/apps/cedit.lua | 26 +++++++++ sys/apps/cshell.lua | 12 ++++ sys/autorun/apps.lua | 1 + sys/etc/app.db | 5 ++ 7 files changed, 50 insertions(+), 143 deletions(-) delete mode 100644 sys/apis/logger.lua create mode 100644 sys/apps/cedit.lua create mode 100644 sys/apps/cshell.lua diff --git a/sys/apis/logger.lua b/sys/apis/logger.lua deleted file mode 100644 index d693f4c..0000000 --- a/sys/apis/logger.lua +++ /dev/null @@ -1,133 +0,0 @@ -local Logger = { - fn = function() end, - filteredEvents = { }, -} - -function Logger.setLogger(fn) - Logger.fn = fn -end - -function Logger.disable() - Logger.setLogger(function() end) -end - -function Logger.setDaemonLogging() - Logger.setLogger(function (text) - os.queueEvent('log', { text = text }) - end) -end - -function Logger.setMonitorLogging() - local debugMon = device.monitor - - if not debugMon then - debugMon.setTextScale(.5) - debugMon.clear() - debugMon.setCursorPos(1, 1) - Logger.setLogger(function(text) - debugMon.write(text) - debugMon.scroll(-1) - debugMon.setCursorPos(1, 1) - end) - end -end - -function Logger.setScreenLogging() - Logger.setLogger(function(text) - local x, y = term.getCursorPos() - if x ~= 1 then - local sx, sy = term.getSize() - term.setCursorPos(1, sy) - --term.scroll(1) - end - print(text) - end) -end - -function Logger.setWirelessLogging() - if device.wireless_modem then - Logger.filter('modem_message') - Logger.filter('modem_receive') - Logger.filter('rednet_message') - Logger.setLogger(function(text) - device.wireless_modem.transmit(59998, os.getComputerID(), { - type = 'log', contents = text - }) - end) - Logger.debug('Logging enabled') - return true - end -end - -function Logger.setFileLogging(fileName) - fs.delete(fileName) - Logger.setLogger(function (text) - local logFile - - local mode = 'w' - if fs.exists(fileName) then - mode = 'a' - end - local file = io.open(fileName, mode) - if file then - file:write(text) - file:write('\n') - file:close() - end - end) -end - -function Logger.log(category, value, ...) - if Logger.filteredEvents[category] then - return - end - - if type(value) == 'table' then - local str - for k,v in pairs(value) do - if not str then - str = '{ ' - else - str = str .. ', ' - end - str = str .. k .. '=' .. tostring(v) - end - if str then - value = str .. ' }' - else - value = '{ }' - end - elseif type(value) == 'string' then - local args = { ... } - if #args > 0 then - value = string.format(value, unpack(args)) - end - else - value = tostring(value) - end - Logger.fn(category .. ': ' .. value) -end - -function Logger.debug(value, ...) - Logger.log('debug', value, ...) -end - -function Logger.logNestedTable(t, indent) - for _,v in ipairs(t) do - if type(v) == 'table' then - log('table') - logNestedTable(v) --, indent+1) - else - log(v) - end - end -end - -function Logger.filter( ...) - local events = { ... } - for _,event in pairs(events) do - Logger.filteredEvents[event] = true - end -end - -return Logger \ No newline at end of file diff --git a/sys/apis/socket.lua b/sys/apis/socket.lua index 7926234..a2d2d7a 100644 --- a/sys/apis/socket.lua +++ b/sys/apis/socket.lua @@ -1,5 +1,4 @@ local Crypto = require('crypto') -local Logger = require('logger') local Security = require('security') local Util = require('util') @@ -15,7 +14,6 @@ function socketClass:read(timeout) end if not self.connected then - Logger.log('socket', 'read: No connection') return end @@ -64,7 +62,6 @@ end function socketClass:close() if self.connected then - Logger.log('socket', 'closing socket ' .. self.sport) self.transmit(self.dport, self.dhost, { type = 'DISC', }) @@ -113,7 +110,6 @@ function Socket.connect(host, port) local socket = newSocket(host == os.getComputerID()) socket.dhost = tonumber(host) - Logger.log('socket', 'connecting to ' .. port) socket.transmit(port, socket.sport, { type = 'OPEN', @@ -138,8 +134,8 @@ function Socket.connect(host, port) socket.dport = dport socket.connected = true - Logger.log('socket', 'connection established to %d %d->%d', - host, socket.sport, socket.dport) + -- Logger.log('socket', 'connection established to %d %d->%d', + -- host, socket.sport, socket.dport) _G.transport.open(socket) @@ -179,7 +175,7 @@ end function Socket.server(port) device.wireless_modem.open(port) - Logger.log('socket', 'Waiting for connections on port ' .. port) + -- Logger.log('socket', 'Waiting for connections on port ' .. port) while true do local _, _, sport, dport, msg = os.pullEvent('modem_message') @@ -203,7 +199,7 @@ function Socket.server(port) dhost = socket.dhost, shost = socket.shost, }) - Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport) + -- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport) _G.transport.open(socket) return socket diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 309c2c1..d823928 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -43,7 +43,7 @@ local buttons = { } local sx, sy = term.current().getSize() local maxRecent = math.ceil(sx * sy / 62) -local function elipse(s, len) +local function ellipsis(s, len) if #s > len then s = s:sub(1, len - 2) .. '..' end @@ -253,7 +253,7 @@ function page.container:setCategory(categoryName, animate) icon = DEFAULT_ICON end - local title = elipse(program.title, 8) + local title = ellipsis(program.title, 8) local width = math.max(icon.width + 2, #title + 2) table.insert(self.children, UI.Icon({ diff --git a/sys/apps/cedit.lua b/sys/apps/cedit.lua new file mode 100644 index 0000000..d1c1295 --- /dev/null +++ b/sys/apps/cedit.lua @@ -0,0 +1,26 @@ +local multishell = _ENV.multishell +local os = _G.os +local read = _G.read +local shell = _ENV.shell + +local args = { ... } +if not args[1] then + error('Syntax: cedit ') +end + +if not _G.cloud_catcher then + print('Paste key: ') + local key = read() + if #key == 0 then + return + end + -- open an unfocused tab + local id = shell.openTab('cloud ' .. key) + print('Connecting...') + while not _G.cloud_catcher do + os.sleep(.2) + end + multishell.setTitle(id, 'Cloud') +end + +shell.run('cloud edit ' .. table.unpack({ ... })) diff --git a/sys/apps/cshell.lua b/sys/apps/cshell.lua new file mode 100644 index 0000000..9d54e84 --- /dev/null +++ b/sys/apps/cshell.lua @@ -0,0 +1,12 @@ +local read = _G.read +local shell = _ENV.shell + +if not _G.cloud_catcher then + print('Paste key: ') + local key = read() + if #key == 0 then + return + end + print('Connecting...') + shell.run('cloud ' .. key) +end diff --git a/sys/autorun/apps.lua b/sys/autorun/apps.lua index 3d711d6..c66656b 100644 --- a/sys/autorun/apps.lua +++ b/sys/autorun/apps.lua @@ -1,3 +1,4 @@ fs.mount('sys/apps/pain.lua', 'urlfs', 'http://pastebin.com/raw/wJQ7jav0') fs.mount('sys/apps/update.lua', 'urlfs', 'http://pastebin.com/raw/UzGHLbNC') fs.mount('sys/apps/Enchat.lua', 'urlfs', 'https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua') +fs.mount('sys/apps/cloud.lua', 'urlfs', 'https://cloud-catcher.squiddev.cc/cloud.lua') diff --git a/sys/etc/app.db b/sys/etc/app.db index 29b2b19..f1349ff 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -7,6 +7,11 @@ \030c\0317\151\131\0310\143\0317\131\0307\031c\148\ \0307\031c\138\030f\0317\151\131\131\131", }, + [ "b2efeaa1a7d6d2185ea02473cf758203dfcea3fe" ] = { + title = "Cloud", + category = "Apps", + run = "cshell.lua", + }, [ "53ebc572b4a44802ba114729f07bdaaf5409a9d7" ] = { title = "Network", category = "Apps", From 2438a406774d1ba445ffda96a0bdd19706bfaab9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 23 Jan 2019 15:43:12 -0500 Subject: [PATCH 053/231] cloud catcher --- sys/apps/Files.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index e40f538..1053e79 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -40,6 +40,7 @@ local Browser = UI.Page { { text = 'File', dropdown = { { text = 'Run', event = 'run' }, { text = 'Edit e', event = 'edit' }, + { text = 'Cloud edit c', event = 'cedit' }, { text = 'Shell s', event = 'shell' }, UI.MenuBar.spacer, { text = 'Quit q', event = 'quit' }, From 66f9481e7dd36d6a2152ecac040dd7b5fc124ebc Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 23 Jan 2019 19:25:09 -0500 Subject: [PATCH 054/231] ui checkbox oops --- sys/apis/ui.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 1813f40..a71ac83 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -3077,6 +3077,8 @@ UI.Checkbox.defaults = { function UI.Checkbox:setParent() if not self.width and not self.ex then self.width = (self.label and #self.label or 0) + 3 + else + self.widthh = 3 end UI.Window.setParent(self) end From 496e95a6c4d138e068ab7f6b23dc07f1257431e7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 26 Jan 2019 00:27:56 -0500 Subject: [PATCH 055/231] trigger event instead of os.queueEvent --- sys/apis/event.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sys/apis/event.lua b/sys/apis/event.lua index 2a66542..5fe4d87 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -243,6 +243,21 @@ local function processRoutines(...) end end +-- invoke the handlers registered for this event +function Event.trigger(event, ...) + local handlers = Event.types[event] + if handlers then + for _,h in pairs(handlers) do + if not h.co then + -- callbacks are single threaded (only 1 co per handler) + h.co = createCoroutine(h) + Event.routines[h.uid] = h + h:resume(event, ...) + end + end + end +end + function Event.processEvent(e) processHandlers(e[1]) processRoutines(table.unpack(e)) From b320c92551a7643da674446bf996b331194b0fc3 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 26 Jan 2019 22:58:02 -0500 Subject: [PATCH 056/231] require rework round 3 --- sys/apis/injector.lua | 52 ++++++++++++----------------------- sys/apps/Network.lua | 4 ++- sys/extensions/4.user.lua | 4 ++- sys/extensions/6.packages.lua | 8 +----- 4 files changed, 24 insertions(+), 44 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index d7ddfec..12792f6 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -15,12 +15,12 @@ for i = 1, #luaPaths do end end -table.insert(luaPaths, 1, '?') -table.insert(luaPaths, 2, '?.lua') -table.insert(luaPaths, 3, '/usr/apis/?') -table.insert(luaPaths, 4, '/usr/apis/?.lua') -table.insert(luaPaths, 5, '/sys/apis/?') -table.insert(luaPaths, 6, '/sys/apis/?.lua') +table.insert(luaPaths, 1, '?.lua') +table.insert(luaPaths, 2, '?/init.lua') +table.insert(luaPaths, 3, '/usr/apis/?.lua') +table.insert(luaPaths, 4, '/usr/apis/?/init.lua') +table.insert(luaPaths, 5, '/sys/apis/?.lua') +table.insert(luaPaths, 6, '/sys/apis/?/init.lua') local DEFAULT_PATH = table.concat(luaPaths, ';') local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'develop-1.8' @@ -82,30 +82,18 @@ end -- Add require and package to the environment return function(env) - local function standardSearcher(modname) - -- Should this be 2 diff searchers ? if yes, installer would need an update + local function preloadSearcher(modname) if env.package.preload[modname] then return function() return env.package.preload[modname](modname, env) end end - if env.package.loaded[modname] then - return function() - return env.package.loaded[modname] - end - end end - local function shellSearcher(modname) - local fname = modname:gsub('%.', '/') .. '.lua' - - if env.shell and type(env.shell.getRunningProgram) == 'function' then - local running = env.shell.getRunningProgram() - if running then - local path = fs.combine(fs.getDir(running), fname) - if fs.exists(path) and not fs.isDir(path) then - return loadfile(path, env) - end + local function loadedSearcher(modname) + if env.package.loaded[modname] then + return function() + return env.package.loaded[modname] end end end @@ -115,21 +103,15 @@ return function(env) for pattern in string.gmatch(env.package.path, "[^;]+") do local sPath = string.gsub(pattern, "%?", fname) - if env.shell and env.shell.dir and sPath:sub(1, 1) ~= "/" then - sPath = fs.combine(env.shell.dir(), sPath) + -- TODO: if there's no shell, we should not be checking relative paths below + -- as they will resolve to root directory + if env.shell and type(env.shell.getRunningProgram) == 'function' and sPath:sub(1, 1) ~= "/" then + sPath = fs.combine(fs.getDir(env.shell.getRunningProgram()), sPath) end if fs.exists(sPath) and not fs.isDir(sPath) then return loadfile(sPath, env) end end - --[[ - for dir in string.gmatch(env.package.path, "[^:]+") do - local path = fs.combine(dir, fname) - if fs.exists(path) and not fs.isDir(path) then - return loadfile(path, env) - end - end - ]] end -- require('BniCQPVf') @@ -185,8 +167,8 @@ return function(env) table = table, }, loaders = { - standardSearcher, - shellSearcher, + preloadSearcher, + loadedSearcher, pathSearcher, pastebinSearcher, gitSearcher, diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 85f6502..70f77c2 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -41,9 +41,10 @@ local page = UI.Page { --{ text = 'Chat', event = 'chat' }, { text = 'Trust', dropdown = { { text = 'Establish', event = 'trust' }, - { text = 'Remove', event = 'untrust' }, +-- { text = 'Remove', event = 'untrust' }, } }, { text = 'Help', event = 'help', noCheck = true }, +--[[ { text = '\187', x = -3, @@ -53,6 +54,7 @@ local page = UI.Page { { text = 'Show trusted', event = 'show_trusted', noCheck = true }, }, }, +]] }, }, grid = UI.ScrollingGrid { diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 89a7000..722ec9a 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -44,6 +44,8 @@ for _, v in pairs(Util.split(shell.path(), '(.-):')) do end shell.setPath(table.concat(path, ':')) -_G.LUA_PATH = config.lua_path +-- TODO: replace when stable (old lua path is now incorrect) +-- _G.LUA_PATH = config.lua_path +_G.LUA_PATH = package.path fs.loadTab('usr/config/fstab') diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index c7203b3..9510e35 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -24,12 +24,6 @@ local function addEntry(t, e, n) table.insert(t, n or 1, e) end -local function addRequirePath(t, path) - addEntry(t, string.format('/%s/?/init.lua', path), 7) - addEntry(t, string.format('/%s/?.lua', path), 7) - addEntry(t, string.format('/%s/?', path), 7) -end - for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) if fs.exists(fs.combine(packageDir, '.install')) then @@ -42,7 +36,7 @@ for name in pairs(Packages:installed()) do addEntry(appPaths, packageDir) local apiPath = fs.combine(fs.combine('packages', name), 'apis') if fs.exists(apiPath) then - addRequirePath(luaPaths, apiPath) + fs.mount(fs.combine('sys/apis', name), 'linkfs', apiPath) end local helpPath = '/' .. fs.combine(fs.combine('packages', name), 'help') From dddb2a6b972f3491a7ca1ec82c56e704c6203642 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 27 Jan 2019 00:26:41 -0500 Subject: [PATCH 057/231] network update --wip --- sys/apis/injector.lua | 2 +- sys/apps/Network.lua | 75 +++++++++++++++++++++++++++++++++++---- sys/network/redserver.lua | 2 +- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 12792f6..7877a4c 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -106,7 +106,7 @@ return function(env) -- TODO: if there's no shell, we should not be checking relative paths below -- as they will resolve to root directory if env.shell and type(env.shell.getRunningProgram) == 'function' and sPath:sub(1, 1) ~= "/" then - sPath = fs.combine(fs.getDir(env.shell.getRunningProgram()), sPath) + sPath = fs.combine(fs.getDir(env.shell.getRunningProgram() or ''), sPath) end if fs.exists(sPath) and not fs.isDir(sPath) then return loadfile(sPath, env) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 70f77c2..2c26afe 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Config = require('config') local Event = require('event') local Socket = require('socket') @@ -44,17 +42,16 @@ local page = UI.Page { -- { text = 'Remove', event = 'untrust' }, } }, { text = 'Help', event = 'help', noCheck = true }, ---[[ { text = '\187', x = -3, dropdown = { - { text = 'Show all', event = 'show_all', noCheck = true }, - UI.MenuBar.spacer, - { text = 'Show trusted', event = 'show_trusted', noCheck = true }, + { text = 'Ports', event = 'ports', noCheck = true }, + -- { text = 'Show all', event = 'show_all', noCheck = true }, + -- UI.MenuBar.spacer, + -- { text = 'Show trusted', event = 'show_trusted', noCheck = true }, }, }, -]] }, }, grid = UI.ScrollingGrid { @@ -64,6 +61,22 @@ local page = UI.Page { sortColumn = 'label', autospace = true, }, + ports = UI.SlideOut { + titleBar = UI.TitleBar { + title = 'Ports', + event = 'ports_hide', + }, + grid = UI.ScrollingGrid { + y = 2, + columns = { + { heading = 'Port', key = 'port' }, + { heading = 'State', key = 'state' }, + { heading = 'Connection', key = 'connection' }, + }, + sortColumn = 'port', + autospace = true, + }, + }, notification = UI.Notification { }, accelerators = { t = 'telnet', @@ -93,6 +106,40 @@ local function sendCommand(host, command) end end +function page.ports.grid:update() + local function findConnection(port) + for _,socket in pairs(_G.transport.sockets) do + if socket.sport == port then + return socket + end + end + end + + local connections = { } + + for i = 0, 65535 do + if device.wireless_modem.isOpen(i) then + local conn = { + port = i + } + local socket = findConnection(i) + if socket then + conn.state = 'CONNECTED' + local host = socket.dhost + if network[host] then + host = network[host].label + end + conn.connection = host .. ':' .. socket.dport + else + conn.state = 'LISTEN' + end + table.insert(connections, conn) + end + end + self.values = connections + UI.Grid.update(self) +end + function page:eventHandler(event) local t = self.grid:getSelected() if t then @@ -167,6 +214,20 @@ This only needs to be done once. } }) + elseif event.type == 'ports' then + self.ports.grid:update() + self.ports:show() + + self.portsHandler = Event.onInterval(3, function() + self.ports.grid:update() + self.ports.grid:draw() + self:sync() + end) + + elseif event.type == 'ports_hide' then + Event.off(self.portsHandler) + self.ports:hide() + elseif event.type == 'show_all' then config.showTrusted = false self.grid:setValues(network) diff --git a/sys/network/redserver.lua b/sys/network/redserver.lua index 8da25a4..6c63d21 100644 --- a/sys/network/redserver.lua +++ b/sys/network/redserver.lua @@ -7,7 +7,7 @@ local os = _G.os local computerId = os.getComputerID() -modem.open(80) +--modem.open(80) -- https://github.com/golgote/neturl/blob/master/lib/net/url.lua local function parseQuery(str) From 02629e266b70fc003a920952588b9d51e6c7d220 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 28 Jan 2019 17:54:00 -0500 Subject: [PATCH 058/231] Overview update --- sys/apis/ui.lua | 57 ++++++--------- sys/apis/ui/fileui.lua | 145 ------------------------------------ sys/apps/Network.lua | 84 +++++++-------------- sys/apps/Overview.lua | 162 ++++++++++++++++++++--------------------- 4 files changed, 131 insertions(+), 317 deletions(-) delete mode 100644 sys/apis/ui/fileui.lua diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index a71ac83..098a56d 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -583,11 +583,11 @@ function UI.Window:sync() end end -function UI.Window:enable() +function UI.Window:enable(...) self.enabled = true if self.children then for _,child in pairs(self.children) do - child:enable() + child:enable(...) end end end @@ -607,10 +607,12 @@ function UI.Window:setTextScale(textScale) end function UI.Window:clear(bg, fg) - if self.canvas then - self.canvas:clear(bg or self.backgroundColor, fg or self.textColor) - else - self:clearArea(1 + self.offx, 1 + self.offy, self.width, self.height, bg) + if self.enabled then + if self.canvas then + self.canvas:clear(bg or self.backgroundColor, fg or self.textColor) + else + self:clearArea(1 + self.offx, 1 + self.offy, self.width, self.height, bg) + end end end @@ -628,16 +630,18 @@ function UI.Window:clearArea(x, y, width, height, bg) end function UI.Window:write(x, y, text, bg, tc) - bg = bg or self.backgroundColor - tc = tc or self.textColor - x = x - self.offx - y = y - self.offy - if y <= self.height and y > 0 then - if self.canvas then - self.canvas:write(x, y, text, bg, tc) - else - self.parent:write( - self.x + x - 1, self.y + y - 1, tostring(text), bg, tc) + if self.enabled then + bg = bg or self.backgroundColor + tc = tc or self.textColor + x = x - self.offx + y = y - self.offy + if y <= self.height and y > 0 then + if self.canvas then + self.canvas:write(x, y, text, bg, tc) + else + self.parent:write( + self.x + x - 1, self.y + y - 1, tostring(text), bg, tc) + end end end end @@ -2056,6 +2060,7 @@ function UI.MenuBar:eventHandler(event) if event.type == 'button_press' and event.button.dropmenu then if event.button.dropmenu.enabled then event.button.dropmenu:hide() + self:refocus() return true else local x, y = getPosition(event.button) @@ -2123,7 +2128,6 @@ function UI.DropMenu:setParent() end function UI.DropMenu:enable() - self.enabled = false end function UI.DropMenu:show(x, y) @@ -2131,10 +2135,7 @@ function UI.DropMenu:show(x, y) self.canvas:move(x, y) self.canvas:setVisible(true) - self.enabled = true - for _,child in pairs(self.children) do - child:enable() - end + UI.Window.enable(self) self:draw() self:capture(self) @@ -2442,16 +2443,12 @@ function UI.SlideOut:setParent() end function UI.SlideOut:enable() - self.enabled = false end function UI.SlideOut:show(...) self:addTransition('expandUp') self.canvas:setVisible(true) - self.enabled = true - for _,child in pairs(self.children) do - child:enable(...) - end + UI.Window.enable(self, ...) self:draw() self:capture(self) self:focusFirst() @@ -2459,12 +2456,7 @@ end function UI.SlideOut:disable() self.canvas:setVisible(false) - self.enabled = false - if self.children then - for _,child in pairs(self.children) do - child:disable() - end - end + UI.Window.disable(self) end function UI.SlideOut:hide() @@ -2553,7 +2545,6 @@ function UI.Notification:draw() end function UI.Notification:enable() - self.enabled = false end function UI.Notification:error(value, timeout) diff --git a/sys/apis/ui/fileui.lua b/sys/apis/ui/fileui.lua deleted file mode 100644 index 02e2bc7..0000000 --- a/sys/apis/ui/fileui.lua +++ /dev/null @@ -1,145 +0,0 @@ -local UI = require('ui') -local Util = require('util') - -local colors = _G.colors -local fs = _G.fs - -return function(args) - - local columns = { - { heading = 'Name', key = 'name' }, - } - - if UI.term.width > 28 then - table.insert(columns, - { heading = 'Size', key = 'size', width = 5 } - ) - end - - args = args or { } - - local selectFile = UI.Dialog { - x = args.x or 3, - y = args.y or 2, - z = args.z or 2, --- rex = args.rex or -3, --- rey = args.rey or -3, - height = args.height, - width = args.width, - title = 'Select File', - grid = UI.ScrollingGrid { - x = 2, - y = 2, - ex = -2, - ey = -4, - path = '', - sortColumn = 'name', - columns = columns, - }, - path = UI.TextEntry { - x = 2, - y = -2, - ex = -11, - limit = 256, - accelerators = { - enter = 'path_enter', - } - }, - cancel = UI.Button { - text = 'Cancel', - x = -9, - y = -2, - event = 'cancel', - }, - } - - function selectFile:enable(path, fn) - self:setPath(path) - self.fn = fn - UI.Dialog.enable(self) - end - - function selectFile:setPath(path) - self.grid.dir = path - while not fs.isDir(self.grid.dir) do - self.grid.dir = fs.getDir(self.grid.dir) - end - - self.path.value = self.grid.dir - end - - function selectFile.grid:draw() - local files = fs.listEx(self.dir) - if #self.dir > 0 then - table.insert(files, { - name = '..', - isDir = true, - }) - end - self:setValues(files) - self:setIndex(1) - UI.Grid.draw(self) - end - - function selectFile.grid:getDisplayValues(row) - if row.size then - row = Util.shallowCopy(row) - row.size = Util.toBytes(row.size) - end - return row - end - - function selectFile.grid:getRowTextColor(file) - if file.isDir then - return colors.cyan - end - if file.isReadOnly then - return colors.pink - end - return colors.white - end - - function selectFile.grid:sortCompare(a, b) - if self.sortColumn == 'size' then - return a.size < b.size - end - if a.isDir == b.isDir then - return a.name:lower() < b.name:lower() - end - return a.isDir - end - - function selectFile:eventHandler(event) - - if event.type == 'grid_select' then - self.grid.dir = fs.combine(self.grid.dir, event.selected.name) - self.path.value = self.grid.dir - if event.selected.isDir then - self.grid:draw() - self.path:draw() - else - UI:setPreviousPage() - self.fn(self.path.value) - end - - elseif event.type == 'path_enter' then - if fs.isDir(self.path.value) then - self:setPath(self.path.value) - self.grid:draw() - self.path:draw() - else - UI:setPreviousPage() - self.fn(self.path.value) - end - - elseif event.type == 'cancel' then - UI:setPreviousPage() - self.fn() - else - return UI.Dialog.eventHandler(self, event) - end - return true - end - - return selectFile -end diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 2c26afe..802b8b5 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -19,7 +19,6 @@ local gridColumns = { { heading = 'Status', key = 'status' }, } -local trusted = Util.readTable('usr/.known_hosts') local config = Config.load('network', { }) if UI.term.width >= 30 then @@ -36,20 +35,16 @@ local page = UI.Page { UI.MenuBar.spacer, { text = 'Reboot r', event = 'reboot' }, } }, - --{ text = 'Chat', event = 'chat' }, { text = 'Trust', dropdown = { { text = 'Establish', event = 'trust' }, --- { text = 'Remove', event = 'untrust' }, } }, - { text = 'Help', event = 'help', noCheck = true }, { text = '\187', x = -3, dropdown = { - { text = 'Ports', event = 'ports', noCheck = true }, - -- { text = 'Show all', event = 'show_all', noCheck = true }, - -- UI.MenuBar.spacer, - -- { text = 'Show trusted', event = 'show_trusted', noCheck = true }, + { text = 'Port Status', event = 'ports', modem = true }, + UI.MenuBar.spacer, + { text = 'Help', event = 'help', noCheck = true }, }, }, }, @@ -117,25 +112,30 @@ function page.ports.grid:update() local connections = { } - for i = 0, 65535 do - if device.wireless_modem.isOpen(i) then - local conn = { - port = i - } - local socket = findConnection(i) - if socket then - conn.state = 'CONNECTED' - local host = socket.dhost - if network[host] then - host = network[host].label + pcall(function() -- guard against modem removal + if device.wireless_modem then + for i = 0, 65535 do + if device.wireless_modem.isOpen(i) then + local conn = { + port = i + } + local socket = findConnection(i) + if socket then + conn.state = 'CONNECTED' + local host = socket.dhost + if network[host] then + host = network[host].label + end + conn.connection = host .. ':' .. socket.dport + else + conn.state = 'LISTEN' + end + table.insert(connections, conn) end - conn.connection = host .. ':' .. socket.dport - else - conn.state = 'LISTEN' end - table.insert(connections, conn) end - end + end) + self.values = connections UI.Grid.update(self) end @@ -173,18 +173,6 @@ function page:eventHandler(event) elseif event.type == 'trust' then shell.openForegroundTab('trust ' .. t.id) - elseif event.type == 'untrust' then - local trustList = Util.readTable('usr/.known_hosts') or { } - trustList[t.id] = nil - Util.writeTable('usr/.known_hosts', trustList) - - elseif event.type == 'chat' then - multishell.openTab({ - path = 'sys/apps/shell', - args = { 'chat join opusChat-' .. t.id .. ' guest-' .. os.getComputerID() }, - title = 'Chatroom', - focused = true, - }) elseif event.type == 'reboot' then sendCommand(t.id, 'reboot') @@ -228,11 +216,6 @@ This only needs to be done once. Event.off(self.portsHandler) self.ports:hide() - elseif event.type == 'show_all' then - config.showTrusted = false - self.grid:setValues(network) - Config.update('network', config) - elseif event.type == 'show_trusted' then config.showTrusted = true Config.update('network', config) @@ -245,16 +228,15 @@ end function page.menuBar:getActive(menuItem) local t = page.grid:getSelected() - if menuItem.event == 'untrust' then - local trustList = Util.readTable('usr/.known_hosts') or { } - return t and trustList[t.id] + if menuItem.modem then + return not not device.wireless_modem end return menuItem.noCheck or not not t end function page.grid:getRowTextColor(row, selected) if not row.active then - return colors.orange + return colors.lightGray end return UI.Grid.getRowTextColor(self, row, selected) end @@ -278,17 +260,7 @@ function page.grid:getDisplayValues(row) end Event.onInterval(1, function() - local t = { } - if config.showTrusted then - for k,v in pairs(network) do - if trusted[k] then - t[k] = v - end - end - page.grid:setValues(t) - else - page.grid:update() - end + page.grid:update() page.grid:draw() page:sync() end) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index d823928..3bda2b1 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -3,7 +3,6 @@ _G.requireInjector(_ENV) local class = require('class') local Config = require('config') local Event = require('event') -local FileUI = require('ui.fileui') local NFT = require('nft') local Packages = require('packages') local SHA1 = require('sha1') @@ -13,6 +12,7 @@ local Util = require('util') local colors = _G.colors local fs = _G.fs +local os = _G.os local pocket = _G.pocket local shell = _ENV.shell local term = _G.term @@ -75,7 +75,7 @@ function UI.VerticalTabBar:setParent() self.x = 1 self.width = 8 self.height = nil - self.ey = -1 + self.ey = -2 UI.TabBar.setParent(self) for k,c in pairs(self.children) do c.x = 1 @@ -88,17 +88,60 @@ end local cx = 9 local cy = 1 -if sx < 30 then - UI.VerticalTabBar = UI.TabBar - cx = 1 - cy = 2 -end local page = UI.Page { container = UI.Viewport { x = cx, y = cy, }, + tray = UI.Window { + y = -1, width = 8, + backgroundColor = colors.lightGray, + newApp = UI.Button { + text = '+', event = 'new', + }, + volume = UI.Button { + x = 3, + text = '\15', event = 'volume', + } + }, + editor = UI.SlideOut { + backgroundColor = colors.cyan, + titleBar = UI.TitleBar { + title = 'Edit Application', + event = 'slide_hide', + }, + form = UI.Form { + y = 2, ey = -2, + [1] = UI.TextEntry { + formLabel = 'Title', formKey = 'title', limit = 11, help = 'Application title', + required = true, + }, + [2] = UI.TextEntry { + formLabel = 'Run', formKey = 'run', limit = 100, help = 'Full path to application', + required = true, + }, + [3] = UI.TextEntry { + formLabel = 'Category', formKey = 'category', limit = 11, help = 'Category of application', + required = true, + }, + iconFile = UI.TextEntry { + x = 11, ex = -12, y = 7, + limit = 128, help = 'Path to icon file', + shadowText = 'Path to icon file', + }, + loadIcon = UI.Button { + x = 11, y = 9, + text = 'Load', event = 'loadIcon', help = 'Load icon file', + }, + image = UI.NftImage { + backgroundColor = colors.black, + y = 7, x = 2, height = 3, width = 8, + }, + }, + notification = UI.Notification(), + statusBar = UI.StatusBar(), + }, notification = UI.Notification(), accelerators = { r = 'refresh', @@ -172,7 +215,6 @@ local function loadApplications() end table.sort(buttons, function(a, b) return a.text < b.text end) table.insert(buttons, 1, { text = 'Recent' }) - table.insert(buttons, { text = '+', event = 'new' }) Util.removeByValue(page.children, page.tabBar) @@ -421,12 +463,12 @@ function page:eventHandler(event) if config.currentCategory ~= 'Recent' then category = config.currentCategory or 'Apps' end - UI:setPage('editor', { category = category }) + self.editor:show({ category = category }) elseif event.type == 'edit' then local focused = page:getFocused() if focused.app then - UI:setPage('editor', focused.app) + self.editor:show(focused.app) end else @@ -435,40 +477,7 @@ function page:eventHandler(event) return true end -local formWidth = math.max(UI.term.width - 8, 26) - -local editor = UI.Dialog { - height = 11, - width = formWidth, - title = 'Edit Application', - form = UI.Form { - y = 2, - height = 9, - title = UI.TextEntry { - formLabel = 'Title', formKey = 'title', limit = 11, help = 'Application title', - required = true, - }, - run = UI.TextEntry { - formLabel = 'Run', formKey = 'run', limit = 100, help = 'Full path to application', - required = true, - }, - category = UI.TextEntry { - formLabel = 'Category', formKey = 'category', limit = 11, help = 'Category of application', - required = true, - }, - loadIcon = UI.Button { - x = 11, y = 6, - text = 'Icon', event = 'loadIcon', help = 'Select icon' - }, - image = UI.NftImage { - y = 6, x = 2, height = 3, width = 8, - }, - }, - statusBar = UI.StatusBar(), - iconFile = '', -} - -function editor:enable(app) +function page.editor:show(app) if app then self.form:setValues(app) @@ -481,16 +490,16 @@ function editor:enable(app) end self.form.image:setImage(icon) end - UI.Dialog.enable(self) + UI.SlideOut.show(self) self:focusFirst() end -function editor.form.image:draw() +function page.editor.form.image:draw() self:clear() UI.NftImage.draw(self) end -function editor:updateApplications(app) +function page.editor:updateApplications(app) if not app.key then app.key = SHA1.sha1(app.title) end @@ -499,51 +508,39 @@ function editor:updateApplications(app) loadApplications() end -function editor:eventHandler(event) +function page.editor:eventHandler(event) if event.type == 'form_cancel' or event.type == 'cancel' then - UI:setPreviousPage() + self:hide() elseif event.type == 'focus_change' then self.statusBar:setStatus(event.focused.help or '') self.statusBar:draw() elseif event.type == 'loadIcon' then - local fileui = FileUI({ - x = self.x, - y = self.y, - z = 2, - width = self.width, - height = self.height, - }) - UI:setPage(fileui, fs.getDir(self.iconFile), function(fileName) - if fileName then - self.iconFile = fileName - local s, m = pcall(function() - local iconLines = Util.readFile(fileName) - if not iconLines then - error('Must be an NFT image - 3 rows, 8 cols max') - end - local icon, m = parseIcon(iconLines) - if not icon then - error(m) - end - if extSupport then - self.form.values.iconExt = iconLines - else - self.form.values.icon = iconLines - end - self.form.image:setImage(icon) - self.form.image:draw() - end) - if not s and m then - local msg = m:gsub('.*: (.*)', '%1') - page.notification:error(msg) - end + local s, m = pcall(function() + local iconLines = Util.readFile(self.form.iconFile.value) + if not iconLines then + error('Must be an NFT image - 3 rows, 8 cols max') end + local icon, m = parseIcon(iconLines) + if not icon then + error(m) + end + if extSupport then + self.form.values.iconExt = iconLines + else + self.form.values.icon = iconLines + end + self.form.image:setImage(icon) + self.form.image:draw() end) + if not s and m then + local msg = m:gsub('.*: (.*)', '%1') + self.notification:error(msg) + end elseif event.type == 'form_invalid' then - page.notification:error(event.message) + self.notification:error(event.message) elseif event.type == 'form_complete' then local values = self.form.values @@ -555,13 +552,12 @@ function editor:eventHandler(event) Config.update('Overview', config) os.queueEvent('overview_refresh') else - return UI.Dialog.eventHandler(self, event) + return UI.SlideOut.eventHandler(self, event) end return true end UI:setPages({ - editor = editor, main = page, }) From 3574d26caadbce2c90284d9197756a229aa8dc95 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 30 Jan 2019 15:11:41 -0500 Subject: [PATCH 059/231] canvas use in UI overhaul --- sys/apis/ui.lua | 149 +++++++++++++++++++---------------- sys/apis/ui/transition.lua | 66 ++++------------ sys/apps/Network.lua | 47 ++++++----- sys/apps/Overview.lua | 1 + sys/apps/System.lua | 2 +- sys/apps/system/aliases.lua | 2 +- sys/apps/system/label.lua | 2 +- sys/apps/system/network.lua | 4 +- sys/apps/system/password.lua | 2 +- sys/apps/system/path.lua | 2 +- sys/apps/system/settings.lua | 5 +- sys/apps/system/turtle.lua | 2 +- 12 files changed, 137 insertions(+), 147 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 098a56d..d97df26 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -317,6 +317,7 @@ end function Manager:setActivePage(page) page.parent.currentPage = page + page.parent.canvas = page.canvas end function Manager:setPage(pageOrName, ...) @@ -330,7 +331,6 @@ function Manager:setPage(pageOrName, ...) if page == currentPage then page:draw() else - local needSync if currentPage then if currentPage.focused then currentPage.focused.focused = false @@ -338,20 +338,16 @@ function Manager:setPage(pageOrName, ...) end currentPage:disable() page.previousPage = currentPage - else - needSync = true end self:setActivePage(page) - page:clear(page.backgroundColor) + --page:clear(page.backgroundColor) page:enable(...) page:draw() if page.focused then page.focused.focused = true page.focused:focus() end - if needSync then - page:sync() -- first time a page has been set - end + page:sync() end end @@ -607,12 +603,10 @@ function UI.Window:setTextScale(textScale) end function UI.Window:clear(bg, fg) - if self.enabled then - if self.canvas then - self.canvas:clear(bg or self.backgroundColor, fg or self.textColor) - else - self:clearArea(1 + self.offx, 1 + self.offy, self.width, self.height, bg) - end + if self.canvas then + self.canvas:clear(bg or self.backgroundColor, fg or self.textColor) + else + self:clearArea(1 + self.offx, 1 + self.offy, self.width, self.height, bg) end end @@ -630,18 +624,17 @@ function UI.Window:clearArea(x, y, width, height, bg) end function UI.Window:write(x, y, text, bg, tc) - if self.enabled then - bg = bg or self.backgroundColor - tc = tc or self.textColor - x = x - self.offx - y = y - self.offy - if y <= self.height and y > 0 then - if self.canvas then - self.canvas:write(x, y, text, bg, tc) - else - self.parent:write( - self.x + x - 1, self.y + y - 1, tostring(text), bg, tc) - end + bg = bg or self.backgroundColor + tc = tc or self.textColor + -- TODO: get rid of offx/y - scroll canvas instead + x = x - self.offx + y = y - self.offy + if y <= self.height and y > 0 then + if self.canvas then + self.canvas:write(x, y, text, bg, tc) + else + self.parent:write( + self.x + x - 1, self.y + y - 1, tostring(text), bg, tc) end end end @@ -933,12 +926,6 @@ function UI.Device:postInit() self.isColor = self.device.isColor() - self.canvas = Canvas({ - x = 1, y = 1, width = self.width, height = self.height, - isColor = self.isColor, - }) - self.canvas:clear(self.backgroundColor, self.textColor) - UI.devices[self.device.side or 'terminal'] = self end @@ -946,6 +933,7 @@ function UI.Device:resize() self.device.setTextScale(self.textScale) self.width, self.height = self.device.getSize() self.lines = { } + -- TODO: resize all pages added to this device self.canvas:resize(self.width, self.height) self.canvas:clear(self.backgroundColor, self.textColor) end @@ -997,11 +985,13 @@ function UI.Device:addTransition(effect, args) end function UI.Device:runTransitions(transitions, canvas) + --[[ for _,t in ipairs(transitions) do canvas:punch(t.args) -- punch out the effect areas end canvas:blitClipped(self.device) -- and blit the remainder canvas:reset() + ]] while true do for _,k in ipairs(Util.keys(transitions)) do @@ -1028,10 +1018,9 @@ function UI.Device:sync() self.device.setCursorBlink(false) end + self.canvas:render(self.device) if transitions then self:runTransitions(transitions, self.canvas) - else - self.canvas:render(self.device) end if self:getCursorBlink() then @@ -1126,16 +1115,23 @@ UI.Page.defaults = { function UI.Page:postInit() self.parent = self.parent or UI.defaultDevice self.__target = self + self.canvas = Canvas({ + x = 1, y = 1, width = self.parent.width, height = self.parent.height, + isColor = self.parent.isColor, + }) + self.canvas:clear(self.backgroundColor, self.textColor) end function UI.Page:setParent() UI.Window.setParent(self) + --[[ if self.z then self.canvas = self:addLayer(self.backgroundColor, self.textColor) self.canvas:clear(self.backgroundColor, self.textColor) else self.canvas = self.parent.canvas end + ]] end function UI.Page:enable() @@ -1154,6 +1150,12 @@ function UI.Page:disable() UI.Window.disable(self) end +function UI.Page:sync() + if self.enabled then + self.parent:sync() + end +end + function UI.Page:capture(child) self.__target = child end @@ -2293,9 +2295,9 @@ function UI.Tabs:eventHandler(event) if event.type == 'tab_change' then local tab = self:find(event.tab.tabUid) if event.current > event.last then - tab:addTransition('slideLeft') + self.transitionHint = 'slideLeft' else - tab:addTransition('slideRight') + self.transitionHint = 'slideRight' end for _,child in pairs(self.children) do @@ -2310,6 +2312,30 @@ function UI.Tabs:eventHandler(event) end end +--[[-- Tab --]]-- +UI.Tab = class(UI.Window) +UI.Tab.defaults = { + UIElement = 'Tab', + tabTitle = 'tab', + backgroundColor = colors.cyan, +} +function UI.Tab:setParent() + UI.Window.setParent(self) + self.canvas = self:addLayer() +end + +function UI.Tab:enable(...) + self.canvas:setVisible(true) + UI.Window.enable(self, ...) + self:addTransition(self.parent.transitionHint or 'slideLeft') + self:focusFirst() +end + +function UI.Tab:disable() + self.canvas:setVisible(false) + UI.Window.disable(self) +end + --[[-- Wizard --]]-- UI.Wizard = class(UI.Window) UI.Wizard.defaults = { @@ -3047,7 +3073,7 @@ function UI.Chooser:eventHandler(event) end end ---[[-- Chooser --]]-- +--[[-- Checkbox --]]-- UI.Checkbox = class(UI.Window) UI.Checkbox.defaults = { UIElement = 'Checkbox', @@ -3243,6 +3269,7 @@ UI.Form.defaults = { values = { }, margin = 2, event = 'form_complete', + cancelEvent = 'form_cancel', } function UI.Form:postInit() self:createForm() @@ -3319,7 +3346,7 @@ function UI.Form:createForm() table.insert(self.children, UI.Button { y = -self.margin, x = -7 - self.margin, text = 'Cancel', - event = 'form_cancel', + event = self.cancelEvent, }) end end @@ -3346,6 +3373,7 @@ function UI.Form:save() local s, m = self:validateField(child) if not s then self:setFocus(child) + Sound.play('entity.villager.no', .5) self:emit({ type = 'form_invalid', message = m, field = child }) return false end @@ -3372,7 +3400,7 @@ function UI.Form:eventHandler(event) if not self:save() then return false end - self:emit({ type = self.event, UIElement = self }) + self:emit({ type = self.event, UIElement = self, values = self.values }) else return UI.Window.eventHandler(self, event) end @@ -3380,49 +3408,38 @@ function UI.Form:eventHandler(event) end --[[-- Dialog --]]-- -UI.Dialog = class(UI.Page) +UI.Dialog = class(UI.SlideOut) UI.Dialog.defaults = { UIElement = 'Dialog', - x = 7, - y = 4, - z = 2, height = 7, textColor = colors.black, backgroundColor = colors.white, + okEvent ='dialog_ok', + cancelEvent = 'dialog_cancel', } function UI.Dialog:postInit() - self.titleBar = UI.TitleBar({ previousPage = true, title = self.title }) + self.y = -self.height + self.titleBar = UI.TitleBar({ event = self.cancelEvent, title = self.title }) end -function UI.Dialog:setParent() - if not self.width then - self.width = self.parent.width - 11 - end - if self.width > self.parent.width then - self.width = self.parent.width - end - self.x = math.floor((self.parent.width - self.width) / 2) + 1 - self.y = math.floor((self.parent.height - self.height) / 2) + 1 - UI.Page.setParent(self) +function UI.Dialog:show(...) + local canvas = self.parent:getCanvas() + self.oldPalette = canvas.palette + canvas:applyPalette(Canvas.darkPalette) + UI.SlideOut.show(self, ...) end -function UI.Dialog:disable() - self.previousPage.canvas.palette = self.oldPalette - UI.Page.disable(self) -end - -function UI.Dialog:enable(...) - self.oldPalette = self.previousPage.canvas.palette - self.previousPage.canvas:applyPalette(Canvas.darkPalette) - self:addTransition('grow') - UI.Page.enable(self, ...) +function UI.Dialog:hide(...) + self.parent:getCanvas().palette = self.oldPalette + UI.SlideOut.hide(self, ...) + self.parent:draw() end function UI.Dialog:eventHandler(event) - if event.type == 'cancel' then - UI:setPreviousPage() + if event.type == 'dialog_cancel' then + self:hide() end - return UI.Page.eventHandler(self, event) + return UI.SlideOut.eventHandler(self, event) end --[[-- Image --]]-- diff --git a/sys/apis/ui/transition.lua b/sys/apis/ui/transition.lua index 16e2127..f6c7af3 100644 --- a/sys/apis/ui/transition.lua +++ b/sys/apis/ui/transition.lua @@ -7,24 +7,14 @@ function Transition.slideLeft(args) local easing = args.easing or 'outQuint' local pos = { x = args.ex } local tween = Tween.new(ticks, pos, { x = args.x }, easing) - local lastScreen = args.canvas:copy() + + args.canvas:move(pos.x, args.canvas.y) return function(device) local finished = tween:update(1) - local x = math.floor(pos.x) - lastScreen:dirty() - lastScreen:blit(device, { - x = args.ex - x + args.x, - y = args.y, - ex = args.ex, - ey = args.ey }, - { x = args.x, y = args.y }) - args.canvas:blit(device, { - x = args.x, - y = args.y, - ex = args.ex - x + args.x, - ey = args.ey }, - { x = x, y = args.y }) + args.canvas:move(math.floor(pos.x), args.canvas.y) + args.canvas:dirty() + args.canvas:render(device) return not finished end end @@ -32,26 +22,16 @@ end function Transition.slideRight(args) local ticks = args.ticks or 6 local easing = args.easing or'outQuint' - local pos = { x = args.x } - local tween = Tween.new(ticks, pos, { x = args.ex }, easing) - local lastScreen = args.canvas:copy() + local pos = { x = -args.canvas.width } + local tween = Tween.new(ticks, pos, { x = 1 }, easing) + + args.canvas:move(pos.x, args.canvas.y) return function(device) local finished = tween:update(1) - local x = math.floor(pos.x) - lastScreen:dirty() - lastScreen:blit(device, { - x = args.x, - y = args.y, - ex = args.ex - x + args.x, - ey = args.ey }, - { x = x, y = args.y }) - args.canvas:blit(device, { - x = args.ex - x + args.x, - y = args.y, - ex = args.ex, - ey = args.ey }, - { x = args.x, y = args.y }) + args.canvas:move(math.floor(pos.x), args.canvas.y) + args.canvas:dirty() + args.canvas:render(device) return not finished end end @@ -62,27 +42,13 @@ function Transition.expandUp(args) local pos = { y = args.ey + 1 } local tween = Tween.new(ticks, pos, { y = args.y }, easing) - return function(device) - local finished = tween:update(1) - args.canvas:blit(device, nil, { x = args.x, y = math.floor(pos.y) }) - return not finished - end -end - -function Transition.grow(args) - local ticks = args.ticks or 3 - local easing = args.easing or 'linear' - local tween = Tween.new(ticks, - { x = args.width / 2 - 1, y = args.height / 2 - 1, w = 1, h = 1 }, - { x = 1, y = 1, w = args.width, h = args.height }, easing) + args.canvas:move(args.x, pos.y) return function(device) local finished = tween:update(1) - local subj = tween.subject - local rect = { x = math.floor(subj.x), y = math.floor(subj.y) } - rect.ex = math.floor(rect.x + subj.w - 1) - rect.ey = math.floor(rect.y + subj.h - 1) - args.canvas:blit(device, rect, { x = args.x + rect.x - 1, y = args.y + rect.y - 1}) + args.canvas:move(args.x, math.floor(pos.y)) + args.canvas:dirty() + args.canvas:render(device) return not finished end end diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 802b8b5..f209aa1 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -72,6 +72,31 @@ local page = UI.Page { autospace = true, }, }, + help = UI.SlideOut { + backgroundColor = colors.cyan, + x = 5, ex = -5, height = 8, y = -8, + titleBar = UI.TitleBar { + title = 'Network Help', + event = 'slide_hide', + }, + text = UI.TextArea { + x = 2, y = 2, + backgroundColor = colors.cyan, + value = [[ + +In order to connect to another computer: + +1. The target computer must have a password set (run 'password' from the shell prompt). + +2. From this computer, click trust and enter the password for that computer. + +This only needs to be done once. + ]], + }, + accelerators = { + q = 'slide_hide', + } + }, notification = UI.Notification { }, accelerators = { t = 'telnet', @@ -180,27 +205,9 @@ function page:eventHandler(event) sendCommand(t.id, 'shutdown') end end + if event.type == 'help' then - UI:setPage(UI.Dialog { - title = 'Network Help', - height = 10, - backgroundColor = colors.white, - text = UI.TextArea { - x = 2, y = 2, - backgroundColor = colors.white, - value = [[ -In order to connect to another computer: - - 1. The target computer must have a password set (run 'password' from the shell prompt). - 2. From this computer, click trust and enter the password for that computer. - -This only needs to be done once. - ]], - }, - accelerators = { - q = 'cancel', - } - }) + self.help:show() elseif event.type == 'ports' then self.ports.grid:update() diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 3bda2b1..8aa1cd8 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -106,6 +106,7 @@ local page = UI.Page { } }, editor = UI.SlideOut { + y = -12, height = 12, backgroundColor = colors.cyan, titleBar = UI.TitleBar { title = 'Edit Application', diff --git a/sys/apps/System.lua b/sys/apps/System.lua index 464f1f2..601edfe 100644 --- a/sys/apps/System.lua +++ b/sys/apps/System.lua @@ -8,7 +8,7 @@ UI:configure('System', ...) local systemPage = UI.Page { tabs = UI.Tabs { - settings = UI.Window { + settings = UI.Tab { tabTitle = 'Category', grid = UI.Grid { y = 2, diff --git a/sys/apps/system/aliases.lua b/sys/apps/system/aliases.lua index cdb38ca..0523f27 100644 --- a/sys/apps/system/aliases.lua +++ b/sys/apps/system/aliases.lua @@ -1,7 +1,7 @@ local Config = require('config') local UI = require('ui') -local aliasTab = UI.Window { +local aliasTab = UI.Tab { tabTitle = 'Aliases', description = 'Shell aliases', alias = UI.TextEntry { diff --git a/sys/apps/system/label.lua b/sys/apps/system/label.lua index 0d03425..7ed6f6f 100644 --- a/sys/apps/system/label.lua +++ b/sys/apps/system/label.lua @@ -4,7 +4,7 @@ local Util = require('util') local fs = _G.fs local os = _G.os -local labelTab = UI.Window { +local labelTab = UI.Tab { tabTitle = 'Label', description = 'Set the computer label', labelText = UI.Text { diff --git a/sys/apps/system/network.lua b/sys/apps/system/network.lua index 0b9737d..4f2199e 100644 --- a/sys/apps/system/network.lua +++ b/sys/apps/system/network.lua @@ -3,7 +3,7 @@ local UI = require('ui') local device = _G.device -local tab = UI.Window { +local tab = UI.Tab { tabTitle = 'Network', description = 'Networking options', form = UI.Form { @@ -40,7 +40,7 @@ function tab:enable() local config = Config.load('os') self.form.modem.value = config.wirelessModem or 'auto' - UI.Window.enable(self) + UI.Tab.enable(self) end function tab:eventHandler(event) diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua index 23524fd..4c45616 100644 --- a/sys/apps/system/password.lua +++ b/sys/apps/system/password.lua @@ -2,7 +2,7 @@ local Security = require('security') local SHA1 = require('sha1') local UI = require('ui') -local passwordTab = UI.Window { +local passwordTab = UI.Tab { tabTitle = 'Password', description = 'Wireless network password', oldPass = UI.TextEntry { diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index 5374634..f2a7c98 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -2,7 +2,7 @@ local Config = require('config') local UI = require('ui') local Util = require('util') -local pathTab = UI.Window { +local pathTab = UI.Tab { tabTitle = 'Path', description = 'Set the shell path', tabClose = true, diff --git a/sys/apps/system/settings.lua b/sys/apps/system/settings.lua index 2722dab..dc919ff 100644 --- a/sys/apps/system/settings.lua +++ b/sys/apps/system/settings.lua @@ -3,7 +3,6 @@ local UI = require('ui') local settings = _G.settings if settings then - local values = { } for _,v in pairs(settings.getNames()) do local value = settings.get(v) @@ -16,11 +15,11 @@ if settings then }) end - local settingsTab = UI.Window { + local settingsTab = UI.Tab { tabTitle = 'Settings', description = 'Computercraft configurable settings', grid = UI.Grid { - y = 1, + y = 2, values = values, autospace = true, sortColumn = 'name', diff --git a/sys/apps/system/turtle.lua b/sys/apps/system/turtle.lua index 18150de..fe6fadf 100644 --- a/sys/apps/system/turtle.lua +++ b/sys/apps/system/turtle.lua @@ -9,7 +9,7 @@ if turtle then local values = { } Config.load('gps', values.home and { values.home } or { }) - local gpsTab = UI.Window { + local gpsTab = UI.Tab { tabTitle = 'GPS', labelText = UI.Text { x = 3, y = 2, From 817c345672d934b98bd32cda08cbed1a426e99ab Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 30 Jan 2019 15:53:09 -0500 Subject: [PATCH 060/231] canvas use in UI overhaul --- sys/apis/ui.lua | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index d97df26..2842373 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -1122,18 +1122,6 @@ function UI.Page:postInit() self.canvas:clear(self.backgroundColor, self.textColor) end -function UI.Page:setParent() - UI.Window.setParent(self) - --[[ - if self.z then - self.canvas = self:addLayer(self.backgroundColor, self.textColor) - self.canvas:clear(self.backgroundColor, self.textColor) - else - self.canvas = self.parent.canvas - end - ]] -end - function UI.Page:enable() self.canvas.visible = true UI.Window.enable(self) @@ -1144,9 +1132,7 @@ function UI.Page:enable() end function UI.Page:disable() - if self.z then - self.canvas.visible = false - end + self.canvas.visible = false UI.Window.disable(self) end @@ -2318,21 +2304,22 @@ UI.Tab.defaults = { UIElement = 'Tab', tabTitle = 'tab', backgroundColor = colors.cyan, + y = 2, } function UI.Tab:setParent() UI.Window.setParent(self) - self.canvas = self:addLayer() + --self.canvas = self:addLayer() end function UI.Tab:enable(...) - self.canvas:setVisible(true) + --self.canvas:setVisible(true) UI.Window.enable(self, ...) - self:addTransition(self.parent.transitionHint or 'slideLeft') + --self:addTransition(self.parent.transitionHint or 'slideLeft') self:focusFirst() end function UI.Tab:disable() - self.canvas:setVisible(false) + --self.canvas:setVisible(false) UI.Window.disable(self) end From 89400ac1bd3dcf5befbe7b9e040b03ed1c346a5c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 30 Jan 2019 16:27:09 -0500 Subject: [PATCH 061/231] canvas use in UI overhaul --- sys/apis/ui.lua | 23 ++++++++++++++++++----- sys/apis/ui/canvas.lua | 9 +++++++-- sys/apps/Overview.lua | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 2842373..2e4597f 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -860,7 +860,17 @@ end function UI.Window:addLayer(bg, fg) local canvas = self:getCanvas() - canvas = canvas:addLayer(self, bg, fg) + local x, y = self.x, self.y + local parent = self.parent + while parent and not parent.canvas do + x = x + parent.x - 1 + y = y + parent.y - 1 + parent = parent.parent + end + canvas = canvas:addLayer({ + x = x, y = y, height = self.height, width = self.width + }, bg, fg) + canvas:clear(bg or self.backgroundColor, fg or self.textColor) return canvas end @@ -2263,6 +2273,7 @@ end function UI.Tabs:enable() self.enabled = true + self.transitionHint = nil self.tabBar:enable() local menuItem = Util.find(self.tabBar.children, 'selected', true) @@ -2308,18 +2319,20 @@ UI.Tab.defaults = { } function UI.Tab:setParent() UI.Window.setParent(self) - --self.canvas = self:addLayer() + self.canvas = self:addLayer() end function UI.Tab:enable(...) - --self.canvas:setVisible(true) + self.canvas:setVisible(true) UI.Window.enable(self, ...) - --self:addTransition(self.parent.transitionHint or 'slideLeft') + if self.parent.transitionHint then + self:addTransition(self.parent.transitionHint) + end self:focusFirst() end function UI.Tab:disable() - --self.canvas:setVisible(false) + self.canvas:setVisible(false) UI.Window.disable(self) end diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index ea45ecf..5e0ed5b 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -111,9 +111,9 @@ end function Canvas:setVisible(visible) self.visible = visible - if not visible then + if not visible and self.parent then self.parent:dirty() - -- set parent's lines to dirty for each line in self + -- TODO: set parent's lines to dirty for each line in self end end @@ -244,6 +244,11 @@ function Canvas:dirty() for _, line in pairs(self.lines) do line.dirty = true end + if self.layers then + for _, canvas in pairs(self.layers) do + canvas:dirty() + end + end end function Canvas:clean() diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 8aa1cd8..2fb9871 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -545,7 +545,7 @@ function page.editor:eventHandler(event) elseif event.type == 'form_complete' then local values = self.form.values - UI:setPreviousPage() + self:hide() self:updateApplications(values) --page:refresh() --page:draw() From 915085ac5f734a89dbcee81bdd2c53a23d1b5459 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 5 Feb 2019 23:03:57 -0500 Subject: [PATCH 062/231] ui overhaul --- sys/apis/class.lua | 3 + sys/apis/terminal.lua | 331 ++- sys/apis/ui.lua | 2400 +-------------------- sys/apis/ui/canvas.lua | 289 +-- sys/apis/ui/components/ActiveLayer.lua | 30 + sys/apis/ui/components/Button.lua | 66 + sys/apis/ui/components/Checkbox.lua | 67 + sys/apis/ui/components/Chooser.lua | 88 + sys/apis/ui/components/Dialog.lua | 39 + sys/apis/ui/components/DropMenu.lua | 71 + sys/apis/ui/components/DropMenuItem.lua | 21 + sys/apis/ui/components/Embedded.lua | 69 + sys/apis/ui/components/Form.lua | 149 ++ sys/apis/ui/components/Grid.lua | 492 +++++ sys/apis/ui/components/Image.lua | 40 + sys/apis/ui/components/Menu.lua | 60 + sys/apis/ui/components/MenuBar.lua | 92 + sys/apis/ui/components/MenuItem.lua | 14 + sys/apis/ui/components/NftImage.lua | 33 + sys/apis/ui/components/Notification.lua | 67 + sys/apis/ui/components/ProgressBar.lua | 18 + sys/apis/ui/components/ScrollBar.lua | 74 + sys/apis/ui/components/ScrollingGrid.lua | 60 + sys/apis/ui/components/SlideOut.lua | 51 + sys/apis/ui/components/StatusBar.lua | 99 + sys/apis/ui/components/Tab.lua | 12 + sys/apis/ui/components/TabBar.lua | 45 + sys/apis/ui/components/TabBarMenuItem.lua | 25 + sys/apis/ui/components/Tabs.lua | 89 + sys/apis/ui/components/Text.lua | 20 + sys/apis/ui/components/TextArea.lua | 36 + sys/apis/ui/components/TextEntry.lua | 189 ++ sys/apis/ui/components/Throttle.lua | 65 + sys/apis/ui/components/TitleBar.lua | 73 + sys/apis/ui/components/VerticalMeter.lua | 18 + sys/apis/ui/components/Viewport.lua | 96 + sys/apis/ui/components/Wizard.lua | 124 ++ sys/apis/ui/components/WizardPage.lua | 11 + sys/apis/ui/transition.lua | 13 +- sys/apps/Installer.lua | 457 ---- sys/apps/Lua.lua | 2 + sys/apps/Overview.lua | 15 +- sys/apps/PackageManager.lua | 13 +- sys/apps/Welcome.lua | 8 +- sys/apps/shell | 26 +- sys/autorun/log.lua | 12 +- sys/kernel.lua | 6 +- 47 files changed, 2879 insertions(+), 3199 deletions(-) create mode 100644 sys/apis/ui/components/ActiveLayer.lua create mode 100644 sys/apis/ui/components/Button.lua create mode 100644 sys/apis/ui/components/Checkbox.lua create mode 100644 sys/apis/ui/components/Chooser.lua create mode 100644 sys/apis/ui/components/Dialog.lua create mode 100644 sys/apis/ui/components/DropMenu.lua create mode 100644 sys/apis/ui/components/DropMenuItem.lua create mode 100644 sys/apis/ui/components/Embedded.lua create mode 100644 sys/apis/ui/components/Form.lua create mode 100644 sys/apis/ui/components/Grid.lua create mode 100644 sys/apis/ui/components/Image.lua create mode 100644 sys/apis/ui/components/Menu.lua create mode 100644 sys/apis/ui/components/MenuBar.lua create mode 100644 sys/apis/ui/components/MenuItem.lua create mode 100644 sys/apis/ui/components/NftImage.lua create mode 100644 sys/apis/ui/components/Notification.lua create mode 100644 sys/apis/ui/components/ProgressBar.lua create mode 100644 sys/apis/ui/components/ScrollBar.lua create mode 100644 sys/apis/ui/components/ScrollingGrid.lua create mode 100644 sys/apis/ui/components/SlideOut.lua create mode 100644 sys/apis/ui/components/StatusBar.lua create mode 100644 sys/apis/ui/components/Tab.lua create mode 100644 sys/apis/ui/components/TabBar.lua create mode 100644 sys/apis/ui/components/TabBarMenuItem.lua create mode 100644 sys/apis/ui/components/Tabs.lua create mode 100644 sys/apis/ui/components/Text.lua create mode 100644 sys/apis/ui/components/TextArea.lua create mode 100644 sys/apis/ui/components/TextEntry.lua create mode 100644 sys/apis/ui/components/Throttle.lua create mode 100644 sys/apis/ui/components/TitleBar.lua create mode 100644 sys/apis/ui/components/VerticalMeter.lua create mode 100644 sys/apis/ui/components/Viewport.lua create mode 100644 sys/apis/ui/components/Wizard.lua create mode 100644 sys/apis/ui/components/WizardPage.lua delete mode 100644 sys/apps/Installer.lua diff --git a/sys/apis/class.lua b/sys/apis/class.lua index f01a9e0..bb94b63 100644 --- a/sys/apis/class.lua +++ b/sys/apis/class.lua @@ -7,6 +7,9 @@ return function(base) local c = { } -- a new class instance if type(base) == 'table' then -- our new class is a shallow copy of the base class! + if base._preload then + base = base._preload(base) + end for i,v in pairs(base) do c[i] = v end diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index fbc860c..fc9f49f 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -1,205 +1,202 @@ +local Canvas = require('ui.canvas') + local colors = _G.colors local term = _G.term local _gsub = string.gsub -local _rep = string.rep -local _sub = string.sub local Terminal = { } --- add scrolling functions to a window -function Terminal.scrollable(win, maxScroll) - local lines = { } - local scrollPos = 0 - local oblit, oreposition = win.blit, win.reposition - - local palette = { } - for n = 1, 16 do - palette[2 ^ (n - 1)] = _sub("0123456789abcdef", n, n) +-- Replacement for window api with scrolling and buffering +function Terminal.window(parent, sx, sy, w, h, isVisible) + isVisible = isVisible ~= false + if not w or not h then + w, h = parent.getSize() end - maxScroll = maxScroll or 100 + local win = { } + local maxScroll = 100 + local cx, cy = 1, 1 + local blink = false + local bg, fg = parent.getBackgroundColor(), parent.getTextColor() - -- should only do if window is visible... - local function redraw() - local _, h = win.getSize() - local x, y = win.getCursorPos() - for i = 1, h do - local line = lines[i + scrollPos] - if line and line.dirty then - win.setCursorPos(1, i) - oblit(line.text, line.fg, line.bg) - line.dirty = false - end - end - win.setCursorPos(x, y) - end + local canvas = Canvas({ + x = sx, + y = sy, + width = w, + height = h, + isColor = parent.isColor(), + }) + canvas.offy = 0 - local function scrollTo(p, forceRedraw) - local _, h = win.getSize() - local ms = #lines - h -- max scroll - p = math.min(math.max(p, 0), ms) -- normalize - - if p ~= scrollPos or forceRedraw then - scrollPos = p - for _, line in pairs(lines) do - line.dirty = true - end + local function update() + if isVisible then + canvas:render(parent) + win.setCursorPos(cx, cy) end end - function win.write(text) - local _, h = win.getSize() + local function scrollTo(y) + y = math.max(0, y) + y = math.min(#canvas.lines - canvas.height, y) - text = tostring(text) or '' - scrollTo(#lines - h) - win.blit(text, - _rep(palette[win.getTextColor()], #text), - _rep(palette[win.getBackgroundColor()], #text)) - local x, y = win.getCursorPos() - win.setCursorPos(x + #text, y) - end - - function win.clearLine() - local w, h = win.getSize() - local _, y = win.getCursorPos() - - scrollTo(#lines - h) - lines[y + scrollPos] = { - text = _rep(' ', w), - fg = _rep(palette[win.getTextColor()], w), - bg = _rep(palette[win.getBackgroundColor()], w), - dirty = true, - } - redraw() - end - - function win.blit(text, fg, bg) - local x, y = win.getCursorPos() - local w, h = win.getSize() - - if y > 0 and y <= h and x <= w then - local width = #text - - -- fix ffs - if x < 1 then - text = _sub(text, 2 - x) - if bg then - bg = _sub(bg, 2 - x) - end - if bg then - fg = _sub(fg, 2 - x) - end - width = width + x - 1 - x = 1 - end - - if x + width - 1 > w then - text = _sub(text, 1, w - x + 1) - if bg then - bg = _sub(bg, 1, w - x + 1) - end - if bg then - fg = _sub(fg, 1, w - x + 1) - end - width = #text - end - - if width > 0 then - local function replace(sstr, pos, rstr) - if pos == 1 and width == w then - return rstr - elseif pos == 1 then - return rstr .. _sub(sstr, pos+width) - elseif pos + width > w then - return _sub(sstr, 1, pos-1) .. rstr - end - return _sub(sstr, 1, pos-1) .. rstr .. _sub(sstr, pos+width) - end - - local line = lines[y + scrollPos] - line.dirty = true - line.text = replace(line.text, x, text, width) - if fg then - line.fg = replace(line.fg, x, fg, width) - end - if bg then - line.bg = replace(line.bg, x, bg, width) - end - end + if y ~= canvas.offy then + canvas.offy = y + canvas:dirty() + update() end - redraw() + end + + function win.write(str) + str = tostring(str) or '' + canvas:write(cx, cy + canvas.offy, str, bg, fg) + win.setCursorPos(cx + #str, cy) + update() + end + + function win.blit(str, fg, bg) + canvas:blit(cx, cy + canvas.offy, str, bg, fg) + win.setCursorPos(cx + #str, cy) + update() end function win.clear() - local w, h = win.getSize() - - local text = _rep(' ', w) - local fg = _rep(palette[win.getTextColor()], w) - local bg = _rep(palette[win.getBackgroundColor()], w) - lines = { } - for y = 1, h do - lines[y] = { - dirty = true, - text = text, - fg = fg, - bg = bg, - } + canvas.offy = 0 + canvas:clear(bg, fg) + for i = #canvas.lines, canvas.height + 1, -1 do + canvas.lines[i] = nil end - scrollPos = 0 - redraw() + update() + end + + function win.clearLine() + canvas:clearLine(cy, bg, fg) + win.setCursorPos(cx, cy) + update() + end + + function win.getCursorPos() + return cx, cy + end + + function win.setCursorPos(x, y) + cx, cy = x, y + parent.setCursorPos(x + canvas.x - 1, y + canvas.y - 1) + end + + function win.setCursorBlink(b) + blink = b + parent.setCursorBlink(b) + end + + function win.isColor() + return canvas.isColor + end + win.isColour = win.isColor + + function win.setTextColor(c) + fg = c + end + win.setTextColour = win.setTextColor + + function win.setBackgroundColor(c) + bg = c + end + win.setBackgroundColour = win.setBackgroundColor + + function win.getSize() + return canvas.width, canvas.height end - -- doesn't support negative scrolling... function win.scroll(n) - local w = win.getSize() - - for _ = 1, n do - lines[#lines + 1] = { - text = _rep(' ', w), - fg = _rep(palette[win.getTextColor()], w), - bg = _rep(palette[win.getBackgroundColor()], w), - } + n = n or 1 + if n > 0 then + for _ = 1, n do + canvas.lines[#canvas.lines + 1] = { } + canvas:clearLine(#canvas.lines, bg, fg) + end + while #canvas.lines > maxScroll do + table.remove(canvas.lines, 1) + end + scrollTo(#canvas.lines - canvas.height) + canvas.offy = #canvas.lines - canvas.height + canvas:dirty() + update() end + end - while #lines > maxScroll do - table.remove(lines, 1) + function win.getTextColor() + return fg + end + win.getTextColour = win.getTextColor + + function win.getBackgroundColor() + return bg + end + win.getBackgroundColour = win.getBackgroundColor + + function win.setVisible(visible) + if visible ~= isVisible then + isVisible = visible + if isVisible then + canvas:dirty() + update() + end end + end - scrollTo(maxScroll, true) - redraw() + function win.redraw() + if isVisible then + canvas:dirty() + canvas:render(parent) + end + end + + function win.restoreCursor() + win.setCursorPos(cx, cy) + win.setCursorBlink(blink) + end + + function win.getPosition() + return canvas.x, canvas.y + end + + function win.reposition(x, y, width, height) + canvas.x, canvas.y = x, y + canvas:resize(width or canvas.width, height or canvas.height) + end + + --[[ Additional methods ]]-- + function win.scrollDown() + scrollTo(canvas.offy + 1) end function win.scrollUp() - scrollTo(scrollPos - 1) - redraw() + scrollTo(canvas.offy - 1) end - function win.scrollDown() - scrollTo(scrollPos + 1) - redraw() + function win.scrollTop() + scrollTo(0) end - function win.reposition(x, y, nw, nh) - local w, h = win.getSize() - local D = (nh or h) - h - - if D > 0 then - for _ = 1, D do - lines[#lines + 1] = { - text = _rep(' ', w), - fg = _rep(palette[win.getTextColor()], w), - bg = _rep(palette[win.getBackgroundColor()], w), - } - end - elseif D < 0 then - for _ = D, -1 do - lines[#lines] = nil - end - end - return oreposition(x, y, nw, nh) + function win.scrollBottom() + scrollTo(#canvas.lines) end - win.clear() + function win.setMaxScroll(ms) + maxScroll = ms + end + + function win.getCanvas() + return canvas + end + + function win.getParent() + return parent + end + + canvas:clear() + + return win end -- get windows contents diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 2e4597f..36e4bc1 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -3,7 +3,6 @@ local class = require('class') local Event = require('event') local Input = require('input') local Peripheral = require('peripheral') -local Sound = require('sound') local Transition = require('ui.transition') local Util = require('util') @@ -14,7 +13,6 @@ local device = _G.device local fs = _G.fs local os = _G.os local term = _G.term -local window = _G.window --[[ Using the shorthand window definition, elements are created from @@ -23,14 +21,6 @@ local window = _G.window On :init(), elements do not know the parent or can calculate sizing. ]] -local function safeValue(v) - local t = type(v) - if t == 'string' or t == 'number' then - return v - end - return tostring(v) -end - -- need to add offsets to this test local function getPosition(element) local x, y = 1, 1 @@ -225,11 +215,7 @@ function Manager:loadTheme(filename) if not theme then error(err) end - for k,v in pairs(theme) do - if self[k] and self[k].defaults then - Util.merge(self[k].defaults, v) - end - end + self.theme = theme end end @@ -479,7 +465,7 @@ function UI.Window:initChildren() end end -local function setSize(self) +function UI.Window:layout() if self.x < 0 then self.x = self.parent.width + self.x + 1 end @@ -525,7 +511,7 @@ function UI.Window:setParent() self.oh, self.ow = self.height, self.width self.ox, self.oy = self.x, self.y - setSize(self) + self:layout() self:initChildren() end @@ -534,7 +520,7 @@ function UI.Window:resize() self.height, self.width = self.oh, self.ow self.x, self.y = self.ox, self.oy - setSize(self) + self:layout() if self.children then for _,child in ipairs(self.children) do @@ -626,13 +612,13 @@ end function UI.Window:write(x, y, text, bg, tc) bg = bg or self.backgroundColor tc = tc or self.textColor - -- TODO: get rid of offx/y - scroll canvas instead - x = x - self.offx - y = y - self.offy - if y <= self.height and y > 0 then - if self.canvas then - self.canvas:write(x, y, text, bg, tc) - else + + if self.canvas then + self.canvas:write(x, y, text, bg, tc) + else + x = x - self.offx + y = y - self.offy + if y <= self.height and y > 0 then self.parent:write( self.x + x - 1, self.y + y - 1, tostring(text), bg, tc) end @@ -759,6 +745,7 @@ function UI.Window:release(child) end function UI.Window:pointToChild(x, y) + -- TODO: get rid of this offx/y mess and scroll canvas instead x = x + self.offx - self.x + 1 y = y + self.offy - self.y + 1 if self.children then @@ -790,13 +777,13 @@ function UI.Window:getFocusables() return a.y < b.y end - local function getFocusable(parent, x, y) + local function getFocusable(parent) for _,child in Util.spairs(parent.children, focusSort) do if child.enabled and child.focus and not child.inactive then table.insert(focusable, child) end if child.children then - getFocusable(child, child.x + x, child.y + y) + getFocusable(child) end end end @@ -907,7 +894,7 @@ function UI.Window:find(uid) end end -function UI.Window:eventHandler(event) +function UI.Window:eventHandler() return false end @@ -995,21 +982,14 @@ function UI.Device:addTransition(effect, args) end function UI.Device:runTransitions(transitions, canvas) - --[[ - for _,t in ipairs(transitions) do - canvas:punch(t.args) -- punch out the effect areas - end - canvas:blitClipped(self.device) -- and blit the remainder - canvas:reset() - ]] - while true do for _,k in ipairs(Util.keys(transitions)) do local transition = transitions[k] - if not transition.update(self.device) then + if not transition.update() then transitions[k] = nil end end + canvas:render(self.device) if Util.empty(transitions) then break end @@ -1018,11 +998,8 @@ function UI.Device:runTransitions(transitions, canvas) end function UI.Device:sync() - local transitions - if self.transitions and self.effectsEnabled then - transitions = self.transitions - self.transitions = nil - end + local transitions = self.effectsEnabled and self.transitions + self.transitions = nil if self:getCursorBlink() then self.device.setCursorBlink(false) @@ -1039,75 +1016,6 @@ function UI.Device:sync() end end ---[[-- StringBuffer --]]-- --- justs optimizes string concatenations -UI.StringBuffer = class() -function UI.StringBuffer:init(bufSize) - self.bufSize = bufSize - self.buffer = {} -end - -function UI.StringBuffer:insert(s, width) - local len = #tostring(s or '') - if len > width then - s = _sub(s, 1, width) - end - table.insert(self.buffer, s) - if len < width then - table.insert(self.buffer, _rep(' ', width - len)) - end -end - -function UI.StringBuffer:insertRight(s, width) - local len = #tostring(s or '') - if len > width then - s = _sub(s, 1, width) - end - if len < width then - table.insert(self.buffer, _rep(' ', width - len)) - end - table.insert(self.buffer, s) -end - -function UI.StringBuffer:get(sep) - return Util.widthify(table.concat(self.buffer, sep or ''), self.bufSize) -end - -function UI.StringBuffer:clear() - self.buffer = { } -end - --- For manipulating text in a fixed width string -local SB = { } -function SB:new(width) - return setmetatable({ - width = width, - buf = _rep(' ', width) - }, { __index = SB }) -end -function SB:insert(x, str, width) - if x < 1 then - x = self.width + x + 1 - end - width = width or #str - if x + width - 1 > self.width then - width = self.width - x - end - if width > 0 then - self.buf = _sub(self.buf, 1, x - 1) .. _sub(str, 1, width) .. _sub(self.buf, x + width) - end -end -function SB:fill(x, ch, width) - width = width or self.width - x + 1 - self:insert(x, _rep(ch, width)) -end -function SB:center(str) - self:insert(math.max(1, math.ceil((self.width - #str + 1) / 2)), str) -end -function SB:get() - return self.buf -end - --[[-- Page (focus manager) --]]-- UI.Page = class(UI.Window) UI.Page.defaults = { @@ -1251,2267 +1159,39 @@ function UI.Page:eventHandler(event) end end ---[[-- Grid --]]-- -UI.Grid = class(UI.Window) -UI.Grid.defaults = { - UIElement = 'Grid', - index = 1, - inverseSort = false, - disableHeader = false, - headerHeight = 1, - marginRight = 0, - textColor = colors.white, - textSelectedColor = colors.white, - backgroundColor = colors.black, - backgroundSelectedColor = colors.gray, - headerBackgroundColor = colors.cyan, - headerTextColor = colors.white, - headerSortColor = colors.yellow, - unfocusedTextSelectedColor = colors.white, - unfocusedBackgroundSelectedColor = colors.gray, - focusIndicator = '>', - sortIndicator = ' ', - inverseSortIndicator = '^', - values = { }, - columns = { }, - accelerators = { - enter = 'key_enter', - [ 'control-c' ] = 'copy', - down = 'scroll_down', - up = 'scroll_up', - home = 'scroll_top', - [ 'end' ] = 'scroll_bottom', - pageUp = 'scroll_pageUp', - [ 'control-b' ] = 'scroll_pageUp', - pageDown = 'scroll_pageDown', - [ 'control-f' ] = 'scroll_pageDown', - }, -} -function UI.Grid:setParent() - UI.Window.setParent(self) - - for _,c in pairs(self.columns) do - c.cw = c.width - if not c.heading then - c.heading = '' +local function loadComponents() + local function load(name) + local s, m = Util.run(_ENV, 'sys/apis/ui/components/' .. name .. '.lua') + if not s then + error(m) end - end - - self:update() - - if not self.pageSize then - if self.disableHeader then - self.pageSize = self.height - else - self.pageSize = self.height - self.headerHeight + if UI[name]._preload then + error('Error loading UI.' .. name) end - end -end - -function UI.Grid:resize() - UI.Window.resize(self) - - if self.disableHeader then - self.pageSize = self.height - else - self.pageSize = self.height - self.headerHeight - end - self:adjustWidth() -end - -function UI.Grid:adjustWidth() - local t = { } -- cols without width - local w = self.width - #self.columns - 1 - self.marginRight -- width remaining - - for _,c in pairs(self.columns) do - if c.width then - c.cw = c.width - w = w - c.cw - else - table.insert(t, c) + if UI.theme[name] and UI[name].defaults then + Util.merge(UI[name].defaults, UI.theme[name]) end + return UI[name] end - if #t == 0 then - return - end + local components = fs.list('sys/apis/ui/components') + for _, f in pairs(components) do + local name = f:match('(.+)%.') - if #t == 1 then - t[1].cw = #(t[1].heading or '') - t[1].cw = math.max(t[1].cw, w) - return - end - - if not self.autospace then - for k,c in ipairs(t) do - c.cw = math.floor(w / (#t - k + 1)) - w = w - c.cw - end - - else - for _,c in ipairs(t) do - c.cw = #(c.heading or '') - w = w - c.cw - end - -- adjust the size to the length of the value - for key,row in pairs(self.values) do - if w <= 0 then - break + UI[name] = setmetatable({ }, { + __call = function(self, ...) + load(name) + setmetatable(self, getmetatable(UI[name])) + return self(...) end - row = self:getDisplayValues(row, key) - for _,col in pairs(t) do - local value = row[col.key] - if value then - value = tostring(value) - if #value > col.cw then - w = w + col.cw - col.cw = math.min(#value, w) - w = w - col.cw - if w <= 0 then - break - end - end - end - end - end - - -- last column does not get padding (right alignment) - if not self.columns[#self.columns].width then - Util.removeByValue(t, self.columns[#self.columns]) - end - - -- got some extra room - add some padding - if w > 0 then - for k,c in ipairs(t) do - local padding = math.floor(w / (#t - k + 1)) - c.cw = c.cw + padding - w = w - padding - end - end - end -end - -function UI.Grid:setPageSize(pageSize) - self.pageSize = pageSize -end - -function UI.Grid:getValues() - return self.values -end - -function UI.Grid:setValues(t) - self.values = t - self:update() -end - -function UI.Grid:setInverseSort(inverseSort) - self.inverseSort = inverseSort - self:update() - self:setIndex(self.index) -end - -function UI.Grid:setSortColumn(column) - self.sortColumn = column -end - -function UI.Grid:getDisplayValues(row, key) - return row -end - -function UI.Grid:getSelected() - if self.sorted then - return self.values[self.sorted[self.index]], self.sorted[self.index] - end -end - -function UI.Grid:setSelected(name, value) - if self.sorted then - for k,v in pairs(self.sorted) do - if self.values[v][name] == value then - self:setIndex(k) - return - end - end - end - self:setIndex(1) -end - -function UI.Grid:focus() - self:drawRows() -end - -function UI.Grid:draw() - if not self.disableHeader then - self:drawHeadings() - end - - if self.index <= 0 then - self:setIndex(1) - elseif self.index > #self.sorted then - self:setIndex(#self.sorted) - end - self:drawRows() -end - --- Something about the displayed table has changed --- resort the table -function UI.Grid:update() - local function sort(a, b) - if not a[self.sortColumn] then - return false - elseif not b[self.sortColumn] then - return true - end - return self:sortCompare(a, b) - end - - local function inverseSort(a, b) - return not sort(a, b) - end - - local order - if self.sortColumn then - order = sort - if self.inverseSort then - order = inverseSort - end - end - - self.sorted = Util.keys(self.values) - if order then - table.sort(self.sorted, function(a,b) - return order(self.values[a], self.values[b]) - end) - end - - self:adjustWidth() -end - -function UI.Grid:drawHeadings() - local x = 1 - local sb = UI.StringBuffer(self.width) - for _,col in ipairs(self.columns) do - local ind = ' ' - if col.key == self.sortColumn then - if self.inverseSort then - ind = self.inverseSortIndicator - else - ind = self.sortIndicator - end - end - sb:insert(ind .. col.heading, col.cw + 1) - --[[ - self:write(x, - 1, - Util.widthify(ind .. col.heading, col.cw + 1), - self.headerBackgroundColor, - col.key == self.sortColumn and self.headerSortColor or self.headerTextColor) - x = x + col.cw + 1 - ]] - end - local y = math.ceil(self.headerHeight / 2) - if self.headerHeight > 1 then - self:clear(self.headerBackgroundColor) - end - self:write(1, y, sb:get(), self.headerBackgroundColor, self.headerTextColor) -end - -function UI.Grid:sortCompare(a, b) - a = safeValue(a[self.sortColumn]) - b = safeValue(b[self.sortColumn]) - if type(a) == type(b) then - return a < b - end - return tostring(a) < tostring(b) -end - -function UI.Grid:drawRows() - local y = 1 - local startRow = math.max(1, self:getStartRow()) - local sb = UI.StringBuffer(self.width) - - if not self.disableHeader then - y = y + self.headerHeight - end - - local lastRow = math.min(startRow + self.pageSize - 1, #self.sorted) - for index = startRow, lastRow do - - local sindex = self.sorted[index] - local rawRow = self.values[sindex] - local key = sindex - local row = self:getDisplayValues(rawRow, key) - - sb:clear() - - local ind = ' ' - if self.focused and index == self.index and not self.inactive then - ind = self.focusIndicator - end - - for _,col in pairs(self.columns) do - if col.justify == 'right' then - sb:insertRight(ind .. safeValue(row[col.key] or ''), col.cw + 1) - else - sb:insert(ind .. safeValue(row[col.key] or ''), col.cw + 1) - end - ind = ' ' - end - - local selected = index == self.index and not self.inactive - - self:write(1, y, sb:get(), - self:getRowBackgroundColor(rawRow, selected), - self:getRowTextColor(rawRow, selected)) - - y = y + 1 - end - - if y <= self.height then - self:clearArea(1, y, self.width, self.height - y + 1) - end -end - -function UI.Grid:getRowTextColor(row, selected) - if selected then - if self.focused then - return self.textSelectedColor - end - return self.unfocusedTextSelectedColor - end - return self.textColor -end - -function UI.Grid:getRowBackgroundColor(row, selected) - if selected then - if self.focused then - return self.backgroundSelectedColor - end - return self.unfocusedBackgroundSelectedColor - end - return self.backgroundColor -end - -function UI.Grid:getIndex() - return self.index -end - -function UI.Grid:setIndex(index) - index = math.max(1, index) - self.index = math.min(index, #self.sorted) - - local selected = self:getSelected() - if selected ~= self.selected then - self:drawRows() - self.selected = selected - if selected then - self:emit({ type = 'grid_focus_row', selected = selected, element = self }) - end - end -end - -function UI.Grid:getStartRow() - return math.floor((self.index - 1) / self.pageSize) * self.pageSize + 1 -end - -function UI.Grid:getPage() - return math.floor(self.index / self.pageSize) + 1 -end - -function UI.Grid:getPageCount() - local tableSize = Util.size(self.values) - local pc = math.floor(tableSize / self.pageSize) - if tableSize % self.pageSize > 0 then - pc = pc + 1 - end - return pc -end - -function UI.Grid:nextPage() - self:setPage(self:getPage() + 1) -end - -function UI.Grid:previousPage() - self:setPage(self:getPage() - 1) -end - -function UI.Grid:setPage(pageNo) - -- 1 based paging - self:setIndex((pageNo-1) * self.pageSize + 1) -end - -function UI.Grid:eventHandler(event) - if event.type == 'mouse_click' or - event.type == 'mouse_rightclick' or - event.type == 'mouse_doubleclick' then - if not self.disableHeader then - if event.y <= self.headerHeight then - local col = 2 - for _,c in ipairs(self.columns) do - if event.x < col + c.cw then - self:emit({ - type = 'grid_sort', - sortColumn = c.key, - inverseSort = self.sortColumn == c.key and not self.inverseSort, - element = self, - }) - break - end - col = col + c.cw + 1 - end - return true - end - end - local row = self:getStartRow() + event.y - 1 - if not self.disableHeader then - row = row - self.headerHeight - end - if row > 0 and row <= Util.size(self.values) then - self:setIndex(row) - if event.type == 'mouse_doubleclick' then - self:emit({ type = 'key_enter' }) - elseif event.type == 'mouse_rightclick' then - self:emit({ type = 'grid_select_right', selected = self.selected, element = self }) - end - return true - end - return false - - elseif event.type == 'grid_sort' then - self.sortColumn = event.sortColumn - self:setInverseSort(event.inverseSort) - self:draw() - elseif event.type == 'scroll_down' then - self:setIndex(self.index + 1) - elseif event.type == 'scroll_up' then - self:setIndex(self.index - 1) - elseif event.type == 'scroll_top' then - self:setIndex(1) - elseif event.type == 'scroll_bottom' then - self:setIndex(Util.size(self.values)) - elseif event.type == 'scroll_pageUp' then - self:setIndex(self.index - self.pageSize) - elseif event.type == 'scroll_pageDown' then - self:setIndex(self.index + self.pageSize) - elseif event.type == 'key_enter' then - if self.selected then - self:emit({ type = 'grid_select', selected = self.selected, element = self }) - end - elseif event.type == 'copy' then - if self.selected then - os.queueEvent('clipboard_copy', self.selected) - end - else - return false - end - return true -end - ---[[-- ScrollingGrid --]]-- -UI.ScrollingGrid = class(UI.Grid) -UI.ScrollingGrid.defaults = { - UIElement = 'ScrollingGrid', - scrollOffset = 0, - marginRight = 1, -} -function UI.ScrollingGrid:postInit() - self.scrollBar = UI.ScrollBar() -end - -function UI.ScrollingGrid:drawRows() - UI.Grid.drawRows(self) - self.scrollBar:draw() -end - -function UI.ScrollingGrid:getViewArea() - local y = 1 - if not self.disableHeader then - y = y + self.headerHeight - end - return { - static = true, -- the container doesn't scroll - y = y, -- scrollbar Y - height = self.pageSize, -- viewable height - totalHeight = Util.size(self.values), -- total height - offsetY = self.scrollOffset, -- scroll offset - } -end - -function UI.ScrollingGrid:getStartRow() - local ts = Util.size(self.values) - if ts < self.pageSize then - self.scrollOffset = 0 - end - return self.scrollOffset + 1 -end - -function UI.ScrollingGrid:setIndex(index) - if index < self.scrollOffset + 1 then - self.scrollOffset = index - 1 - elseif index - self.scrollOffset > self.pageSize then - self.scrollOffset = index - self.pageSize - end - - if self.scrollOffset < 0 then - self.scrollOffset = 0 - else - local ts = Util.size(self.values) - if self.pageSize + self.scrollOffset + 1 > ts then - self.scrollOffset = math.max(0, ts - self.pageSize) - end - end - UI.Grid.setIndex(self, index) -end - ---[[-- Menu --]]-- -UI.Menu = class(UI.Grid) -UI.Menu.defaults = { - UIElement = 'Menu', - disableHeader = true, - columns = { { heading = 'Prompt', key = 'prompt', width = 20 } }, -} -function UI.Menu:postInit() - self.values = self.menuItems - self.pageSize = #self.menuItems -end - -function UI.Menu:setParent() - UI.Grid.setParent(self) - self.itemWidth = 1 - for _,v in pairs(self.values) do - if #v.prompt > self.itemWidth then - self.itemWidth = #v.prompt - end - end - self.columns[1].width = self.itemWidth - - if self.centered then - self:center() - else - self.width = self.itemWidth + 2 - end -end - -function UI.Menu:center() - self.x = (self.width - self.itemWidth + 2) / 2 - self.width = self.itemWidth + 2 -end - -function UI.Menu:eventHandler(event) - if event.type == 'key' then - if event.key == 'enter' then - local selected = self.menuItems[self.index] - self:emit({ - type = selected.event or 'menu_select', - selected = selected - }) - return true - end - elseif event.type == 'mouse_click' then - if event.y <= #self.menuItems then - UI.Grid.setIndex(self, event.y) - local selected = self.menuItems[self.index] - self:emit({ - type = selected.event or 'menu_select', - selected = selected - }) - return true - end - end - return UI.Grid.eventHandler(self, event) -end - ---[[-- Viewport --]]-- -UI.Viewport = class(UI.Window) -UI.Viewport.defaults = { - UIElement = 'Viewport', - backgroundColor = colors.cyan, - accelerators = { - down = 'scroll_down', - up = 'scroll_up', - home = 'scroll_top', - [ 'end' ] = 'scroll_bottom', - pageUp = 'scroll_pageUp', - [ 'control-b' ] = 'scroll_pageUp', - pageDown = 'scroll_pageDown', - [ 'control-f' ] = 'scroll_pageDown', - }, -} -function UI.Viewport:setScrollPosition(offset) - local oldOffset = self.offy - self.offy = math.max(offset, 0) - local max = self.ymax or self.height - if self.children then - for _, child in ipairs(self.children) do - if child ~= self.scrollBar then -- hack ! - max = math.max(child.y + child.height - 1, max) - end - end - end - self.offy = math.min(self.offy, math.max(max, self.height) - self.height) - if self.offy ~= oldOffset then - self:draw() - end -end - -function UI.Viewport:reset() - self.offy = 0 -end - -function UI.Viewport:getViewArea() - return { - y = (self.offy or 0) + 1, - height = self.height, - totalHeight = self.ymax, - offsetY = self.offy or 0, - } -end - -function UI.Viewport:eventHandler(event) - if event.type == 'scroll_down' then - self:setScrollPosition(self.offy + 1) - elseif event.type == 'scroll_up' then - self:setScrollPosition(self.offy - 1) - elseif event.type == 'scroll_top' then - self:setScrollPosition(0) - elseif event.type == 'scroll_bottom' then - self:setScrollPosition(10000000) - elseif event.type == 'scroll_pageUp' then - self:setScrollPosition(self.offy - self.height) - elseif event.type == 'scroll_pageDown' then - self:setScrollPosition(self.offy + self.height) - else - return false - end - return true -end - ---[[-- TitleBar --]]-- -UI.TitleBar = class(UI.Window) -UI.TitleBar.defaults = { - UIElement = 'TitleBar', - height = 1, - textColor = colors.white, - backgroundColor = colors.cyan, - title = '', - frameChar = '-', - closeInd = '*', -} -function UI.TitleBar:draw() - local sb = SB:new(self.width) - sb:fill(2, self.frameChar, sb.width - 3) - sb:center(string.format(' %s ', self.title)) - if self.previousPage or self.event then - sb:insert(-1, self.closeInd) - else - sb:insert(-2, self.frameChar) - end - self:write(1, 1, sb:get()) -end - -function UI.TitleBar:eventHandler(event) - if event.type == 'mouse_click' then - if (self.previousPage or self.event) and event.x == self.width then - if self.event then - self:emit({ type = self.event, element = self }) - elseif type(self.previousPage) == 'string' or - type(self.previousPage) == 'table' then - UI:setPage(self.previousPage) - else - UI:setPreviousPage() - end - return true - end - end -end - ---[[-- Button --]]-- -UI.Button = class(UI.Window) -UI.Button.defaults = { - UIElement = 'Button', - text = 'button', - backgroundColor = colors.lightGray, - backgroundFocusColor = colors.gray, - textFocusColor = colors.white, - textInactiveColor = colors.gray, - textColor = colors.black, - centered = true, - height = 1, - focusIndicator = ' ', - event = 'button_press', - accelerators = { - space = 'button_activate', - enter = 'button_activate', - mouse_click = 'button_activate', - } -} -function UI.Button:setParent() - if not self.width and not self.ex then - self.width = #self.text + 2 - end - UI.Window.setParent(self) -end - -function UI.Button:draw() - local fg = self.textColor - local bg = self.backgroundColor - local ind = ' ' - if self.focused then - bg = self.backgroundFocusColor - fg = self.textFocusColor - ind = self.focusIndicator - elseif self.inactive then - fg = self.textInactiveColor - end - local text = ind .. self.text .. ' ' - if self.centered then - self:clear(bg) - self:centeredWrite(1 + math.floor(self.height / 2), text, bg, fg) - else - self:write(1, 1, Util.widthify(text, self.width), bg, fg) - end -end - -function UI.Button:focus() - if self.focused then - self:scrollIntoView() - end - self:draw() -end - -function UI.Button:eventHandler(event) - if event.type == 'button_activate' then - self:emit({ type = self.event, button = self }) - return true - end - return false -end - ---[[-- MenuItem --]]-- -UI.MenuItem = class(UI.Button) -UI.MenuItem.defaults = { - UIElement = 'MenuItem', - textColor = colors.black, - backgroundColor = colors.lightGray, - textFocusColor = colors.white, - backgroundFocusColor = colors.lightGray, -} - ---[[-- MenuBar --]]-- -UI.MenuBar = class(UI.Window) -UI.MenuBar.defaults = { - UIElement = 'MenuBar', - buttons = { }, - height = 1, - backgroundColor = colors.lightGray, - textColor = colors.black, - spacing = 2, - lastx = 1, - showBackButton = false, - buttonClass = 'MenuItem', -} -UI.MenuBar.spacer = { spacer = true, text = 'spacer', inactive = true } - -function UI.MenuBar:postInit() - self:addButtons(self.buttons) -end - -function UI.MenuBar:addButtons(buttons) - if not self.children then - self.children = { } - end - - for _,button in pairs(buttons) do - if button.UIElement then - table.insert(self.children, button) - else - local buttonProperties = { - x = self.lastx, - width = #button.text + self.spacing, - centered = false, - } - self.lastx = self.lastx + buttonProperties.width - UI:mergeProperties(buttonProperties, button) - - button = UI[self.buttonClass](buttonProperties) - if button.name then - self[button.name] = button - else - table.insert(self.children, button) - end - - if button.dropdown then - button.dropmenu = UI.DropMenu { buttons = button.dropdown } - end - end - end - if self.parent then - self:initChildren() - end -end - -function UI.MenuBar:getActive(menuItem) - return not menuItem.inactive -end - -function UI.MenuBar:eventHandler(event) - if event.type == 'button_press' and event.button.dropmenu then - if event.button.dropmenu.enabled then - event.button.dropmenu:hide() - self:refocus() - return true - else - local x, y = getPosition(event.button) - if x + event.button.dropmenu.width > self.width then - x = self.width - event.button.dropmenu.width + 1 - end - for _,c in pairs(event.button.dropmenu.children) do - if not c.spacer then - c.inactive = not self:getActive(c) - end - end - event.button.dropmenu:show(x, y + 1) - end - return true - end -end - ---[[-- DropMenuItem --]]-- -UI.DropMenuItem = class(UI.Button) -UI.DropMenuItem.defaults = { - UIElement = 'DropMenuItem', - textColor = colors.black, - backgroundColor = colors.white, - textFocusColor = colors.white, - textInactiveColor = colors.lightGray, - backgroundFocusColor = colors.lightGray, -} -function UI.DropMenuItem:eventHandler(event) - if event.type == 'button_activate' then - self.parent:hide() - end - return UI.Button.eventHandler(self, event) -end - ---[[-- DropMenu --]]-- -UI.DropMenu = class(UI.MenuBar) -UI.DropMenu.defaults = { - UIElement = 'DropMenu', - backgroundColor = colors.white, - buttonClass = 'DropMenuItem', -} -function UI.DropMenu:setParent() - UI.MenuBar.setParent(self) - - local maxWidth = 1 - for y,child in ipairs(self.children) do - child.x = 1 - child.y = y - if #(child.text or '') > maxWidth then - maxWidth = #child.text - end - end - for _,child in ipairs(self.children) do - child.width = maxWidth + 2 - if child.spacer then - child.text = string.rep('-', child.width - 2) - end - end - - self.height = #self.children + 1 - self.width = maxWidth + 2 - self.ow = self.width - - self.canvas = self:addLayer() -end - -function UI.DropMenu:enable() -end - -function UI.DropMenu:show(x, y) - self.x, self.y = x, y - self.canvas:move(x, y) - self.canvas:setVisible(true) - - UI.Window.enable(self) - - self:draw() - self:capture(self) - self:focusFirst() -end - -function UI.DropMenu:hide() - self:disable() - self.canvas:setVisible(false) - self:release(self) -end - -function UI.DropMenu:eventHandler(event) - if event.type == 'focus_lost' and self.enabled then - if not Util.contains(self.children, event.focused) then - self:hide() - end - elseif event.type == 'mouse_out' and self.enabled then - self:hide() - self:refocus() - else - return UI.MenuBar.eventHandler(self, event) - end - return true -end - ---[[-- TabBarMenuItem --]]-- -UI.TabBarMenuItem = class(UI.Button) -UI.TabBarMenuItem.defaults = { - UIElement = 'TabBarMenuItem', - event = 'tab_select', - textColor = colors.black, - selectedBackgroundColor = colors.cyan, - unselectedBackgroundColor = colors.lightGray, - backgroundColor = colors.lightGray, -} -function UI.TabBarMenuItem:draw() - if self.selected then - self.backgroundColor = self.selectedBackgroundColor - self.backgroundFocusColor = self.selectedBackgroundColor - else - self.backgroundColor = self.unselectedBackgroundColor - self.backgroundFocusColor = self.unselectedBackgroundColor - end - UI.Button.draw(self) -end - ---[[-- TabBar --]]-- -UI.TabBar = class(UI.MenuBar) -UI.TabBar.defaults = { - UIElement = 'TabBar', - buttonClass = 'TabBarMenuItem', - selectedBackgroundColor = colors.cyan, -} -function UI.TabBar:enable() - UI.MenuBar.enable(self) - if not Util.find(self.children, 'selected', true) then - local menuItem = self:getFocusables()[1] - if menuItem then - menuItem.selected = true - end - end -end - -function UI.TabBar:eventHandler(event) - if event.type == 'tab_select' then - local selected, si = Util.find(self.children, 'uid', event.button.uid) - local previous, pi = Util.find(self.children, 'selected', true) - - if si ~= pi then - selected.selected = true - if previous then - previous.selected = false - self:emit({ type = 'tab_change', current = si, last = pi, tab = selected }) - end - end - UI.MenuBar.draw(self) - end - return UI.MenuBar.eventHandler(self, event) -end - -function UI.TabBar:selectTab(text) - local menuItem = Util.find(self.children, 'text', text) - if menuItem then - menuItem.selected = true - end -end - ---[[-- Tabs --]]-- -UI.Tabs = class(UI.Window) -UI.Tabs.defaults = { - UIElement = 'Tabs', -} -function UI.Tabs:postInit() - self:add(self) -end - -function UI.Tabs:add(children) - local buttons = { } - for _,child in pairs(children) do - if type(child) == 'table' and child.UIElement and child.tabTitle then - child.y = 2 - table.insert(buttons, { - text = child.tabTitle, - event = 'tab_select', - tabUid = child.uid, - }) - end - end - - if not self.tabBar then - self.tabBar = UI.TabBar({ - buttons = buttons, }) - else - self.tabBar:addButtons(buttons) - end - - if self.parent then - return UI.Window.add(self, children) - end -end - -function UI.Tabs:selectTab(tab) - local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) - if menuItem then - self.tabBar:emit({ type = 'tab_select', button = { uid = menuItem.uid } }) - end -end - -function UI.Tabs:setActive(tab, active) - local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) - if menuItem then - menuItem.inactive = not active - end -end - -function UI.Tabs:enable() - self.enabled = true - self.transitionHint = nil - self.tabBar:enable() - - local menuItem = Util.find(self.tabBar.children, 'selected', true) - - for _,child in pairs(self.children) do - if child.uid == menuItem.tabUid then - child:enable() - self:emit({ type = 'tab_activate', activated = child }) - elseif child.tabTitle then - child:disable() + UI[name]._preload = function(self) + return load(name) end end end -function UI.Tabs:eventHandler(event) - if event.type == 'tab_change' then - local tab = self:find(event.tab.tabUid) - if event.current > event.last then - self.transitionHint = 'slideLeft' - else - self.transitionHint = 'slideRight' - end - - for _,child in pairs(self.children) do - if child.uid == event.tab.tabUid then - child:enable() - elseif child.tabTitle then - child:disable() - end - end - self:emit({ type = 'tab_activate', activated = tab }) - tab:draw() - end -end - ---[[-- Tab --]]-- -UI.Tab = class(UI.Window) -UI.Tab.defaults = { - UIElement = 'Tab', - tabTitle = 'tab', - backgroundColor = colors.cyan, - y = 2, -} -function UI.Tab:setParent() - UI.Window.setParent(self) - self.canvas = self:addLayer() -end - -function UI.Tab:enable(...) - self.canvas:setVisible(true) - UI.Window.enable(self, ...) - if self.parent.transitionHint then - self:addTransition(self.parent.transitionHint) - end - self:focusFirst() -end - -function UI.Tab:disable() - self.canvas:setVisible(false) - UI.Window.disable(self) -end - ---[[-- Wizard --]]-- -UI.Wizard = class(UI.Window) -UI.Wizard.defaults = { - UIElement = 'Wizard', - pages = { }, -} -function UI.Wizard:postInit() - self.cancelButton = UI.Button { - x = 2, y = -1, - text = 'Cancel', - event = 'cancel', - } - self.previousButton = UI.Button { - x = -18, y = -1, - text = '< Back', - event = 'previousView', - } - self.nextButton = UI.Button { - x = -9, y = -1, - text = 'Next >', - event = 'nextView', - } - - Util.merge(self, self.pages) - for _, child in pairs(self.pages) do - child.ey = -2 - end -end - -function UI.Wizard:add(pages) - Util.merge(self.pages, pages) - Util.merge(self, pages) - - for _, child in pairs(self.pages) do - child.ey = child.ey or -2 - end - - if self.parent then - self:initChildren() - end -end - -function UI.Wizard:getPage(index) - return Util.find(self.pages, 'index', index) -end - -function UI.Wizard:enable(...) - self.enabled = true - self.index = 1 - local initial = self:getPage(1) - for _,child in pairs(self.children) do - if child == initial or not child.index then - child:enable(...) - else - child:disable() - end - end - self:emit({ type = 'enable_view', next = initial }) -end - -function UI.Wizard:isViewValid() - local currentView = self:getPage(self.index) - return not currentView.validate and true or currentView:validate() -end - -function UI.Wizard:eventHandler(event) - if event.type == 'nextView' then - local currentView = self:getPage(self.index) - if self:isViewValid() then - self.index = self.index + 1 - local nextView = self:getPage(self.index) - currentView:emit({ type = 'enable_view', next = nextView, current = currentView }) - end - - elseif event.type == 'previousView' then - local currentView = self:getPage(self.index) - local nextView = self:getPage(self.index - 1) - if nextView then - self.index = self.index - 1 - currentView:emit({ type = 'enable_view', prev = nextView, current = currentView }) - end - return true - - elseif event.type == 'wizard_complete' then - if self:isViewValid() then - self:emit({ type = 'accept' }) - end - - elseif event.type == 'enable_view' then - if event.current then - if event.next then - self:addTransition('slideLeft') - elseif event.prev then - self:addTransition('slideRight') - end - event.current:disable() - end - - local current = event.next or event.prev - if not current then error('property "index" is required on wizard pages') end - - if self:getPage(self.index - 1) then - self.previousButton:enable() - else - self.previousButton:disable() - end - - if self:getPage(self.index + 1) then - self.nextButton.text = 'Next >' - self.nextButton.event = 'nextView' - else - self.nextButton.text = 'Accept' - self.nextButton.event = 'wizard_complete' - end - -- a new current view - current:enable() - current:emit({ type = 'view_enabled', view = current }) - self:draw() - end -end - ---[[-- SlideOut --]]-- -UI.SlideOut = class(UI.Window) -UI.SlideOut.defaults = { - UIElement = 'SlideOut', - pageType = 'modal', -} -function UI.SlideOut:setParent() - UI.Window.setParent(self) - self.canvas = self:addLayer() -end - -function UI.SlideOut:enable() -end - -function UI.SlideOut:show(...) - self:addTransition('expandUp') - self.canvas:setVisible(true) - UI.Window.enable(self, ...) - self:draw() - self:capture(self) - self:focusFirst() -end - -function UI.SlideOut:disable() - self.canvas:setVisible(false) - UI.Window.disable(self) -end - -function UI.SlideOut:hide() - self:disable() - self:release(self) - self:refocus() -end - -function UI.SlideOut:eventHandler(event) - if event.type == 'slide_show' then - self:show() - return true - - elseif event.type == 'slide_hide' then - self:hide() - return true - end -end - ---[[-- Embedded --]]-- -UI.Embedded = class(UI.Window) -UI.Embedded.defaults = { - UIElement = 'Embedded', - backgroundColor = colors.black, - textColor = colors.white, - accelerators = { - up = 'scroll_up', - down = 'scroll_down', - } -} - -function UI.Embedded:setParent() - UI.Window.setParent(self) - self.win = window.create(UI.term.device, 1, 1, self.width, self.height, false) - Canvas.scrollingWindow(self.win, self.x, self.y) - self.win.setParent(UI.term.device) - self.win.setMaxScroll(100) - - local canvas = self:getCanvas() - self.win.canvas.parent = canvas - table.insert(canvas.layers, self.win.canvas) - self.canvas = self.win.canvas - - self.win.setCursorPos(1, 1) - self.win.setBackgroundColor(self.backgroundColor) - self.win.setTextColor(self.textColor) - self.win.clear() -end - -function UI.Embedded:draw() - self.canvas:dirty() -end - -function UI.Embedded:enable() - self.canvas:setVisible(true) - UI.Window.enable(self) -end - -function UI.Embedded:disable() - self.canvas:setVisible(false) - UI.Window.disable(self) -end - -function UI.Embedded:eventHandler(event) - if event.type == 'scroll_up' then - self.win.scrollUp() - return true - elseif event.type == 'scroll_down' then - self.win.scrollDown() - return true - end -end - -function UI.Embedded:focus() - -- allow scrolling -end - ---[[-- Notification --]]-- -UI.Notification = class(UI.Window) -UI.Notification.defaults = { - UIElement = 'Notification', - backgroundColor = colors.gray, - height = 3, -} -function UI.Notification:draw() -end - -function UI.Notification:enable() -end - -function UI.Notification:error(value, timeout) - self.backgroundColor = colors.red - Sound.play('entity.villager.no', .5) - self:display(value, timeout) -end - -function UI.Notification:info(value, timeout) - self.backgroundColor = colors.gray - self:display(value, timeout) -end - -function UI.Notification:success(value, timeout) - self.backgroundColor = colors.green - self:display(value, timeout) -end - -function UI.Notification:cancel() - if self.canvas then - Event.cancelNamedTimer('notificationTimer') - self.enabled = false - self.canvas:removeLayer() - self.canvas = nil - end -end - -function UI.Notification:display(value, timeout) - self.enabled = true - local lines = Util.wordWrap(value, self.width - 2) - self.height = #lines + 1 - self.y = self.parent.height - self.height + 1 - if self.canvas then - self.canvas:removeLayer() - end - - self.canvas = self:addLayer(self.backgroundColor, self.textColor) - self:addTransition('expandUp', { ticks = self.height }) - self.canvas:setVisible(true) - self:clear() - for k,v in pairs(lines) do - self:write(2, k, v) - end - - Event.addNamedTimer('notificationTimer', timeout or 3, false, function() - self:cancel() - self:sync() - end) -end - ---[[-- Throttle --]]-- -UI.Throttle = class(UI.Window) -UI.Throttle.defaults = { - UIElement = 'Throttle', - backgroundColor = colors.gray, - bordercolor = colors.cyan, - height = 4, - width = 10, - timeout = .075, - ctr = 0, - image = { - ' //) (O )~@ &~&-( ?Q ', - ' //) (O )- @ \\-( ?) && ', - ' //) (O ), @ \\-(?) && ', - ' //) (O ). @ \\-d ) (@ ' - } -} -function UI.Throttle:setParent() - self.x = math.ceil((self.parent.width - self.width) / 2) - self.y = math.ceil((self.parent.height - self.height) / 2) - UI.Window.setParent(self) -end - -function UI.Throttle:enable() - self.c = os.clock() - self.enabled = false -end - -function UI.Throttle:disable() - if self.canvas then - self.enabled = false - self.canvas:removeLayer() - self.canvas = nil - self.ctr = 0 - end -end - -function UI.Throttle:update() - local cc = os.clock() - if cc > self.c + self.timeout then - os.sleep(0) - self.c = os.clock() - self.enabled = true - if not self.canvas then - self.canvas = self:addLayer(self.backgroundColor, self.borderColor) - self.canvas:setVisible(true) - self:clear(self.borderColor) - end - local image = self.image[self.ctr + 1] - local width = self.width - 2 - for i = 0, #self.image do - self:write(2, i + 1, image:sub(width * i + 1, width * i + width), - self.backgroundColor, self.textColor) - end - - self.ctr = (self.ctr + 1) % #self.image - - self:sync() - end -end - ---[[-- StatusBar --]]-- -UI.StatusBar = class(UI.Window) -UI.StatusBar.defaults = { - UIElement = 'StatusBar', - backgroundColor = colors.lightGray, - textColor = colors.gray, - height = 1, - ey = -1, -} -function UI.StatusBar:adjustWidth() - -- Can only have 1 adjustable width - if self.columns then - local w = self.width - #self.columns - 1 - for _,c in pairs(self.columns) do - if c.width then - c.cw = c.width -- computed width - w = w - c.width - end - end - for _,c in pairs(self.columns) do - if not c.width then - c.cw = w - end - end - end -end - -function UI.StatusBar:resize() - UI.Window.resize(self) - self:adjustWidth() -end - -function UI.StatusBar:setParent() - UI.Window.setParent(self) - self:adjustWidth() -end - -function UI.StatusBar:setStatus(status) - if self.values ~= status then - self.values = status - self:draw() - end -end - -function UI.StatusBar:setValue(name, value) - if not self.values then - self.values = { } - end - self.values[name] = value -end - -function UI.StatusBar:getValue(name) - if self.values then - return self.values[name] - end -end - -function UI.StatusBar:timedStatus(status, timeout) - timeout = timeout or 3 - self:write(2, 1, Util.widthify(status, self.width-2), self.backgroundColor) - Event.addNamedTimer('statusTimer', timeout, false, function() - if self.parent.enabled then - self:draw() - self:sync() - end - end) -end - -function UI.StatusBar:getColumnWidth(name) - local c = Util.find(self.columns, 'key', name) - return c and c.cw -end - -function UI.StatusBar:setColumnWidth(name, width) - local c = Util.find(self.columns, 'key', name) - if c then - c.cw = width - end -end - -function UI.StatusBar:draw() - if not self.values then - self:clear() - elseif type(self.values) == 'string' then - self:write(1, 1, Util.widthify(' ' .. self.values, self.width)) - else - local s = '' - for _,c in ipairs(self.columns) do - s = s .. ' ' .. Util.widthify(tostring(self.values[c.key] or ''), c.cw) - end - self:write(1, 1, Util.widthify(s, self.width)) - end -end - ---[[-- ProgressBar --]]-- -UI.ProgressBar = class(UI.Window) -UI.ProgressBar.defaults = { - UIElement = 'ProgressBar', - progressColor = colors.lime, - backgroundColor = colors.gray, - height = 1, - value = 0, -} -function UI.ProgressBar:draw() - self:clear() - local width = math.ceil(self.value / 100 * self.width) - self:clearArea(1, 1, width, self.height, self.progressColor) -end - ---[[-- VerticalMeter --]]-- -UI.VerticalMeter = class(UI.Window) -UI.VerticalMeter.defaults = { - UIElement = 'VerticalMeter', - backgroundColor = colors.gray, - meterColor = colors.lime, - width = 1, - value = 0, -} -function UI.VerticalMeter:draw() - local height = self.height - math.ceil(self.value / 100 * self.height) - self:clear() - self:clearArea(1, height + 1, self.width, self.height, self.meterColor) -end - ---[[-- TextEntry --]]-- -UI.TextEntry = class(UI.Window) -UI.TextEntry.defaults = { - UIElement = 'TextEntry', - value = '', - shadowText = '', - focused = false, - textColor = colors.white, - shadowTextColor = colors.gray, - backgroundColor = colors.black, -- colors.lightGray, - backgroundFocusColor = colors.black, --lightGray, - height = 1, - limit = 6, - pos = 0, - accelerators = { - [ 'control-c' ] = 'copy', - } -} -function UI.TextEntry:postInit() - self.value = tostring(self.value) -end - -function UI.TextEntry:setValue(value) - self.value = value -end - -function UI.TextEntry:setPosition(pos) - self.pos = pos -end - -function UI.TextEntry:updateScroll() - if not self.scroll then - self.scroll = 0 - end - - if not self.pos then - self.pos = #tostring(self.value) - self.scroll = 0 - elseif self.pos > #tostring(self.value) then - self.pos = #tostring(self.value) - self.scroll = 0 - end - - if self.pos - self.scroll > self.width - 2 then - self.scroll = self.pos - (self.width - 2) - elseif self.pos < self.scroll then - self.scroll = self.pos - end -end - -function UI.TextEntry:draw() - local bg = self.backgroundColor - local tc = self.textColor - if self.focused then - bg = self.backgroundFocusColor - end - - self:updateScroll() - local text = tostring(self.value) - if #text > 0 then - if self.scroll and self.scroll > 0 then - text = text:sub(1 + self.scroll) - end - if self.mask then - text = _rep('*', #text) - end - else - tc = self.shadowTextColor - text = self.shadowText - end - - self:write(1, 1, ' ' .. Util.widthify(text, self.width - 2) .. ' ', bg, tc) - if self.focused then - self:setCursorPos(self.pos-self.scroll+2, 1) - end -end - -function UI.TextEntry:reset() - self.pos = 0 - self.value = '' - self:draw() - self:updateCursor() -end - -function UI.TextEntry:updateCursor() - self:updateScroll() - self:setCursorPos(self.pos-self.scroll+2, 1) -end - -function UI.TextEntry:focus() - self:draw() - if self.focused then - self:setCursorBlink(true) - else - self:setCursorBlink(false) - end -end - ---[[ - A few lines below from theoriginalbit - http://www.computercraft.info/forums2/index.php?/topic/16070-read-and-limit-length-of-the-input-field/ ---]] -function UI.TextEntry:eventHandler(event) - if event.type == 'key' then - local ch = event.key - if ch == 'left' then - if self.pos > 0 then - self.pos = math.max(self.pos-1, 0) - self:draw() - end - elseif ch == 'right' then - local input = tostring(self.value) - if self.pos < #input then - self.pos = math.min(self.pos+1, #input) - self:draw() - end - elseif ch == 'home' then - self.pos = 0 - self:draw() - elseif ch == 'end' then - self.pos = #tostring(self.value) - self:draw() - elseif ch == 'backspace' then - if self.pos > 0 then - local input = tostring(self.value) - self.value = input:sub(1, self.pos-1) .. input:sub(self.pos+1) - self.pos = self.pos - 1 - self:draw() - self:emit({ type = 'text_change', text = self.value, element = self }) - end - elseif ch == 'delete' then - local input = tostring(self.value) - if self.pos < #input then - self.value = input:sub(1, self.pos) .. input:sub(self.pos+2) - self:draw() - self:emit({ type = 'text_change', text = self.value, element = self }) - end - elseif #ch == 1 then - local input = tostring(self.value) - if #input < self.limit then - self.value = input:sub(1, self.pos) .. ch .. input:sub(self.pos+1) - self.pos = self.pos + 1 - self:draw() - self:emit({ type = 'text_change', text = self.value, element = self }) - end - else - return false - end - return true - - elseif event.type == 'copy' then - os.queueEvent('clipboard_copy', self.value) - - elseif event.type == 'paste' then - local input = tostring(self.value) - local text = event.text - if #input + #text > self.limit then - text = text:sub(1, self.limit-#input) - end - self.value = input:sub(1, self.pos) .. text .. input:sub(self.pos+1) - self.pos = self.pos + #text - self:draw() - self:updateCursor() - self:emit({ type = 'text_change', text = self.value, element = self }) - return true - - elseif event.type == 'mouse_click' then - if self.focused and event.x > 1 then - self.pos = event.x + self.scroll - 2 - self:updateCursor() - return true - end - elseif event.type == 'mouse_rightclick' then - local input = tostring(self.value) - if #input > 0 then - self:reset() - self:emit({ type = 'text_change', text = self.value, element = self }) - end - end - - return false -end - ---[[-- Chooser --]]-- -UI.Chooser = class(UI.Window) -UI.Chooser.defaults = { - UIElement = 'Chooser', - choices = { }, - nochoice = 'Select', - backgroundFocusColor = colors.lightGray, - textInactiveColor = colors.gray, - leftIndicator = '<', - rightIndicator = '>', - height = 1, -} -function UI.Chooser:setParent() - if not self.width and not self.ex then - self.width = 1 - for _,v in pairs(self.choices) do - if #v.name > self.width then - self.width = #v.name - end - end - self.width = self.width + 4 - end - UI.Window.setParent(self) -end - -function UI.Chooser:draw() - local bg = self.backgroundColor - if self.focused then - bg = self.backgroundFocusColor - end - local fg = self.inactive and self.textInactiveColor or self.textColor - local choice = Util.find(self.choices, 'value', self.value) - local value = self.nochoice - if choice then - value = choice.name - end - self:write(1, 1, self.leftIndicator, self.backgroundColor, colors.black) - self:write(2, 1, ' ' .. Util.widthify(tostring(value), self.width-4) .. ' ', bg, fg) - self:write(self.width, 1, self.rightIndicator, self.backgroundColor, colors.black) -end - -function UI.Chooser:focus() - self:draw() -end - -function UI.Chooser:eventHandler(event) - if event.type == 'key' then - if event.key == 'right' or event.key == 'space' then - local _,k = Util.find(self.choices, 'value', self.value) - local choice - if not k then k = 1 end - if k and k < #self.choices then - choice = self.choices[k+1] - else - choice = self.choices[1] - end - self.value = choice.value - self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice }) - self:draw() - return true - elseif event.key == 'left' then - local _,k = Util.find(self.choices, 'value', self.value) - local choice - if k and k > 1 then - choice = self.choices[k-1] - else - choice = self.choices[#self.choices] - end - self.value = choice.value - self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice }) - self:draw() - return true - end - elseif event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then - if event.x == 1 then - self:emit({ type = 'key', key = 'left' }) - return true - elseif event.x == self.width then - self:emit({ type = 'key', key = 'right' }) - return true - end - end -end - ---[[-- Checkbox --]]-- -UI.Checkbox = class(UI.Window) -UI.Checkbox.defaults = { - UIElement = 'Checkbox', - nochoice = 'Select', - checkedIndicator = 'X', - leftMarker = '[', - rightMarker = ']', - value = false, - textColor = colors.white, - backgroundColor = colors.black, - backgroundFocusColor = colors.lightGray, - height = 1, - accelerators = { - space = 'checkbox_toggle', - mouse_click = 'checkbox_toggle', - } -} -function UI.Checkbox:setParent() - if not self.width and not self.ex then - self.width = (self.label and #self.label or 0) + 3 - else - self.widthh = 3 - end - UI.Window.setParent(self) -end - -function UI.Checkbox:draw() - local bg = self.backgroundColor - if self.focused then - bg = self.backgroundFocusColor - end - if type(self.value) == 'string' then - self.value = nil -- TODO: fix form - end - local text = string.format('[%s]', not self.value and ' ' or self.checkedIndicator) - local x = 1 - if self.label then - self:write(1, 1, self.label) - x = #self.label + 2 - end - self:write(x, 1, text, bg) - self:write(x, 1, self.leftMarker, self.backgroundColor, self.textColor) - self:write(x + 1, 1, not self.value and ' ' or self.checkedIndicator, bg) - self:write(x + 2, 1, self.rightMarker, self.backgroundColor, self.textColor) -end - -function UI.Checkbox:focus() - self:draw() -end - -function UI.Checkbox:reset() - self.value = false -end - -function UI.Checkbox:eventHandler(event) - if event.type == 'checkbox_toggle' then - self.value = not self.value - self:emit({ type = 'checkbox_change', checked = self.value, element = self }) - self:draw() - return true - end -end - ---[[-- Text --]]-- -UI.Text = class(UI.Window) -UI.Text.defaults = { - UIElement = 'Text', - value = '', - height = 1, -} -function UI.Text:setParent() - if not self.width and not self.ex then - self.width = #tostring(self.value) - end - UI.Window.setParent(self) -end - -function UI.Text:draw() - self:write(1, 1, Util.widthify(self.value or '', self.width), self.backgroundColor) -end - ---[[-- ScrollBar --]]-- -UI.ScrollBar = class(UI.Window) -UI.ScrollBar.defaults = { - UIElement = 'ScrollBar', - lineChar = '|', - sliderChar = '#', - upArrowChar = '^', - downArrowChar = 'v', - scrollbarColor = colors.lightGray, - value = '', - width = 1, - x = -1, - ey = -1, -} -function UI.ScrollBar:draw() - local parent = self.parent - local view = parent:getViewArea() - - if view.totalHeight > view.height then - local maxScroll = view.totalHeight - view.height - local percent = view.offsetY / maxScroll - local sliderSize = math.max(1, Util.round(view.height / view.totalHeight * (view.height - 2))) - local x = self.width - - local row = view.y - if not view.static then -- does the container scroll ? - self.y = row -- if so, move the scrollbar onscreen - row = 1 - end - - for i = 1, view.height - 2 do - self:write(x, row + i, self.lineChar, nil, self.scrollbarColor) - end - - local y = Util.round((view.height - 2 - sliderSize) * percent) - for i = 1, sliderSize do - self:write(x, row + y + i, self.sliderChar, nil, self.scrollbarColor) - end - - local color = self.scrollbarColor - if view.offsetY > 0 then - color = colors.white - end - self:write(x, row, self.upArrowChar, nil, color) - - color = self.scrollbarColor - if view.offsetY + view.height < view.totalHeight then - color = colors.white - end - self:write(x, row + view.height - 1, self.downArrowChar, nil, color) - end -end - -function UI.ScrollBar:eventHandler(event) - if event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then - if event.x == 1 then - local view = self.parent:getViewArea() - if view.totalHeight > view.height then - if event.y == view.y then - self:emit({ type = 'scroll_up'}) - elseif event.y == self.height then - self:emit({ type = 'scroll_down'}) - -- else - -- ... percentage ... - end - end - return true - end - end -end - ---[[-- TextArea --]]-- -UI.TextArea = class(UI.Viewport) -UI.TextArea.defaults = { - UIElement = 'TextArea', - marginRight = 2, - value = '', -} -function UI.TextArea:postInit() - self.scrollBar = UI.ScrollBar() -end - -function UI.TextArea:setText(text) - self.offy = 0 - self.ymax = nil - self.value = text - self:draw() -end - -function UI.TextArea:focus() - -- allow keyboard scrolling -end - -function UI.TextArea:draw() - self:clear() --- self:setCursorPos(1, 1) - self.cursorX, self.cursorY = 1, 1 - self:print(self.value) - self.ymax = self.cursorY - - for _,child in pairs(self.children) do - if child.enabled then - child:draw() - end - end -end - ---[[-- Form --]]-- -UI.Form = class(UI.Window) -UI.Form.defaults = { - UIElement = 'Form', - values = { }, - margin = 2, - event = 'form_complete', - cancelEvent = 'form_cancel', -} -function UI.Form:postInit() - self:createForm() -end - -function UI.Form:reset() - for _,child in pairs(self.children) do - if child.reset then - child:reset() - end - end -end - -function UI.Form:setValues(values) - self:reset() - self.values = values - for _,child in pairs(self.children) do - if child.formKey then - -- this should be child:setValue(self.values[child.formKey]) - -- so chooser can set default choice if null - -- null should be valid as well - child.value = self.values[child.formKey] or '' - end - end -end - -function UI.Form:createForm() - self.children = self.children or { } - - if not self.labelWidth then - self.labelWidth = 1 - for _, child in pairs(self) do - if type(child) == 'table' and child.UIElement then - if child.formLabel then - self.labelWidth = math.max(self.labelWidth, #child.formLabel + 2) - end - end - end - end - - local y = self.margin - for _, child in pairs(self) do - if type(child) == 'table' and child.UIElement then - if child.formKey then - child.value = self.values[child.formKey] or '' - end - if child.formLabel then - child.x = self.labelWidth + self.margin - 1 - child.y = y - if not child.width and not child.ex then - child.ex = -self.margin - end - - table.insert(self.children, UI.Text { - x = self.margin, - y = y, - textColor = colors.black, - width = #child.formLabel, - value = child.formLabel, - }) - end - if child.formKey or child.formLabel then - y = y + 1 - end - end - end - - if not self.manualControls then - table.insert(self.children, UI.Button { - y = -self.margin, x = -12 - self.margin, - text = 'Ok', - event = 'form_ok', - }) - table.insert(self.children, UI.Button { - y = -self.margin, x = -7 - self.margin, - text = 'Cancel', - event = self.cancelEvent, - }) - end -end - -function UI.Form:validateField(field) - if field.required then - if not field.value or #tostring(field.value) == 0 then - return false, 'Field is required' - end - end - if field.validate == 'numeric' then - if #tostring(field.value) > 0 then - if not tonumber(field.value) then - return false, 'Invalid number' - end - end - end - return true -end - -function UI.Form:save() - for _,child in pairs(self.children) do - if child.formKey then - local s, m = self:validateField(child) - if not s then - self:setFocus(child) - Sound.play('entity.villager.no', .5) - self:emit({ type = 'form_invalid', message = m, field = child }) - return false - end - end - end - for _,child in pairs(self.children) do - if child.formKey then - if (child.pruneEmpty and type(child.value) == 'string' and #child.value == 0) or - (child.pruneEmpty and type(child.value) == 'boolean' and not child.value) then - self.values[child.formKey] = nil - elseif child.validate == 'numeric' then - self.values[child.formKey] = tonumber(child.value) - else - self.values[child.formKey] = child.value - end - end - end - - return true -end - -function UI.Form:eventHandler(event) - if event.type == 'form_ok' then - if not self:save() then - return false - end - self:emit({ type = self.event, UIElement = self, values = self.values }) - else - return UI.Window.eventHandler(self, event) - end - return true -end - ---[[-- Dialog --]]-- -UI.Dialog = class(UI.SlideOut) -UI.Dialog.defaults = { - UIElement = 'Dialog', - height = 7, - textColor = colors.black, - backgroundColor = colors.white, - okEvent ='dialog_ok', - cancelEvent = 'dialog_cancel', -} -function UI.Dialog:postInit() - self.y = -self.height - self.titleBar = UI.TitleBar({ event = self.cancelEvent, title = self.title }) -end - -function UI.Dialog:show(...) - local canvas = self.parent:getCanvas() - self.oldPalette = canvas.palette - canvas:applyPalette(Canvas.darkPalette) - UI.SlideOut.show(self, ...) -end - -function UI.Dialog:hide(...) - self.parent:getCanvas().palette = self.oldPalette - UI.SlideOut.hide(self, ...) - self.parent:draw() -end - -function UI.Dialog:eventHandler(event) - if event.type == 'dialog_cancel' then - self:hide() - end - return UI.SlideOut.eventHandler(self, event) -end - ---[[-- Image --]]-- -UI.Image = class(UI.Window) -UI.Image.defaults = { - UIElement = 'Image', - event = 'button_press', -} -function UI.Image:setParent() - if self.image then - self.height = #self.image - end - if self.image and not self.width then - self.width = #self.image[1] - end - UI.Window.setParent(self) -end - -function UI.Image:draw() - self:clear() - if self.image then - for y = 1, #self.image do - local line = self.image[y] - for x = 1, #line do - local ch = line[x] - if type(ch) == 'number' then - if ch > 0 then - self:write(x, y, ' ', ch) - end - else - self:write(x, y, ch) - end - end - end - end -end - -function UI.Image:setImage(image) - self.image = image -end - ---[[-- NftImage --]]-- -UI.NftImage = class(UI.Window) -UI.NftImage.defaults = { - UIElement = 'NftImage', - event = 'button_press', -} -function UI.NftImage:setParent() - if self.image then - self.height = self.image.height - end - if self.image and not self.width then - self.width = self.image.width - end - UI.Window.setParent(self) -end - -function UI.NftImage:draw() - if self.image then - for y = 1, self.image.height do - for x = 1, #self.image.text[y] do - self:write(x, y, self.image.text[y][x], self.image.bg[y][x], self.image.fg[y][x]) - end - end - else - self:clear() - end -end - -function UI.NftImage:setImage(image) - self.image = image -end +loadComponents() UI:loadTheme('usr/config/ui.theme') if Util.getVersion() >= 1.76 then diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index 5e0ed5b..931e9bd 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -2,9 +2,9 @@ local class = require('class') local Region = require('ui.region') local Util = require('util') -local _rep = string.rep -local _sub = string.sub -local _gsub = string.gsub +local _rep = string.rep +local _sub = string.sub +local _gsub = string.gsub local colors = _G.colors local Canvas = class() @@ -19,6 +19,10 @@ for n = 1, 16 do Canvas.darkPalette[2 ^ (n - 1)] = _sub("8777777f77fff77f", n, n) end +--[[ + A canvas can have more lines than canvas.height in order to scroll +]] + function Canvas:init(args) self.x = 1 self.y = 1 @@ -50,7 +54,7 @@ function Canvas:move(x, y) end function Canvas:resize(w, h) - for i = self.height, h do + for i = #self.lines, h do self.lines[i] = { } end @@ -78,7 +82,7 @@ function Canvas:copy() height = self.height, isColor = self.isColor, }) - for i = 1, self.height do + for i = 1, #self.lines do b.lines[i].text = self.lines[i].text b.lines[i].fg = self.lines[i].fg b.lines[i].bg = self.lines[i].bg @@ -117,6 +121,19 @@ function Canvas:setVisible(visible) end end +-- Push a layer to the top +function Canvas:raise() + if self.parent then + local layers = self.parent.layers or { } + for k, v in pairs(layers) do + if v == self then + table.insert(layers, table.remove(layers, k)) + break + end + end + end +end + function Canvas:write(x, y, text, bg, fg) if bg then bg = _rep(self.palette[bg], #text) @@ -124,10 +141,10 @@ function Canvas:write(x, y, text, bg, fg) if fg then fg = _rep(self.palette[fg], #text) end - self:writeBlit(x, y, text, bg, fg) + self:blit(x, y, text, bg, fg) end -function Canvas:writeBlit(x, y, text, bg, fg) +function Canvas:blit(x, y, text, bg, fg) if y > 0 and y <= #self.lines and x <= self.width then local width = #text @@ -157,7 +174,7 @@ function Canvas:writeBlit(x, y, text, bg, fg) if width > 0 then - local function replace(sstr, pos, rstr, width) + local function replace(sstr, pos, rstr) if pos == 1 and width == self.width then return rstr elseif pos == 1 then @@ -188,39 +205,48 @@ function Canvas:writeLine(y, text, fg, bg) self.lines[y].bg = bg end -function Canvas:reset() - self.regions = nil +function Canvas:clearLine(y, bg, fg) + fg = _rep(self.palette[fg or colors.white], self.width) + bg = _rep(self.palette[bg or colors.black], self.width) + self:writeLine(y, _rep(' ', self.width), fg, bg) end function Canvas:clear(bg, fg) local text = _rep(' ', self.width) fg = _rep(self.palette[fg or colors.white], self.width) bg = _rep(self.palette[bg or colors.black], self.width) - for i = 1, self.height do + for i = 1, #self.lines do self:writeLine(i, text, fg, bg) end end function Canvas:punch(rect) - if not self.regions then - self.regions = Region.new(self.x, self.y, self.ex, self.ey) - end - self.regions:subRect(rect.x, rect.y, rect.ex, rect.ey) + local offset = { x = 0, y = 0 } + + + self.regions:subRect(rect.x + offset.x, rect.y + offset.y, rect.ex + offset.x, rect.ey + offset.y) end -function Canvas:blitClipped(device) +function Canvas:blitClipped(device, offset) + offset = { x = self.x, y = self.y } + local parent = self.parent + while parent do + offset.x = offset.x + parent.x - 1 + offset.y = offset.y + parent.y - 1 + parent = parent.parent + end for _,region in ipairs(self.regions.region) do - self:blit(device, - { x = region[1] - self.x + 1, - y = region[2] - self.y + 1, - ex = region[3]- self.x + 1, - ey = region[4] - self.y + 1 }, - { x = region[1], y = region[2] }) + self:blitRect(device, + { x = region[1], + y = region[2], + ex = region[3], + ey = region[4] }, + { x = region[1] + offset.x - 1, y = region[2] + offset.y - 1 }) end end function Canvas:redraw(device) - self:reset() +--[[ if #self.layers > 0 then for _,layer in pairs(self.layers) do self:punch(layer) @@ -230,19 +256,20 @@ function Canvas:redraw(device) self:blit(device) end self:clean() +]] end function Canvas:isDirty() - for _, line in pairs(self.lines) do - if line.dirty then + for i = 1, #self.lines do + if self.lines[i].dirty then return true end end end function Canvas:dirty() - for _, line in pairs(self.lines) do - line.dirty = true + for i = 1, #self.lines do + self.lines[i].dirty = true end if self.layers then for _, canvas in pairs(self.layers) do @@ -252,37 +279,81 @@ function Canvas:dirty() end function Canvas:clean() - for _, line in pairs(self.lines) do - line.dirty = false + for i = 1, #self.lines do + self.lines[i].dirty = nil end end -function Canvas:render(device, layers) --- redrawAll ? - layers = layers or self.layers - if #layers > 0 then - self.regions = Region.new(self.x, self.y, self.ex, self.ey) - local l = Util.shallowCopy(layers) - for _, canvas in ipairs(layers) do - table.remove(l, 1) +function Canvas:renderLayers(device, offset) + if not offset then + offset = { x = self.x, y = self.y } + end + if #self.layers > 0 then + self.regions = Region.new(1, 1, self.ex, self.ey) + + for i = 1, #self.layers do + local canvas = self.layers[i] if canvas.visible then + + -- punch out this area from the parent's canvas self:punch(canvas) - canvas:render(device, l) + + -- get the area to render for this layer + canvas.regions = Region.new(canvas.x, canvas.y, canvas.ex, canvas.ey) + + -- determine if we should render this layer by punching + -- out any layers that overlap this one + for j = i + 1, #self.layers do + if self.layers[j].visible then + canvas:punch(self.layers[j]) + end + end end end - self:blitClipped(device) - self:reset() + + for _, canvas in ipairs(self.layers) do + if canvas.visible and #canvas.regions.region > 0 then + canvas:renderLayers(device, { + x = canvas.x, --offset.x + self.x - 1, + y = canvas.y, + }) + end + end + + self:blitClipped(device, offset) + + --elseif #self.regions.region > 0 then + -- self:blitClipped(device, offset) + else - self:blit(device) + offset = { x = self.x, y = self.y } + local parent = self.parent + while parent do + offset.x = offset.x + parent.x - 1 + offset.y = offset.y + parent.y - 1 + parent = parent.parent + end + self:blitRect(device, nil, offset) end self:clean() end -function Canvas:blit(device, src, tgt) +function Canvas:render(device) + --_G._p = self + if #self.layers > 0 then + self:renderLayers(device) + else + self:blitRect(device) + self:clean() + end +end + +function Canvas:blitRect(device, src, tgt) src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 } tgt = tgt or self for i = 0, src.ey - src.y do - local line = self.lines[src.y + i] + local line = self.lines[src.y + i + (self.offy or 0)] if line and line.dirty then local t, fg, bg = line.text, line.fg, line.bg if src.x > 1 or src.ex < self.ex then @@ -290,13 +361,11 @@ function Canvas:blit(device, src, tgt) fg = _sub(fg, src.x, src.ex) bg = _sub(bg, src.x, src.ex) end - --if tgt.y + i > self.ey then -- wrong place to do clipping ?? - -- break - --end device.setCursorPos(tgt.x, tgt.y + i) device.blit(t, fg, bg) end end + --os.sleep(.1) end function Canvas:applyPalette(palette) @@ -351,7 +420,7 @@ function Canvas.convertWindow(win, parent, wx, wy) function win.blit(text, fg, bg) local x, y = win.getCursorPos() - win.canvas:writeBlit(x, y, text, bg, fg) + win.canvas:blit(x, y, text, bg, fg) end function win.redraw() @@ -372,132 +441,4 @@ function Canvas.convertWindow(win, parent, wx, wy) win.clear() end -function Canvas.scrollingWindow(win, wx, wy) - local w, h = win.getSize() - local scrollPos = 0 - local maxScroll = h - - -- canvas lines are are a sliding window within the local lines table - local lines = { } - - local parent - local canvas = Canvas({ - x = wx, - y = wy, - width = w, - height = h, - isColor = win.isColor(), - }) - win.canvas = canvas - - local function scrollTo(p, forceRedraw) - local ms = #lines - canvas.height -- max scroll - p = math.min(math.max(p, 0), ms) -- normalize - - if p ~= scrollPos or forceRedraw then - scrollPos = p - for i = 1, canvas.height do - canvas.lines[i] = lines[i + scrollPos] - end - canvas:dirty() - end - end - - function win.blit(text, fg, bg) - local x, y = win.getCursorPos() - win.canvas:writeBlit(x, y, text, bg, fg) - win.redraw() - end - - function win.clear() - lines = { } - for i = 1, canvas.height do - lines[i] = canvas.lines[i] - end - scrollPos = 0 - canvas:clear(win.getBackgroundColor(), win.getTextColor()) - win.redraw() - end - - function win.clearLine() - local _, y = win.getCursorPos() - - scrollTo(#lines - canvas.height) - win.canvas:write(1, - y, - _rep(' ', win.canvas.width), - win.getBackgroundColor(), - win.getTextColor()) - win.redraw() - end - - function win.redraw() - if parent and canvas.visible then - local x, y = win.getCursorPos() - for i = 1, canvas.height do - local line = canvas.lines[i] - if line and line.dirty then - parent.setCursorPos(canvas.x, canvas.y + i - 1) - parent.blit(line.text, line.fg, line.bg) - line.dirty = false - end - end - win.setCursorPos(x, y) - end - end - - -- doesn't support negative scrolling... - function win.scroll(n) - for _ = 1, n do - lines[#lines + 1] = { - text = _rep(' ', canvas.width), - fg = _rep(canvas.palette[win.getTextColor()], canvas.width), - bg = _rep(canvas.palette[win.getBackgroundColor()], canvas.width), - } - end - - while #lines > maxScroll do - table.remove(lines, 1) - end - - scrollTo(maxScroll, true) - win.redraw() - end - - function win.scrollDown() - scrollTo(scrollPos + 1) - win.redraw() - end - - function win.scrollUp() - scrollTo(scrollPos - 1) - win.redraw() - end - - function win.setMaxScroll(ms) - maxScroll = ms - end - - function win.setParent(p) - parent = p - end - - function win.write(str) - str = tostring(str) or '' - - local x, y = win.getCursorPos() - scrollTo(#lines - canvas.height) - win.blit(str, - _rep(canvas.palette[win.getTextColor()], #str), - _rep(canvas.palette[win.getBackgroundColor()], #str)) - win.setCursorPos(x + #str, y) - end - - function win.reposition(x, y, width, height) - win.canvas.x, win.canvas.y = x, y - win.canvas:resize(width or win.canvas.width, height or win.canvas.height) - end - - win.clear() -end return Canvas diff --git a/sys/apis/ui/components/ActiveLayer.lua b/sys/apis/ui/components/ActiveLayer.lua new file mode 100644 index 0000000..8f84a4e --- /dev/null +++ b/sys/apis/ui/components/ActiveLayer.lua @@ -0,0 +1,30 @@ +local class = require('class') +local UI = require('ui') + +UI.ActiveLayer = class(UI.Window) +UI.ActiveLayer.defaults = { + UIElement = 'ActiveLayer', +} +function UI.ActiveLayer:setParent() + self:layout(self) + self.canvas = self:addLayer() + + UI.Window.setParent(self) +end + +function UI.ActiveLayer:enable(...) + self.canvas:raise() + self.canvas:setVisible(true) + UI.Window.enable(self, ...) + if self.parent.transitionHint then + self:addTransition(self.parent.transitionHint) + end + self:focusFirst() +end + +function UI.ActiveLayer:disable() + if self.canvas then + self.canvas:setVisible(false) + end + UI.Window.disable(self) +end diff --git a/sys/apis/ui/components/Button.lua b/sys/apis/ui/components/Button.lua new file mode 100644 index 0000000..be31cad --- /dev/null +++ b/sys/apis/ui/components/Button.lua @@ -0,0 +1,66 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.Button = class(UI.Window) +UI.Button.defaults = { + UIElement = 'Button', + text = 'button', + backgroundColor = colors.lightGray, + backgroundFocusColor = colors.gray, + textFocusColor = colors.white, + textInactiveColor = colors.gray, + textColor = colors.black, + centered = true, + height = 1, + focusIndicator = ' ', + event = 'button_press', + accelerators = { + space = 'button_activate', + enter = 'button_activate', + mouse_click = 'button_activate', + } +} +function UI.Button:setParent() + if not self.width and not self.ex then + self.width = #self.text + 2 + end + UI.Window.setParent(self) +end + +function UI.Button:draw() + local fg = self.textColor + local bg = self.backgroundColor + local ind = ' ' + if self.focused then + bg = self.backgroundFocusColor + fg = self.textFocusColor + ind = self.focusIndicator + elseif self.inactive then + fg = self.textInactiveColor + end + local text = ind .. self.text .. ' ' + if self.centered then + self:clear(bg) + self:centeredWrite(1 + math.floor(self.height / 2), text, bg, fg) + else + self:write(1, 1, Util.widthify(text, self.width), bg, fg) + end +end + +function UI.Button:focus() + if self.focused then + self:scrollIntoView() + end + self:draw() +end + +function UI.Button:eventHandler(event) + if event.type == 'button_activate' then + self:emit({ type = self.event, button = self }) + return true + end + return false +end diff --git a/sys/apis/ui/components/Checkbox.lua b/sys/apis/ui/components/Checkbox.lua new file mode 100644 index 0000000..ac3ec4c --- /dev/null +++ b/sys/apis/ui/components/Checkbox.lua @@ -0,0 +1,67 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +UI.Checkbox = class(UI.Window) +UI.Checkbox.defaults = { + UIElement = 'Checkbox', + nochoice = 'Select', + checkedIndicator = 'X', + leftMarker = '[', + rightMarker = ']', + value = false, + textColor = colors.white, + backgroundColor = colors.black, + backgroundFocusColor = colors.lightGray, + height = 1, + accelerators = { + space = 'checkbox_toggle', + mouse_click = 'checkbox_toggle', + } +} +function UI.Checkbox:setParent() + if not self.width and not self.ex then + self.width = (self.label and #self.label or 0) + 3 + else + self.widthh = 3 + end + UI.Window.setParent(self) +end + +function UI.Checkbox:draw() + local bg = self.backgroundColor + if self.focused then + bg = self.backgroundFocusColor + end + if type(self.value) == 'string' then + self.value = nil -- TODO: fix form + end + local text = string.format('[%s]', not self.value and ' ' or self.checkedIndicator) + local x = 1 + if self.label then + self:write(1, 1, self.label) + x = #self.label + 2 + end + self:write(x, 1, text, bg) + self:write(x, 1, self.leftMarker, self.backgroundColor, self.textColor) + self:write(x + 1, 1, not self.value and ' ' or self.checkedIndicator, bg) + self:write(x + 2, 1, self.rightMarker, self.backgroundColor, self.textColor) +end + +function UI.Checkbox:focus() + self:draw() +end + +function UI.Checkbox:reset() + self.value = false +end + +function UI.Checkbox:eventHandler(event) + if event.type == 'checkbox_toggle' then + self.value = not self.value + self:emit({ type = 'checkbox_change', checked = self.value, element = self }) + self:draw() + return true + end +end diff --git a/sys/apis/ui/components/Chooser.lua b/sys/apis/ui/components/Chooser.lua new file mode 100644 index 0000000..f6e632d --- /dev/null +++ b/sys/apis/ui/components/Chooser.lua @@ -0,0 +1,88 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.Chooser = class(UI.Window) +UI.Chooser.defaults = { + UIElement = 'Chooser', + choices = { }, + nochoice = 'Select', + backgroundFocusColor = colors.lightGray, + textInactiveColor = colors.gray, + leftIndicator = '<', + rightIndicator = '>', + height = 1, +} +function UI.Chooser:setParent() + if not self.width and not self.ex then + self.width = 1 + for _,v in pairs(self.choices) do + if #v.name > self.width then + self.width = #v.name + end + end + self.width = self.width + 4 + end + UI.Window.setParent(self) +end + +function UI.Chooser:draw() + local bg = self.backgroundColor + if self.focused then + bg = self.backgroundFocusColor + end + local fg = self.inactive and self.textInactiveColor or self.textColor + local choice = Util.find(self.choices, 'value', self.value) + local value = self.nochoice + if choice then + value = choice.name + end + self:write(1, 1, self.leftIndicator, self.backgroundColor, colors.black) + self:write(2, 1, ' ' .. Util.widthify(tostring(value), self.width-4) .. ' ', bg, fg) + self:write(self.width, 1, self.rightIndicator, self.backgroundColor, colors.black) +end + +function UI.Chooser:focus() + self:draw() +end + +function UI.Chooser:eventHandler(event) + if event.type == 'key' then + if event.key == 'right' or event.key == 'space' then + local _,k = Util.find(self.choices, 'value', self.value) + local choice + if not k then k = 1 end + if k and k < #self.choices then + choice = self.choices[k+1] + else + choice = self.choices[1] + end + self.value = choice.value + self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice }) + self:draw() + return true + elseif event.key == 'left' then + local _,k = Util.find(self.choices, 'value', self.value) + local choice + if k and k > 1 then + choice = self.choices[k-1] + else + choice = self.choices[#self.choices] + end + self.value = choice.value + self:emit({ type = 'choice_change', value = self.value, element = self, choice = choice }) + self:draw() + return true + end + elseif event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then + if event.x == 1 then + self:emit({ type = 'key', key = 'left' }) + return true + elseif event.x == self.width then + self:emit({ type = 'key', key = 'right' }) + return true + end + end +end diff --git a/sys/apis/ui/components/Dialog.lua b/sys/apis/ui/components/Dialog.lua new file mode 100644 index 0000000..a293052 --- /dev/null +++ b/sys/apis/ui/components/Dialog.lua @@ -0,0 +1,39 @@ +local Canvas = require('ui.canvas') +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +UI.Dialog = class(UI.SlideOut) +UI.Dialog.defaults = { + UIElement = 'Dialog', + height = 7, + textColor = colors.black, + backgroundColor = colors.white, + okEvent ='dialog_ok', + cancelEvent = 'dialog_cancel', +} +function UI.Dialog:postInit() + self.y = -self.height + self.titleBar = UI.TitleBar({ event = self.cancelEvent, title = self.title }) +end + +function UI.Dialog:show(...) + local canvas = self.parent:getCanvas() + self.oldPalette = canvas.palette + canvas:applyPalette(Canvas.darkPalette) + UI.SlideOut.show(self, ...) +end + +function UI.Dialog:hide(...) + self.parent:getCanvas().palette = self.oldPalette + UI.SlideOut.hide(self, ...) + self.parent:draw() +end + +function UI.Dialog:eventHandler(event) + if event.type == 'dialog_cancel' then + self:hide() + end + return UI.SlideOut.eventHandler(self, event) +end \ No newline at end of file diff --git a/sys/apis/ui/components/DropMenu.lua b/sys/apis/ui/components/DropMenu.lua new file mode 100644 index 0000000..98f92be --- /dev/null +++ b/sys/apis/ui/components/DropMenu.lua @@ -0,0 +1,71 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.DropMenu = class(UI.MenuBar) +UI.DropMenu.defaults = { + UIElement = 'DropMenu', + backgroundColor = colors.white, + buttonClass = 'DropMenuItem', +} +function UI.DropMenu:setParent() + UI.MenuBar.setParent(self) + + local maxWidth = 1 + for y,child in ipairs(self.children) do + child.x = 1 + child.y = y + if #(child.text or '') > maxWidth then + maxWidth = #child.text + end + end + for _,child in ipairs(self.children) do + child.width = maxWidth + 2 + if child.spacer then + child.text = string.rep('-', child.width - 2) + end + end + + self.height = #self.children + 1 + self.width = maxWidth + 2 + self.ow = self.width + + self.canvas = self:addLayer() +end + +function UI.DropMenu:enable() +end + +function UI.DropMenu:show(x, y) + self.x, self.y = x, y + self.canvas:move(x, y) + self.canvas:setVisible(true) + + UI.Window.enable(self) + + self:draw() + self:capture(self) + self:focusFirst() +end + +function UI.DropMenu:hide() + self:disable() + self.canvas:setVisible(false) + self:release(self) +end + +function UI.DropMenu:eventHandler(event) + if event.type == 'focus_lost' and self.enabled then + if not Util.contains(self.children, event.focused) then + self:hide() + end + elseif event.type == 'mouse_out' and self.enabled then + self:hide() + self:refocus() + else + return UI.MenuBar.eventHandler(self, event) + end + return true +end diff --git a/sys/apis/ui/components/DropMenuItem.lua b/sys/apis/ui/components/DropMenuItem.lua new file mode 100644 index 0000000..a08f505 --- /dev/null +++ b/sys/apis/ui/components/DropMenuItem.lua @@ -0,0 +1,21 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +--[[-- DropMenuItem --]]-- +UI.DropMenuItem = class(UI.Button) +UI.DropMenuItem.defaults = { + UIElement = 'DropMenuItem', + textColor = colors.black, + backgroundColor = colors.white, + textFocusColor = colors.white, + textInactiveColor = colors.lightGray, + backgroundFocusColor = colors.lightGray, +} +function UI.DropMenuItem:eventHandler(event) + if event.type == 'button_activate' then + self.parent:hide() + end + return UI.Button.eventHandler(self, event) +end diff --git a/sys/apis/ui/components/Embedded.lua b/sys/apis/ui/components/Embedded.lua new file mode 100644 index 0000000..626516f --- /dev/null +++ b/sys/apis/ui/components/Embedded.lua @@ -0,0 +1,69 @@ +local class = require('class') +local Terminal = require('terminal') +local UI = require('ui') + +local colors = _G.colors + +UI.Embedded = class(UI.Window) +UI.Embedded.defaults = { + UIElement = 'Embedded', + backgroundColor = colors.black, + textColor = colors.white, + maxScroll = 100, + accelerators = { + up = 'scroll_up', + down = 'scroll_down', + } +} +function UI.Embedded:setParent() + UI.Window.setParent(self) + + self.win = Terminal.window(UI.term.device, self.x, self.y, self.width, self.height, false) + self.win.setMaxScroll(self.maxScroll) + + local canvas = self:getCanvas() + self.win.getCanvas().parent = canvas + table.insert(canvas.layers, self.win.getCanvas()) + self.canvas = self.win.getCanvas() + + self.win.setCursorPos(1, 1) + self.win.setBackgroundColor(self.backgroundColor) + self.win.setTextColor(self.textColor) + self.win.clear() +end + +function UI.Embedded:draw() + self.canvas:dirty() +end + +function UI.Embedded:enable() + self.canvas:setVisible(true) + self.canvas:raise() + if self.visible then + -- the window will automatically update on changes + -- the canvas does not need to be rendereed + self.win.setVisible(true) + end + UI.Window.enable(self) + self.canvas:dirty() +end + +function UI.Embedded:disable() + self.canvas:setVisible(false) + self.win.setVisible(false) + UI.Window.disable(self) +end + +function UI.Embedded:eventHandler(event) + if event.type == 'scroll_up' then + self.win.scrollUp() + return true + elseif event.type == 'scroll_down' then + self.win.scrollDown() + return true + end +end + +function UI.Embedded:focus() + -- allow scrolling +end diff --git a/sys/apis/ui/components/Form.lua b/sys/apis/ui/components/Form.lua new file mode 100644 index 0000000..43b3557 --- /dev/null +++ b/sys/apis/ui/components/Form.lua @@ -0,0 +1,149 @@ +local class = require('class') +local Sound = require('sound') +local UI = require('ui') + +local colors = _G.colors + +UI.Form = class(UI.Window) +UI.Form.defaults = { + UIElement = 'Form', + values = { }, + margin = 2, + event = 'form_complete', + cancelEvent = 'form_cancel', +} +function UI.Form:postInit() + self:createForm() +end + +function UI.Form:reset() + for _,child in pairs(self.children) do + if child.reset then + child:reset() + end + end +end + +function UI.Form:setValues(values) + self:reset() + self.values = values + for _,child in pairs(self.children) do + if child.formKey then + -- this should be child:setValue(self.values[child.formKey]) + -- so chooser can set default choice if null + -- null should be valid as well + child.value = self.values[child.formKey] or '' + end + end +end + +function UI.Form:createForm() + self.children = self.children or { } + + if not self.labelWidth then + self.labelWidth = 1 + for _, child in pairs(self) do + if type(child) == 'table' and child.UIElement then + if child.formLabel then + self.labelWidth = math.max(self.labelWidth, #child.formLabel + 2) + end + end + end + end + + local y = self.margin + for _, child in pairs(self) do + if type(child) == 'table' and child.UIElement then + if child.formKey then + child.value = self.values[child.formKey] or '' + end + if child.formLabel then + child.x = self.labelWidth + self.margin - 1 + child.y = y + if not child.width and not child.ex then + child.ex = -self.margin + end + + table.insert(self.children, UI.Text { + x = self.margin, + y = y, + textColor = colors.black, + width = #child.formLabel, + value = child.formLabel, + }) + end + if child.formKey or child.formLabel then + y = y + 1 + end + end + end + + if not self.manualControls then + table.insert(self.children, UI.Button { + y = -self.margin, x = -12 - self.margin, + text = 'Ok', + event = 'form_ok', + }) + table.insert(self.children, UI.Button { + y = -self.margin, x = -7 - self.margin, + text = 'Cancel', + event = self.cancelEvent, + }) + end +end + +function UI.Form:validateField(field) + if field.required then + if not field.value or #tostring(field.value) == 0 then + return false, 'Field is required' + end + end + if field.validate == 'numeric' then + if #tostring(field.value) > 0 then + if not tonumber(field.value) then + return false, 'Invalid number' + end + end + end + return true +end + +function UI.Form:save() + for _,child in pairs(self.children) do + if child.formKey then + local s, m = self:validateField(child) + if not s then + self:setFocus(child) + Sound.play('entity.villager.no', .5) + self:emit({ type = 'form_invalid', message = m, field = child }) + return false + end + end + end + for _,child in pairs(self.children) do + if child.formKey then + if (child.pruneEmpty and type(child.value) == 'string' and #child.value == 0) or + (child.pruneEmpty and type(child.value) == 'boolean' and not child.value) then + self.values[child.formKey] = nil + elseif child.validate == 'numeric' then + self.values[child.formKey] = tonumber(child.value) + else + self.values[child.formKey] = child.value + end + end + end + + return true +end + +function UI.Form:eventHandler(event) + if event.type == 'form_ok' then + if not self:save() then + return false + end + self:emit({ type = self.event, UIElement = self, values = self.values }) + else + return UI.Window.eventHandler(self, event) + end + return true +end diff --git a/sys/apis/ui/components/Grid.lua b/sys/apis/ui/components/Grid.lua new file mode 100644 index 0000000..c5ce6db --- /dev/null +++ b/sys/apis/ui/components/Grid.lua @@ -0,0 +1,492 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors +local os = _G.os +local _rep = string.rep +local _sub = string.sub + +local function safeValue(v) + local t = type(v) + if t == 'string' or t == 'number' then + return v + end + return tostring(v) +end + +local Writer = class() +function Writer:init(element, y) + self.element = element + self.y = y + self.x = 1 +end + +function Writer:write(s, width, justify, bg, fg) + local len = #tostring(s or '') + if len > width then + s = _sub(s, 1, width) + end + local padding = len < width and _rep(' ', width - len) + if padding then + if justify == 'right' then + s = padding .. s + else + s = s .. padding + end + end + self.element:write(self.x, self.y, s, bg, fg) + self.x = self.x + width +end + +function Writer:finish(bg) + if self.x <= self.element.width then + self.element:write(self.x, self.y, _rep(' ', self.element.width - self.x + 1), bg) + end + self.x = 1 + self.y = self.y + 1 +end + +--[[-- Grid --]]-- +UI.Grid = class(UI.Window) +UI.Grid.defaults = { + UIElement = 'Grid', + index = 1, + inverseSort = false, + disableHeader = false, + headerHeight = 1, + marginRight = 0, + textColor = colors.white, + textSelectedColor = colors.white, + backgroundColor = colors.black, + backgroundSelectedColor = colors.gray, + headerBackgroundColor = colors.cyan, + headerTextColor = colors.white, + headerSortColor = colors.yellow, + unfocusedTextSelectedColor = colors.white, + unfocusedBackgroundSelectedColor = colors.gray, + focusIndicator = '>', + sortIndicator = ' ', + inverseSortIndicator = '^', + values = { }, + columns = { }, + accelerators = { + enter = 'key_enter', + [ 'control-c' ] = 'copy', + down = 'scroll_down', + up = 'scroll_up', + home = 'scroll_top', + [ 'end' ] = 'scroll_bottom', + pageUp = 'scroll_pageUp', + [ 'control-b' ] = 'scroll_pageUp', + pageDown = 'scroll_pageDown', + [ 'control-f' ] = 'scroll_pageDown', + }, +} +function UI.Grid:setParent() + UI.Window.setParent(self) + + for _,c in pairs(self.columns) do + c.cw = c.width + if not c.heading then + c.heading = '' + end + end + + self:update() + + if not self.pageSize then + if self.disableHeader then + self.pageSize = self.height + else + self.pageSize = self.height - self.headerHeight + end + end +end + +function UI.Grid:resize() + UI.Window.resize(self) + + if self.disableHeader then + self.pageSize = self.height + else + self.pageSize = self.height - self.headerHeight + end + self:adjustWidth() +end + +function UI.Grid:adjustWidth() + local t = { } -- cols without width + local w = self.width - #self.columns - 1 - self.marginRight -- width remaining + + for _,c in pairs(self.columns) do + if c.width then + c.cw = c.width + w = w - c.cw + else + table.insert(t, c) + end + end + + if #t == 0 then + return + end + + if #t == 1 then + t[1].cw = #(t[1].heading or '') + t[1].cw = math.max(t[1].cw, w) + return + end + + if not self.autospace then + for k,c in ipairs(t) do + c.cw = math.floor(w / (#t - k + 1)) + w = w - c.cw + end + + else + for _,c in ipairs(t) do + c.cw = #(c.heading or '') + w = w - c.cw + end + -- adjust the size to the length of the value + for key,row in pairs(self.values) do + if w <= 0 then + break + end + row = self:getDisplayValues(row, key) + for _,col in pairs(t) do + local value = row[col.key] + if value then + value = tostring(value) + if #value > col.cw then + w = w + col.cw + col.cw = math.min(#value, w) + w = w - col.cw + if w <= 0 then + break + end + end + end + end + end + + -- last column does not get padding (right alignment) + if not self.columns[#self.columns].width then + Util.removeByValue(t, self.columns[#self.columns]) + end + + -- got some extra room - add some padding + if w > 0 then + for k,c in ipairs(t) do + local padding = math.floor(w / (#t - k + 1)) + c.cw = c.cw + padding + w = w - padding + end + end + end +end + +function UI.Grid:setPageSize(pageSize) + self.pageSize = pageSize +end + +function UI.Grid:getValues() + return self.values +end + +function UI.Grid:setValues(t) + self.values = t + self:update() +end + +function UI.Grid:setInverseSort(inverseSort) + self.inverseSort = inverseSort + self:update() + self:setIndex(self.index) +end + +function UI.Grid:setSortColumn(column) + self.sortColumn = column +end + +function UI.Grid:getDisplayValues(row, key) + return row +end + +function UI.Grid:getSelected() + if self.sorted then + return self.values[self.sorted[self.index]], self.sorted[self.index] + end +end + +function UI.Grid:setSelected(name, value) + if self.sorted then + for k,v in pairs(self.sorted) do + if self.values[v][name] == value then + self:setIndex(k) + return + end + end + end + self:setIndex(1) +end + +function UI.Grid:focus() + self:drawRows() +end + +function UI.Grid:draw() + if not self.disableHeader then + self:drawHeadings() + end + + if self.index <= 0 then + self:setIndex(1) + elseif self.index > #self.sorted then + self:setIndex(#self.sorted) + end + self:drawRows() +end + +-- Something about the displayed table has changed +-- resort the table +function UI.Grid:update() + local function sort(a, b) + if not a[self.sortColumn] then + return false + elseif not b[self.sortColumn] then + return true + end + return self:sortCompare(a, b) + end + + local function inverseSort(a, b) + return not sort(a, b) + end + + local order + if self.sortColumn then + order = sort + if self.inverseSort then + order = inverseSort + end + end + + self.sorted = Util.keys(self.values) + if order then + table.sort(self.sorted, function(a,b) + return order(self.values[a], self.values[b]) + end) + end + + self:adjustWidth() +end + +function UI.Grid:drawHeadings() + if self.headerHeight > 1 then + self:clear(self.headerBackgroundColor) + end + local sb = Writer(self, math.ceil(self.headerHeight / 2)) + for _,col in ipairs(self.columns) do + local ind = ' ' + local color = self.headerTextColor + if col.key == self.sortColumn then + if self.inverseSort then + ind = self.inverseSortIndicator + else + ind = self.sortIndicator + end + color = self.headerSortColor + end + sb:write(ind .. col.heading, + col.cw + 1, + col.justify, + self.headerBackgroundColor, + color) + end + sb:finish(self.headerBackgroundColor) +end + +function UI.Grid:sortCompare(a, b) + a = safeValue(a[self.sortColumn]) + b = safeValue(b[self.sortColumn]) + if type(a) == type(b) then + return a < b + end + return tostring(a) < tostring(b) +end + +function UI.Grid:drawRows() + local startRow = math.max(1, self:getStartRow()) + + local sb = Writer(self, self.disableHeader and 1 or self.headerHeight + 1) + + local lastRow = math.min(startRow + self.pageSize - 1, #self.sorted) + for index = startRow, lastRow do + + local key = self.sorted[index] + local rawRow = self.values[key] + local row = self:getDisplayValues(rawRow, key) + + local ind = ' ' + if self.focused and index == self.index and not self.inactive then + ind = self.focusIndicator + end + + local selected = index == self.index and not self.inactive + local bg = self:getRowBackgroundColor(rawRow, selected) + local fg = self:getRowTextColor(rawRow, selected) + + for _,col in pairs(self.columns) do + sb:write(ind .. safeValue(row[col.key] or ''), + col.cw + 1, + col.justify, + bg, + fg) + ind = ' ' + end + sb:finish(bg) + end + + if sb.y <= self.height then + self:clearArea(1, sb.y, self.width, self.height - sb.y + 1) + end +end + +function UI.Grid:getRowTextColor(row, selected) + if selected then + if self.focused then + return self.textSelectedColor + end + return self.unfocusedTextSelectedColor + end + return self.textColor +end + +function UI.Grid:getRowBackgroundColor(row, selected) + if selected then + if self.focused then + return self.backgroundSelectedColor + end + return self.unfocusedBackgroundSelectedColor + end + return self.backgroundColor +end + +function UI.Grid:getIndex() + return self.index +end + +function UI.Grid:setIndex(index) + index = math.max(1, index) + self.index = math.min(index, #self.sorted) + + local selected = self:getSelected() + if selected ~= self.selected then + self:drawRows() + self.selected = selected + if selected then + self:emit({ type = 'grid_focus_row', selected = selected, element = self }) + end + end +end + +function UI.Grid:getStartRow() + return math.floor((self.index - 1) / self.pageSize) * self.pageSize + 1 +end + +function UI.Grid:getPage() + return math.floor(self.index / self.pageSize) + 1 +end + +function UI.Grid:getPageCount() + local tableSize = Util.size(self.values) + local pc = math.floor(tableSize / self.pageSize) + if tableSize % self.pageSize > 0 then + pc = pc + 1 + end + return pc +end + +function UI.Grid:nextPage() + self:setPage(self:getPage() + 1) +end + +function UI.Grid:previousPage() + self:setPage(self:getPage() - 1) +end + +function UI.Grid:setPage(pageNo) + -- 1 based paging + self:setIndex((pageNo-1) * self.pageSize + 1) +end + +function UI.Grid:eventHandler(event) + if event.type == 'mouse_click' or + event.type == 'mouse_rightclick' or + event.type == 'mouse_doubleclick' then + if not self.disableHeader then + if event.y <= self.headerHeight then + local col = 2 + for _,c in ipairs(self.columns) do + if event.x < col + c.cw then + self:emit({ + type = 'grid_sort', + sortColumn = c.key, + inverseSort = self.sortColumn == c.key and not self.inverseSort, + element = self, + }) + break + end + col = col + c.cw + 1 + end + return true + end + end + local row = self:getStartRow() + event.y - 1 + if not self.disableHeader then + row = row - self.headerHeight + end + if row > 0 and row <= Util.size(self.values) then + self:setIndex(row) + if event.type == 'mouse_doubleclick' then + self:emit({ type = 'key_enter' }) + elseif event.type == 'mouse_rightclick' then + self:emit({ type = 'grid_select_right', selected = self.selected, element = self }) + end + return true + end + return false + + elseif event.type == 'grid_sort' then + self.sortColumn = event.sortColumn + self:setInverseSort(event.inverseSort) + self:draw() + elseif event.type == 'scroll_down' then + self:setIndex(self.index + 1) + elseif event.type == 'scroll_up' then + self:setIndex(self.index - 1) + elseif event.type == 'scroll_top' then + self:setIndex(1) + elseif event.type == 'scroll_bottom' then + self:setIndex(Util.size(self.values)) + elseif event.type == 'scroll_pageUp' then + self:setIndex(self.index - self.pageSize) + elseif event.type == 'scroll_pageDown' then + self:setIndex(self.index + self.pageSize) + elseif event.type == 'scroll_to' then + self:setIndex(event.offset) + elseif event.type == 'key_enter' then + if self.selected then + self:emit({ type = 'grid_select', selected = self.selected, element = self }) + end + elseif event.type == 'copy' then + if self.selected then + os.queueEvent('clipboard_copy', self.selected) + end + else + return false + end + return true +end diff --git a/sys/apis/ui/components/Image.lua b/sys/apis/ui/components/Image.lua new file mode 100644 index 0000000..630cf3c --- /dev/null +++ b/sys/apis/ui/components/Image.lua @@ -0,0 +1,40 @@ +local class = require('class') +local UI = require('ui') + +UI.Image = class(UI.Window) +UI.Image.defaults = { + UIElement = 'Image', + event = 'button_press', +} +function UI.Image:setParent() + if self.image then + self.height = #self.image + end + if self.image and not self.width then + self.width = #self.image[1] + end + UI.Window.setParent(self) +end + +function UI.Image:draw() + self:clear() + if self.image then + for y = 1, #self.image do + local line = self.image[y] + for x = 1, #line do + local ch = line[x] + if type(ch) == 'number' then + if ch > 0 then + self:write(x, y, ' ', ch) + end + else + self:write(x, y, ch) + end + end + end + end +end + +function UI.Image:setImage(image) + self.image = image +end diff --git a/sys/apis/ui/components/Menu.lua b/sys/apis/ui/components/Menu.lua new file mode 100644 index 0000000..3377a0e --- /dev/null +++ b/sys/apis/ui/components/Menu.lua @@ -0,0 +1,60 @@ +local class = require('class') +local UI = require('ui') + +--[[-- Menu --]]-- +UI.Menu = class(UI.Grid) +UI.Menu.defaults = { + UIElement = 'Menu', + disableHeader = true, + columns = { { heading = 'Prompt', key = 'prompt', width = 20 } }, +} +function UI.Menu:postInit() + self.values = self.menuItems + self.pageSize = #self.menuItems +end + +function UI.Menu:setParent() + UI.Grid.setParent(self) + self.itemWidth = 1 + for _,v in pairs(self.values) do + if #v.prompt > self.itemWidth then + self.itemWidth = #v.prompt + end + end + self.columns[1].width = self.itemWidth + + if self.centered then + self:center() + else + self.width = self.itemWidth + 2 + end +end + +function UI.Menu:center() + self.x = (self.width - self.itemWidth + 2) / 2 + self.width = self.itemWidth + 2 +end + +function UI.Menu:eventHandler(event) + if event.type == 'key' then + if event.key == 'enter' then + local selected = self.menuItems[self.index] + self:emit({ + type = selected.event or 'menu_select', + selected = selected + }) + return true + end + elseif event.type == 'mouse_click' then + if event.y <= #self.menuItems then + UI.Grid.setIndex(self, event.y) + local selected = self.menuItems[self.index] + self:emit({ + type = selected.event or 'menu_select', + selected = selected + }) + return true + end + end + return UI.Grid.eventHandler(self, event) +end diff --git a/sys/apis/ui/components/MenuBar.lua b/sys/apis/ui/components/MenuBar.lua new file mode 100644 index 0000000..34ee7b9 --- /dev/null +++ b/sys/apis/ui/components/MenuBar.lua @@ -0,0 +1,92 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +local function getPosition(element) + local x, y = 1, 1 + repeat + x = element.x + x - 1 + y = element.y + y - 1 + element = element.parent + until not element + return x, y +end + +UI.MenuBar = class(UI.Window) +UI.MenuBar.defaults = { + UIElement = 'MenuBar', + buttons = { }, + height = 1, + backgroundColor = colors.lightGray, + textColor = colors.black, + spacing = 2, + lastx = 1, + showBackButton = false, + buttonClass = 'MenuItem', +} +UI.MenuBar.spacer = { spacer = true, text = 'spacer', inactive = true } + +function UI.MenuBar:postInit() + self:addButtons(self.buttons) +end + +function UI.MenuBar:addButtons(buttons) + if not self.children then + self.children = { } + end + + for _,button in pairs(buttons) do + if button.UIElement then + table.insert(self.children, button) + else + local buttonProperties = { + x = self.lastx, + width = #button.text + self.spacing, + centered = false, + } + self.lastx = self.lastx + buttonProperties.width + UI:mergeProperties(buttonProperties, button) + + button = UI[self.buttonClass](buttonProperties) + if button.name then + self[button.name] = button + else + table.insert(self.children, button) + end + + if button.dropdown then + button.dropmenu = UI.DropMenu { buttons = button.dropdown } + end + end + end + if self.parent then + self:initChildren() + end +end + +function UI.MenuBar:getActive(menuItem) + return not menuItem.inactive +end + +function UI.MenuBar:eventHandler(event) + if event.type == 'button_press' and event.button.dropmenu then + if event.button.dropmenu.enabled then + event.button.dropmenu:hide() + self:refocus() + return true + else + local x, y = getPosition(event.button) + if x + event.button.dropmenu.width > self.width then + x = self.width - event.button.dropmenu.width + 1 + end + for _,c in pairs(event.button.dropmenu.children) do + if not c.spacer then + c.inactive = not self:getActive(c) + end + end + event.button.dropmenu:show(x, y + 1) + end + return true + end +end diff --git a/sys/apis/ui/components/MenuItem.lua b/sys/apis/ui/components/MenuItem.lua new file mode 100644 index 0000000..c4dbc7a --- /dev/null +++ b/sys/apis/ui/components/MenuItem.lua @@ -0,0 +1,14 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +--[[-- MenuItem --]]-- +UI.MenuItem = class(UI.Button) +UI.MenuItem.defaults = { + UIElement = 'MenuItem', + textColor = colors.black, + backgroundColor = colors.lightGray, + textFocusColor = colors.white, + backgroundFocusColor = colors.lightGray, +} diff --git a/sys/apis/ui/components/NftImage.lua b/sys/apis/ui/components/NftImage.lua new file mode 100644 index 0000000..37740c5 --- /dev/null +++ b/sys/apis/ui/components/NftImage.lua @@ -0,0 +1,33 @@ +local class = require('class') +local UI = require('ui') + +UI.NftImage = class(UI.Window) +UI.NftImage.defaults = { + UIElement = 'NftImage', + event = 'button_press', +} +function UI.NftImage:setParent() + if self.image then + self.height = self.image.height + end + if self.image and not self.width then + self.width = self.image.width + end + UI.Window.setParent(self) +end + +function UI.NftImage:draw() + if self.image then + for y = 1, self.image.height do + for x = 1, #self.image.text[y] do + self:write(x, y, self.image.text[y][x], self.image.bg[y][x], self.image.fg[y][x]) + end + end + else + self:clear() + end +end + +function UI.NftImage:setImage(image) + self.image = image +end diff --git a/sys/apis/ui/components/Notification.lua b/sys/apis/ui/components/Notification.lua new file mode 100644 index 0000000..f71408b --- /dev/null +++ b/sys/apis/ui/components/Notification.lua @@ -0,0 +1,67 @@ +local class = require('class') +local Event = require('event') +local Sound = require('sound') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.Notification = class(UI.Window) +UI.Notification.defaults = { + UIElement = 'Notification', + backgroundColor = colors.gray, + height = 3, +} +function UI.Notification:draw() +end + +function UI.Notification:enable() +end + +function UI.Notification:error(value, timeout) + self.backgroundColor = colors.red + Sound.play('entity.villager.no', .5) + self:display(value, timeout) +end + +function UI.Notification:info(value, timeout) + self.backgroundColor = colors.gray + self:display(value, timeout) +end + +function UI.Notification:success(value, timeout) + self.backgroundColor = colors.green + self:display(value, timeout) +end + +function UI.Notification:cancel() + if self.canvas then + Event.cancelNamedTimer('notificationTimer') + self.enabled = false + self.canvas:removeLayer() + self.canvas = nil + end +end + +function UI.Notification:display(value, timeout) + self.enabled = true + local lines = Util.wordWrap(value, self.width - 2) + self.height = #lines + 1 + self.y = self.parent.height - self.height + 1 + if self.canvas then + self.canvas:removeLayer() + end + + self.canvas = self:addLayer(self.backgroundColor, self.textColor) + self:addTransition('expandUp', { ticks = self.height }) + self.canvas:setVisible(true) + self:clear() + for k,v in pairs(lines) do + self:write(2, k, v) + end + + Event.addNamedTimer('notificationTimer', timeout or 3, false, function() + self:cancel() + self:sync() + end) +end diff --git a/sys/apis/ui/components/ProgressBar.lua b/sys/apis/ui/components/ProgressBar.lua new file mode 100644 index 0000000..2a78c5f --- /dev/null +++ b/sys/apis/ui/components/ProgressBar.lua @@ -0,0 +1,18 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +UI.ProgressBar = class(UI.Window) +UI.ProgressBar.defaults = { + UIElement = 'ProgressBar', + progressColor = colors.lime, + backgroundColor = colors.gray, + height = 1, + value = 0, +} +function UI.ProgressBar:draw() + self:clear() + local width = math.ceil(self.value / 100 * self.width) + self:clearArea(1, 1, width, self.height, self.progressColor) +end diff --git a/sys/apis/ui/components/ScrollBar.lua b/sys/apis/ui/components/ScrollBar.lua new file mode 100644 index 0000000..8be6de9 --- /dev/null +++ b/sys/apis/ui/components/ScrollBar.lua @@ -0,0 +1,74 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.ScrollBar = class(UI.Window) +UI.ScrollBar.defaults = { + UIElement = 'ScrollBar', + lineChar = '|', + sliderChar = '#', + upArrowChar = '^', + downArrowChar = 'v', + scrollbarColor = colors.lightGray, + width = 1, + x = -1, + ey = -1, +} +function UI.ScrollBar:draw() + local view = self.parent:getViewArea() + + if view.totalHeight > view.height then + local maxScroll = view.totalHeight - view.height + local percent = view.offsetY / maxScroll + local sliderSize = math.max(1, Util.round(view.height / view.totalHeight * (view.height - 2))) + local x = self.width + + local row = view.y + if not view.static then -- does the container scroll ? + self.height = view.totalHeight + end + + for i = 1, view.height - 2 do + self:write(x, row + i, self.lineChar, nil, self.scrollbarColor) + end + + local y = Util.round((view.height - 2 - sliderSize) * percent) + for i = 1, sliderSize do + self:write(x, row + y + i, self.sliderChar, nil, self.scrollbarColor) + end + + local color = self.scrollbarColor + if view.offsetY > 0 then + color = colors.white + end + self:write(x, row, self.upArrowChar, nil, color) + + color = self.scrollbarColor + if view.offsetY + view.height < view.totalHeight then + color = colors.white + end + self:write(x, row + view.height - 1, self.downArrowChar, nil, color) + end +end + +function UI.ScrollBar:eventHandler(event) + if event.type == 'mouse_click' or event.type == 'mouse_doubleclick' then + if event.x == 1 then + local view = self.parent:getViewArea() + if view.totalHeight > view.height then + if event.y == view.y then + self:emit({ type = 'scroll_up'}) + elseif event.y == view.y + view.height - 1 then + self:emit({ type = 'scroll_down'}) + else + local percent = (event.y - view.y) / (view.height - 2) + local y = math.floor((view.totalHeight - view.height) * percent) + self:emit({ type = 'scroll_to', offset = y }) + end + end + return true + end + end +end diff --git a/sys/apis/ui/components/ScrollingGrid.lua b/sys/apis/ui/components/ScrollingGrid.lua new file mode 100644 index 0000000..c29fe74 --- /dev/null +++ b/sys/apis/ui/components/ScrollingGrid.lua @@ -0,0 +1,60 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +--[[-- ScrollingGrid --]]-- +UI.ScrollingGrid = class(UI.Grid) +UI.ScrollingGrid.defaults = { + UIElement = 'ScrollingGrid', + scrollOffset = 0, + marginRight = 1, +} +function UI.ScrollingGrid:postInit() + self.scrollBar = UI.ScrollBar() +end + +function UI.ScrollingGrid:drawRows() + UI.Grid.drawRows(self) + self.scrollBar:draw() +end + +function UI.ScrollingGrid:getViewArea() + local y = 1 + if not self.disableHeader then + y = y + self.headerHeight + end + + return { + static = true, -- the container doesn't scroll + y = y, -- scrollbar Y + height = self.pageSize, -- viewable height + totalHeight = Util.size(self.values), -- total height + offsetY = self.scrollOffset, -- scroll offset + } +end + +function UI.ScrollingGrid:getStartRow() + local ts = Util.size(self.values) + if ts < self.pageSize then + self.scrollOffset = 0 + end + return self.scrollOffset + 1 +end + +function UI.ScrollingGrid:setIndex(index) + if index < self.scrollOffset + 1 then + self.scrollOffset = index - 1 + elseif index - self.scrollOffset > self.pageSize then + self.scrollOffset = index - self.pageSize + end + + if self.scrollOffset < 0 then + self.scrollOffset = 0 + else + local ts = Util.size(self.values) + if self.pageSize + self.scrollOffset + 1 > ts then + self.scrollOffset = math.max(0, ts - self.pageSize) + end + end + UI.Grid.setIndex(self, index) +end diff --git a/sys/apis/ui/components/SlideOut.lua b/sys/apis/ui/components/SlideOut.lua new file mode 100644 index 0000000..5994c69 --- /dev/null +++ b/sys/apis/ui/components/SlideOut.lua @@ -0,0 +1,51 @@ +local class = require('class') +local UI = require('ui') + +--[[-- SlideOut --]]-- +UI.SlideOut = class(UI.Window) +UI.SlideOut.defaults = { + UIElement = 'SlideOut', + pageType = 'modal', +} +function UI.SlideOut:setParent() + -- TODO: size should be set at this point + self:layout() + self.canvas = self:addLayer() + + UI.Window.setParent(self) +end + +function UI.SlideOut:enable() +end + +function UI.SlideOut:show(...) + self:addTransition('expandUp') + self.canvas:raise() + self.canvas:setVisible(true) + UI.Window.enable(self, ...) + self:draw() + self:capture(self) + self:focusFirst() +end + +function UI.SlideOut:disable() + self.canvas:setVisible(false) + UI.Window.disable(self) +end + +function UI.SlideOut:hide() + self:disable() + self:release(self) + self:refocus() +end + +function UI.SlideOut:eventHandler(event) + if event.type == 'slide_show' then + self:show() + return true + + elseif event.type == 'slide_hide' then + self:hide() + return true + end +end diff --git a/sys/apis/ui/components/StatusBar.lua b/sys/apis/ui/components/StatusBar.lua new file mode 100644 index 0000000..183014a --- /dev/null +++ b/sys/apis/ui/components/StatusBar.lua @@ -0,0 +1,99 @@ +local class = require('class') +local Event = require('event') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.StatusBar = class(UI.Window) +UI.StatusBar.defaults = { + UIElement = 'StatusBar', + backgroundColor = colors.lightGray, + textColor = colors.gray, + height = 1, + ey = -1, +} +function UI.StatusBar:adjustWidth() + -- Can only have 1 adjustable width + if self.columns then + local w = self.width - #self.columns - 1 + for _,c in pairs(self.columns) do + if c.width then + c.cw = c.width -- computed width + w = w - c.width + end + end + for _,c in pairs(self.columns) do + if not c.width then + c.cw = w + end + end + end +end + +function UI.StatusBar:resize() + UI.Window.resize(self) + self:adjustWidth() +end + +function UI.StatusBar:setParent() + UI.Window.setParent(self) + self:adjustWidth() +end + +function UI.StatusBar:setStatus(status) + if self.values ~= status then + self.values = status + self:draw() + end +end + +function UI.StatusBar:setValue(name, value) + if not self.values then + self.values = { } + end + self.values[name] = value +end + +function UI.StatusBar:getValue(name) + if self.values then + return self.values[name] + end +end + +function UI.StatusBar:timedStatus(status, timeout) + timeout = timeout or 3 + self:write(2, 1, Util.widthify(status, self.width-2), self.backgroundColor) + Event.addNamedTimer('statusTimer', timeout, false, function() + if self.parent.enabled then + self:draw() + self:sync() + end + end) +end + +function UI.StatusBar:getColumnWidth(name) + local c = Util.find(self.columns, 'key', name) + return c and c.cw +end + +function UI.StatusBar:setColumnWidth(name, width) + local c = Util.find(self.columns, 'key', name) + if c then + c.cw = width + end +end + +function UI.StatusBar:draw() + if not self.values then + self:clear() + elseif type(self.values) == 'string' then + self:write(1, 1, Util.widthify(' ' .. self.values, self.width)) + else + local s = '' + for _,c in ipairs(self.columns) do + s = s .. ' ' .. Util.widthify(tostring(self.values[c.key] or ''), c.cw) + end + self:write(1, 1, Util.widthify(s, self.width)) + end +end diff --git a/sys/apis/ui/components/Tab.lua b/sys/apis/ui/components/Tab.lua new file mode 100644 index 0000000..d564c86 --- /dev/null +++ b/sys/apis/ui/components/Tab.lua @@ -0,0 +1,12 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +UI.Tab = class(UI.ActiveLayer) +UI.Tab.defaults = { + UIElement = 'Tab', + tabTitle = 'tab', + backgroundColor = colors.cyan, + y = 2, +} diff --git a/sys/apis/ui/components/TabBar.lua b/sys/apis/ui/components/TabBar.lua new file mode 100644 index 0000000..1431314 --- /dev/null +++ b/sys/apis/ui/components/TabBar.lua @@ -0,0 +1,45 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors + +UI.TabBar = class(UI.MenuBar) +UI.TabBar.defaults = { + UIElement = 'TabBar', + buttonClass = 'TabBarMenuItem', + selectedBackgroundColor = colors.cyan, +} +function UI.TabBar:enable() + UI.MenuBar.enable(self) + if not Util.find(self.children, 'selected', true) then + local menuItem = self:getFocusables()[1] + if menuItem then + menuItem.selected = true + end + end +end + +function UI.TabBar:eventHandler(event) + if event.type == 'tab_select' then + local selected, si = Util.find(self.children, 'uid', event.button.uid) + local previous, pi = Util.find(self.children, 'selected', true) + + if si ~= pi then + selected.selected = true + if previous then + previous.selected = false + self:emit({ type = 'tab_change', current = si, last = pi, tab = selected }) + end + end + UI.MenuBar.draw(self) + end + return UI.MenuBar.eventHandler(self, event) +end + +function UI.TabBar:selectTab(text) + local menuItem = Util.find(self.children, 'text', text) + if menuItem then + menuItem.selected = true + end +end diff --git a/sys/apis/ui/components/TabBarMenuItem.lua b/sys/apis/ui/components/TabBarMenuItem.lua new file mode 100644 index 0000000..28e585b --- /dev/null +++ b/sys/apis/ui/components/TabBarMenuItem.lua @@ -0,0 +1,25 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +--[[-- TabBarMenuItem --]]-- +UI.TabBarMenuItem = class(UI.Button) +UI.TabBarMenuItem.defaults = { + UIElement = 'TabBarMenuItem', + event = 'tab_select', + textColor = colors.black, + selectedBackgroundColor = colors.cyan, + unselectedBackgroundColor = colors.lightGray, + backgroundColor = colors.lightGray, +} +function UI.TabBarMenuItem:draw() + if self.selected then + self.backgroundColor = self.selectedBackgroundColor + self.backgroundFocusColor = self.selectedBackgroundColor + else + self.backgroundColor = self.unselectedBackgroundColor + self.backgroundFocusColor = self.unselectedBackgroundColor + end + UI.Button.draw(self) +end diff --git a/sys/apis/ui/components/Tabs.lua b/sys/apis/ui/components/Tabs.lua new file mode 100644 index 0000000..7c2d967 --- /dev/null +++ b/sys/apis/ui/components/Tabs.lua @@ -0,0 +1,89 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +UI.Tabs = class(UI.Window) +UI.Tabs.defaults = { + UIElement = 'Tabs', +} +function UI.Tabs:postInit() + self:add(self) +end + +function UI.Tabs:add(children) + local buttons = { } + for _,child in pairs(children) do + if type(child) == 'table' and child.UIElement and child.tabTitle then + child.y = 2 + table.insert(buttons, { + text = child.tabTitle, + event = 'tab_select', + tabUid = child.uid, + }) + end + end + + if not self.tabBar then + self.tabBar = UI.TabBar({ + buttons = buttons, + }) + else + self.tabBar:addButtons(buttons) + end + + if self.parent then + return UI.Window.add(self, children) + end +end + +function UI.Tabs:selectTab(tab) + local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) + if menuItem then + self.tabBar:emit({ type = 'tab_select', button = { uid = menuItem.uid } }) + end +end + +function UI.Tabs:setActive(tab, active) + local menuItem = Util.find(self.tabBar.children, 'tabUid', tab.uid) + if menuItem then + menuItem.inactive = not active + end +end + +function UI.Tabs:enable() + self.enabled = true + self.transitionHint = nil + self.tabBar:enable() + + local menuItem = Util.find(self.tabBar.children, 'selected', true) + + for _,child in pairs(self.children) do + if child.uid == menuItem.tabUid then + child:enable() + self:emit({ type = 'tab_activate', activated = child }) + elseif child.tabTitle then + child:disable() + end + end +end + +function UI.Tabs:eventHandler(event) + if event.type == 'tab_change' then + local tab = self:find(event.tab.tabUid) + if event.current > event.last then + self.transitionHint = 'slideLeft' + else + self.transitionHint = 'slideRight' + end + + for _,child in pairs(self.children) do + if child.uid == event.tab.tabUid then + child:enable() + elseif child.tabTitle then + child:disable() + end + end + self:emit({ type = 'tab_activate', activated = tab }) + tab:draw() + end +end diff --git a/sys/apis/ui/components/Text.lua b/sys/apis/ui/components/Text.lua new file mode 100644 index 0000000..96310ec --- /dev/null +++ b/sys/apis/ui/components/Text.lua @@ -0,0 +1,20 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +UI.Text = class(UI.Window) +UI.Text.defaults = { + UIElement = 'Text', + value = '', + height = 1, +} +function UI.Text:setParent() + if not self.width and not self.ex then + self.width = #tostring(self.value) + end + UI.Window.setParent(self) +end + +function UI.Text:draw() + self:write(1, 1, Util.widthify(self.value or '', self.width), self.backgroundColor) +end diff --git a/sys/apis/ui/components/TextArea.lua b/sys/apis/ui/components/TextArea.lua new file mode 100644 index 0000000..8602866 --- /dev/null +++ b/sys/apis/ui/components/TextArea.lua @@ -0,0 +1,36 @@ +local class = require('class') +local UI = require('ui') + +--[[-- TextArea --]]-- +UI.TextArea = class(UI.Viewport) +UI.TextArea.defaults = { + UIElement = 'TextArea', + marginRight = 2, + value = '', +} +function UI.TextArea:postInit() + self.scrollBar = UI.ScrollBar() +end + +function UI.TextArea:setText(text) + self:reset() + self.value = text + self:draw() +end + +function UI.TextArea:focus() + -- allow keyboard scrolling +end + +function UI.TextArea:draw() + self:clear() +-- self:setCursorPos(1, 1) + self.cursorX, self.cursorY = 1, 1 + self:print(self.value) + + for _,child in pairs(self.children) do + if child.enabled then + child:draw() + end + end +end diff --git a/sys/apis/ui/components/TextEntry.lua b/sys/apis/ui/components/TextEntry.lua new file mode 100644 index 0000000..384c098 --- /dev/null +++ b/sys/apis/ui/components/TextEntry.lua @@ -0,0 +1,189 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors +local os = _G.os +local _rep = string.rep + +UI.TextEntry = class(UI.Window) +UI.TextEntry.defaults = { + UIElement = 'TextEntry', + value = '', + shadowText = '', + focused = false, + textColor = colors.white, + shadowTextColor = colors.gray, + backgroundColor = colors.black, -- colors.lightGray, + backgroundFocusColor = colors.black, --lightGray, + height = 1, + limit = 6, + pos = 0, + accelerators = { + [ 'control-c' ] = 'copy', + } +} +function UI.TextEntry:postInit() + self.value = tostring(self.value) +end + +function UI.TextEntry:setValue(value) + self.value = value +end + +function UI.TextEntry:setPosition(pos) + self.pos = pos +end + +function UI.TextEntry:updateScroll() + if not self.scroll then + self.scroll = 0 + end + + if not self.pos then + self.pos = #tostring(self.value) + self.scroll = 0 + elseif self.pos > #tostring(self.value) then + self.pos = #tostring(self.value) + self.scroll = 0 + end + + if self.pos - self.scroll > self.width - 2 then + self.scroll = self.pos - (self.width - 2) + elseif self.pos < self.scroll then + self.scroll = self.pos + end +end + +function UI.TextEntry:draw() + local bg = self.backgroundColor + local tc = self.textColor + if self.focused then + bg = self.backgroundFocusColor + end + + self:updateScroll() + local text = tostring(self.value) + if #text > 0 then + if self.scroll and self.scroll > 0 then + text = text:sub(1 + self.scroll) + end + if self.mask then + text = _rep('*', #text) + end + else + tc = self.shadowTextColor + text = self.shadowText + end + + self:write(1, 1, ' ' .. Util.widthify(text, self.width - 2) .. ' ', bg, tc) + if self.focused then + self:setCursorPos(self.pos-self.scroll+2, 1) + end +end + +function UI.TextEntry:reset() + self.pos = 0 + self.value = '' + self:draw() + self:updateCursor() +end + +function UI.TextEntry:updateCursor() + self:updateScroll() + self:setCursorPos(self.pos-self.scroll+2, 1) +end + +function UI.TextEntry:focus() + self:draw() + if self.focused then + self:setCursorBlink(true) + else + self:setCursorBlink(false) + end +end + +--[[ + A few lines below from theoriginalbit + http://www.computercraft.info/forums2/index.php?/topic/16070-read-and-limit-length-of-the-input-field/ +--]] +function UI.TextEntry:eventHandler(event) + if event.type == 'key' then + local ch = event.key + if ch == 'left' then + if self.pos > 0 then + self.pos = math.max(self.pos-1, 0) + self:draw() + end + elseif ch == 'right' then + local input = tostring(self.value) + if self.pos < #input then + self.pos = math.min(self.pos+1, #input) + self:draw() + end + elseif ch == 'home' then + self.pos = 0 + self:draw() + elseif ch == 'end' then + self.pos = #tostring(self.value) + self:draw() + elseif ch == 'backspace' then + if self.pos > 0 then + local input = tostring(self.value) + self.value = input:sub(1, self.pos-1) .. input:sub(self.pos+1) + self.pos = self.pos - 1 + self:draw() + self:emit({ type = 'text_change', text = self.value, element = self }) + end + elseif ch == 'delete' then + local input = tostring(self.value) + if self.pos < #input then + self.value = input:sub(1, self.pos) .. input:sub(self.pos+2) + self:draw() + self:emit({ type = 'text_change', text = self.value, element = self }) + end + elseif #ch == 1 then + local input = tostring(self.value) + if #input < self.limit then + self.value = input:sub(1, self.pos) .. ch .. input:sub(self.pos+1) + self.pos = self.pos + 1 + self:draw() + self:emit({ type = 'text_change', text = self.value, element = self }) + end + else + return false + end + return true + + elseif event.type == 'copy' then + os.queueEvent('clipboard_copy', self.value) + + elseif event.type == 'paste' then + local input = tostring(self.value) + local text = event.text + if #input + #text > self.limit then + text = text:sub(1, self.limit-#input) + end + self.value = input:sub(1, self.pos) .. text .. input:sub(self.pos+1) + self.pos = self.pos + #text + self:draw() + self:updateCursor() + self:emit({ type = 'text_change', text = self.value, element = self }) + return true + + elseif event.type == 'mouse_click' then + if self.focused and event.x > 1 then + self.pos = event.x + self.scroll - 2 + self:updateCursor() + return true + end + elseif event.type == 'mouse_rightclick' then + local input = tostring(self.value) + if #input > 0 then + self:reset() + self:emit({ type = 'text_change', text = self.value, element = self }) + end + end + + return false +end diff --git a/sys/apis/ui/components/Throttle.lua b/sys/apis/ui/components/Throttle.lua new file mode 100644 index 0000000..1e2dc02 --- /dev/null +++ b/sys/apis/ui/components/Throttle.lua @@ -0,0 +1,65 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors +local os = _G.os + +UI.Throttle = class(UI.Window) +UI.Throttle.defaults = { + UIElement = 'Throttle', + backgroundColor = colors.gray, + bordercolor = colors.cyan, + height = 4, + width = 10, + timeout = .075, + ctr = 0, + image = { + ' //) (O )~@ &~&-( ?Q ', + ' //) (O )- @ \\-( ?) && ', + ' //) (O ), @ \\-(?) && ', + ' //) (O ). @ \\-d ) (@ ' + } +} +function UI.Throttle:setParent() + self.x = math.ceil((self.parent.width - self.width) / 2) + self.y = math.ceil((self.parent.height - self.height) / 2) + UI.Window.setParent(self) +end + +function UI.Throttle:enable() + self.c = os.clock() + self.enabled = false +end + +function UI.Throttle:disable() + if self.canvas then + self.enabled = false + self.canvas:removeLayer() + self.canvas = nil + self.ctr = 0 + end +end + +function UI.Throttle:update() + local cc = os.clock() + if cc > self.c + self.timeout then + os.sleep(0) + self.c = os.clock() + self.enabled = true + if not self.canvas then + self.canvas = self:addLayer(self.backgroundColor, self.borderColor) + self.canvas:setVisible(true) + self:clear(self.borderColor) + end + local image = self.image[self.ctr + 1] + local width = self.width - 2 + for i = 0, #self.image do + self:write(2, i + 1, image:sub(width * i + 1, width * i + width), + self.backgroundColor, self.textColor) + end + + self.ctr = (self.ctr + 1) % #self.image + + self:sync() + end +end diff --git a/sys/apis/ui/components/TitleBar.lua b/sys/apis/ui/components/TitleBar.lua new file mode 100644 index 0000000..0a464ab --- /dev/null +++ b/sys/apis/ui/components/TitleBar.lua @@ -0,0 +1,73 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors +local _rep = string.rep +local _sub = string.sub + +-- For manipulating text in a fixed width string +local SB = class() +function SB:init(width) + self.width = width + self.buf = _rep(' ', width) +end +function SB:insert(x, str, width) + if x < 1 then + x = self.width + x + 1 + end + width = width or #str + if x + width - 1 > self.width then + width = self.width - x + end + if width > 0 then + self.buf = _sub(self.buf, 1, x - 1) .. _sub(str, 1, width) .. _sub(self.buf, x + width) + end +end +function SB:fill(x, ch, width) + width = width or self.width - x + 1 + self:insert(x, _rep(ch, width)) +end +function SB:center(str) + self:insert(math.max(1, math.ceil((self.width - #str + 1) / 2)), str) +end +function SB:get() + return self.buf +end + +UI.TitleBar = class(UI.Window) +UI.TitleBar.defaults = { + UIElement = 'TitleBar', + height = 1, + textColor = colors.white, + backgroundColor = colors.cyan, + title = '', + frameChar = '-', + closeInd = '*', +} +function UI.TitleBar:draw() + local sb = SB(self.width) + sb:fill(2, self.frameChar, sb.width - 3) + sb:center(string.format(' %s ', self.title)) + if self.previousPage or self.event then + sb:insert(-1, self.closeInd) + else + sb:insert(-2, self.frameChar) + end + self:write(1, 1, sb:get()) +end + +function UI.TitleBar:eventHandler(event) + if event.type == 'mouse_click' then + if (self.previousPage or self.event) and event.x == self.width then + if self.event then + self:emit({ type = self.event, element = self }) + elseif type(self.previousPage) == 'string' or + type(self.previousPage) == 'table' then + UI:setPage(self.previousPage) + else + UI:setPreviousPage() + end + return true + end + end +end diff --git a/sys/apis/ui/components/VerticalMeter.lua b/sys/apis/ui/components/VerticalMeter.lua new file mode 100644 index 0000000..e4f1e7b --- /dev/null +++ b/sys/apis/ui/components/VerticalMeter.lua @@ -0,0 +1,18 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +UI.VerticalMeter = class(UI.Window) +UI.VerticalMeter.defaults = { + UIElement = 'VerticalMeter', + backgroundColor = colors.gray, + meterColor = colors.lime, + width = 1, + value = 0, +} +function UI.VerticalMeter:draw() + local height = self.height - math.ceil(self.value / 100 * self.height) + self:clear() + self:clearArea(1, height + 1, self.width, self.height, self.meterColor) +end diff --git a/sys/apis/ui/components/Viewport.lua b/sys/apis/ui/components/Viewport.lua new file mode 100644 index 0000000..e8289bd --- /dev/null +++ b/sys/apis/ui/components/Viewport.lua @@ -0,0 +1,96 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +--[[-- Viewport --]]-- +UI.Viewport = class(UI.Window) +UI.Viewport.defaults = { + UIElement = 'Viewport', + backgroundColor = colors.cyan, + accelerators = { + down = 'scroll_down', + up = 'scroll_up', + home = 'scroll_top', + [ 'end' ] = 'scroll_bottom', + pageUp = 'scroll_pageUp', + [ 'control-b' ] = 'scroll_pageUp', + pageDown = 'scroll_pageDown', + [ 'control-f' ] = 'scroll_pageDown', + }, +} +function UI.Viewport:setParent() + UI.Window.setParent(self) + self.canvas = self:addLayer() +end + +function UI.Viewport:enable() + UI.Window.enable(self) + self.canvas:setVisible(true) +end + +function UI.Viewport:disable() + UI.Window.disable(self) + self.canvas:setVisible(false) +end + +function UI.Viewport:setScrollPosition(offset) + local oldOffset = self.offy + self.offy = math.max(offset, 0) + self.offy = math.min(self.offy, math.max(#self.canvas.lines, self.height) - self.height) + if self.offy ~= oldOffset then + if self.scrollBar then + self.scrollBar:draw() + end + self.canvas.offy = offset + self.canvas:dirty() + end +end + +function UI.Viewport:write(x, y, text, bg, tc) + if y > #self.canvas.lines then + for i = #self.canvas.lines, y do + self.canvas.lines[i + 1] = { } + self.canvas:clearLine(i + 1, self.backgroundColor, self.textColor) + end + end + return UI.Window.write(self, x, y, text, bg, tc) +end + +function UI.Viewport:reset() + self.offy = 0 + self.canvas.offy = 0 + for i = self.height + 1, #self.canvas.lines do + self.canvas.lines[i] = nil + end +end + +function UI.Viewport:getViewArea() + return { + y = (self.offy or 0) + 1, + height = self.height, + totalHeight = #self.canvas.lines, + offsetY = self.offy or 0, + } +end + +function UI.Viewport:eventHandler(event) + if event.type == 'scroll_down' then + self:setScrollPosition(self.offy + 1) + elseif event.type == 'scroll_up' then + self:setScrollPosition(self.offy - 1) + elseif event.type == 'scroll_top' then + self:setScrollPosition(0) + elseif event.type == 'scroll_bottom' then + self:setScrollPosition(10000000) + elseif event.type == 'scroll_pageUp' then + self:setScrollPosition(self.offy - self.height) + elseif event.type == 'scroll_pageDown' then + self:setScrollPosition(self.offy + self.height) + elseif event.type == 'scroll_to' then + self:setScrollPosition(event.offset) + else + return false + end + return true +end diff --git a/sys/apis/ui/components/Wizard.lua b/sys/apis/ui/components/Wizard.lua new file mode 100644 index 0000000..67dcc2b --- /dev/null +++ b/sys/apis/ui/components/Wizard.lua @@ -0,0 +1,124 @@ +local class = require('class') +local UI = require('ui') +local Util = require('util') + +UI.Wizard = class(UI.Window) +UI.Wizard.defaults = { + UIElement = 'Wizard', + pages = { }, +} +function UI.Wizard:postInit() + self.cancelButton = UI.Button { + x = 2, y = -1, + text = 'Cancel', + event = 'cancel', + } + self.previousButton = UI.Button { + x = -18, y = -1, + text = '< Back', + event = 'previousView', + } + self.nextButton = UI.Button { + x = -9, y = -1, + text = 'Next >', + event = 'nextView', + } + + Util.merge(self, self.pages) + --for _, child in pairs(self.pages) do + -- child.ey = -2 + --end +end + +function UI.Wizard:add(pages) + Util.merge(self.pages, pages) + Util.merge(self, pages) + + for _, child in pairs(self.pages) do + child.ey = child.ey or -2 + end + + if self.parent then + self:initChildren() + end +end + +function UI.Wizard:getPage(index) + return Util.find(self.pages, 'index', index) +end + +function UI.Wizard:enable(...) + self.enabled = true + self.index = 1 + self.transitionHint = nil + local initial = self:getPage(1) + for _,child in pairs(self.children) do + if child == initial or not child.index then + child:enable(...) + else + child:disable() + end + end + self:emit({ type = 'enable_view', next = initial }) +end + +function UI.Wizard:isViewValid() + local currentView = self:getPage(self.index) + return not currentView.validate and true or currentView:validate() +end + +function UI.Wizard:eventHandler(event) + if event.type == 'nextView' then + local currentView = self:getPage(self.index) + if self:isViewValid() then + self.index = self.index + 1 + local nextView = self:getPage(self.index) + currentView:emit({ type = 'enable_view', next = nextView, current = currentView }) + end + + elseif event.type == 'previousView' then + local currentView = self:getPage(self.index) + local nextView = self:getPage(self.index - 1) + if nextView then + self.index = self.index - 1 + currentView:emit({ type = 'enable_view', prev = nextView, current = currentView }) + end + return true + + elseif event.type == 'wizard_complete' then + if self:isViewValid() then + self:emit({ type = 'accept' }) + end + + elseif event.type == 'enable_view' then + local current = event.next or event.prev + if not current then error('property "index" is required on wizard pages') end + + if event.current then + if event.next then + self.transitionHint = 'slideLeft' + elseif event.prev then + self.transitionHint = 'slideRight' + end + event.current:disable() + end + + if self:getPage(self.index - 1) then + self.previousButton:enable() + else + self.previousButton:disable() + end + + if self:getPage(self.index + 1) then + self.nextButton.text = 'Next >' + self.nextButton.event = 'nextView' + else + self.nextButton.text = 'Accept' + self.nextButton.event = 'wizard_complete' + end + -- a new current view + current:enable() + current:emit({ type = 'view_enabled', view = current }) + self:draw() + end +end diff --git a/sys/apis/ui/components/WizardPage.lua b/sys/apis/ui/components/WizardPage.lua new file mode 100644 index 0000000..dae4e9a --- /dev/null +++ b/sys/apis/ui/components/WizardPage.lua @@ -0,0 +1,11 @@ +local class = require('class') +local UI = require('ui') + +local colors = _G.colors + +UI.WizardPage = class(UI.ActiveLayer) +UI.WizardPage.defaults = { + UIElement = 'WizardPage', + backgroundColor = colors.cyan, + ey = -2, +} diff --git a/sys/apis/ui/transition.lua b/sys/apis/ui/transition.lua index f6c7af3..90db9ee 100644 --- a/sys/apis/ui/transition.lua +++ b/sys/apis/ui/transition.lua @@ -3,35 +3,33 @@ local Tween = require('ui.tween') local Transition = { } function Transition.slideLeft(args) - local ticks = args.ticks or 6 + local ticks = args.ticks or 10 local easing = args.easing or 'outQuint' local pos = { x = args.ex } local tween = Tween.new(ticks, pos, { x = args.x }, easing) args.canvas:move(pos.x, args.canvas.y) - return function(device) + return function() local finished = tween:update(1) args.canvas:move(math.floor(pos.x), args.canvas.y) args.canvas:dirty() - args.canvas:render(device) return not finished end end function Transition.slideRight(args) - local ticks = args.ticks or 6 + local ticks = args.ticks or 10 local easing = args.easing or'outQuint' local pos = { x = -args.canvas.width } local tween = Tween.new(ticks, pos, { x = 1 }, easing) args.canvas:move(pos.x, args.canvas.y) - return function(device) + return function() local finished = tween:update(1) args.canvas:move(math.floor(pos.x), args.canvas.y) args.canvas:dirty() - args.canvas:render(device) return not finished end end @@ -44,11 +42,10 @@ function Transition.expandUp(args) args.canvas:move(args.x, pos.y) - return function(device) + return function() local finished = tween:update(1) args.canvas:move(args.x, math.floor(pos.y)) args.canvas:dirty() - args.canvas:render(device) return not finished end end diff --git a/sys/apps/Installer.lua b/sys/apps/Installer.lua deleted file mode 100644 index da576a5..0000000 --- a/sys/apps/Installer.lua +++ /dev/null @@ -1,457 +0,0 @@ -local colors = _G.colors -local fs = _G.fs -local http = _G.http -local install = _ENV.install -local os = _G.os - -local injector -if not install.testing then - _G.OPUS_BRANCH = 'master-1.8' - local url ='https://raw.githubusercontent.com/kepler155c/opus/master-1.8/sys/apis/injector.lua' - injector = load(http.get(url).readAll(), 'injector.lua', nil, _ENV)() -else - injector = _G.requireInjector -end - -injector(_ENV) - -if not install.testing then - if package then - for _ = 1, 4 do - table.remove(package.loaders, 1) - end - end -end - -local Git = require('git') -local UI = require('ui') -local Util = require('util') - -local currentFile = '' -local currentProgress = 0 -local cancelEvent - -local args = { ... } -local steps = install.steps[args[1] or 'install'] - -if not steps then - error('Invalid install type') -end - -local mode = steps[#steps] - -if UI.term.width < 32 then - cancelEvent = 'quit' -end - -local page = UI.Page { - backgroundColor = colors.cyan, - titleBar = UI.TitleBar { - event = cancelEvent, - }, - wizard = UI.Wizard { - y = 2, ey = -2, - }, - notification = UI.Notification(), - accelerators = { - q = 'quit', - }, -} - -local pages = { - splash = UI.Viewport { }, - review = UI.Viewport { }, - license = UI.Viewport { - backgroundColor = colors.black, - }, - branch = UI.Window { - grid = UI.ScrollingGrid { - ey = -3, - columns = { - { heading = 'Branch', key = 'branch' }, - { heading = 'Description', key = 'description' }, - }, - values = install.branches, - autospace = true, - }, - }, - files = UI.Window { - grid = UI.ScrollingGrid { - ey = -3, - columns = { - { heading = 'Files', key = 'file' }, - }, - sortColumn = 'file', - }, - }, - install = UI.Window { - progressBar = UI.ProgressBar { - y = -1, - }, - }, - uninstall = UI.Window { - progressBar = UI.ProgressBar { - y = -1, - }, - }, -} - -local function getFileList() - if install.gitRepo then - local gitFiles = Git.list(string.format('%s/%s', install.gitRepo, install.gitBranch or 'master')) - install.files = { } - install.diskspace = 0 - for path, entry in pairs(gitFiles) do - install.files[path] = entry.url - install.diskspace = install.diskspace + entry.size - end - end - - if not install.files or Util.empty(install.files) then - error('File list is missing or empty') - end -end - ---[[ Splash ]]-- -function pages.splash:enable() - page.titleBar.title = 'Installer v1.0' - UI.Viewport.enable(self) -end - -function pages.splash:draw() - self:clear() - self:setCursorPos(1, 1) - self:print( - string.format('%s v%s\n', install.title, install.version), nil, colors.yellow) - self:print( - string.format('By: %s\n\n%s\n', install.author, install.description)) - - self.ymax = self.cursorY -end - ---[[ License ]]-- -function pages.license:enable() - page.titleBar.title = 'License Review' - page.wizard.nextButton.text = 'Accept' - UI.Viewport.enable(self) -end - -function pages.license:draw() - self:clear() - self:setCursorPos(1, 1) - self:print( - string.format('Copyright (c) %s %s\n\n', install.copyrightYear, - install.copyrightHolders), - nil, colors.yellow) - self:print(install.license) - - self.ymax = self.cursorY + 1 -end - ---[[ Review ]]-- -function pages.review:enable() - if mode == 'uninstall' then - page.nextButton.text = 'Remove' - page.titleBar.title = 'Remove Installed Files' - else - page.wizard.nextButton.text = 'Begin' - page.titleBar.title = 'Download and Install' - end - UI.Viewport.enable(self) -end - -function pages.review:draw() - self:clear() - self:setCursorPos(1, 1) - - local text = 'Ready to begin installation.\n\nProceeding will download and install the files to the hard drive.' - if mode == 'uninstall' then - text = 'Ready to begin.\n\nProceeding will remove the files previously installed.' - end - self:print(text) - - self.ymax = self.cursorY + 1 -end - ---[[ Files ]]-- -function pages.files:enable() - page.titleBar.title = 'Review Files' - self.grid.values = { } - for k,v in pairs(install.files) do - table.insert(self.grid.values, { file = k, code = v }) - end - self.grid:update() - UI.Window.enable(self) -end - -function pages.files:draw() - self:clear() - - local function formatSize(size) - if size >= 1000000 then - return string.format('%dM', math.floor(size/1000000, 2)) - elseif size >= 1000 then - return string.format('%dK', math.floor(size/1000, 2)) - end - return size - end - - if install.diskspace then - - local bg = self.backgroundColor - - local diskFree = fs.getFreeSpace('/') - if install.diskspace > diskFree then - bg = colors.red - end - - local text = string.format('Space Required: %s, Free: %s', - formatSize(install.diskspace), formatSize(diskFree)) - - if #text > self.width then - text = string.format('Space: %s Free: %s', - formatSize(install.diskspace), formatSize(diskFree)) - end - - self:write(1, self.height, Util.widthify(text, self.width), bg) - end - self.grid:draw() -end - ---[[ -function pages.files:view(url) - local s, m = pcall(function() - page.notification:info('Downloading') - page:sync() - Util.download(url, '/.source') - end) - page.notification:disable() - if s then - shell.run('edit /.source') - fs.delete('/.source') - page:draw() - page.notification:cancel() - else - page.notification:error(m:gsub('.*: (.*)', '%1')) - end -end - -function pages.files:eventHandler(event) - if event.type == 'grid_select' then - self:view(event.selected.code) - return true - end -end ---]] - -local function drawCommon(self) - if currentFile then - self:write(1, 3, 'File:') - self:write(1, 4, Util.widthify(currentFile, self.width)) - else - self:write(1, 3, 'Finished') - end - if self.failed then - self:write(1, 5, Util.widthify(self.failed, self.width), colors.red) - end - self:write(1, self.height - 1, 'Progress') - - self.progressBar.value = currentProgress - self.progressBar:draw() - self:sync() -end - ---[[ Branch ]]-- -function pages.branch:enable() - page.titleBar.title = 'Select Branch' - UI.Window.enable(self) -end - -function pages.branch:eventHandler(event) - -- user is navigating to next view (not previous) - if event.type == 'enable_view' and event.next then - install.gitBranch = self.grid:getSelected().branch - getFileList() - end -end - ---[[ Install ]]-- -function pages.install:enable() - page.wizard.cancelButton:disable() - page.wizard.previousButton:disable() - page.wizard.nextButton:disable() - - page.titleBar.title = 'Installing...' - page.titleBar.event = nil - - UI.Window.enable(self) - - page:draw() - page:sync() - - local i = 0 - local numFiles = Util.size(install.files) - for filename,url in pairs(install.files) do - currentFile = filename - currentProgress = i / numFiles * 100 - self:draw(self) - self:sync() - local s, m = pcall(function() - Util.download(url, fs.combine(install.directory or '', filename)) - end) - if not s then - self.failed = m:gsub('.*: (.*)', '%1') - break - end - i = i + 1 - end - - if not self.failed then - currentProgress = 100 - currentFile = nil - - if install.postInstall then - local s, m = pcall(function() install.postInstall(page, UI) end) - if not s then - self.failed = m:gsub('.*: (.*)', '%1') - end - end - end - - page.wizard.nextButton.text = 'Exit' - page.wizard.nextButton.event = 'quit' - if not self.failed and install.rebootAfter then - page.wizard.nextButton.text = 'Reboot' - page.wizard.nextButton.event = 'reboot' - end - - page.wizard.nextButton:enable() - page:draw() - page:sync() - - if not self.failed and Util.key(args, 'automatic') then - if install.rebootAfter then - os.reboot() - else - UI:exitPullEvents() - end - end -end - -function pages.install:draw() - self:clear() - local text = 'The files are being installed' - if #text > self.width then - text = 'Installing files' - end - self:write(1, 1, text, nil, colors.yellow) - - drawCommon(self) -end - ---[[ Uninstall ]]-- -function pages.uninstall:enable() - page.wizard.cancelButton:disable() - page.wizard.previousButton:disable() - page.wizard.nextButton:disable() - - page.titleBar.title = 'Uninstalling...' - page.titleBar.event = nil - - page:draw() - page:sync() - - UI.Window.enable(self) - - local function pruneDir(dir) - if #dir > 0 then - if fs.exists(dir) then - local files = fs.list(dir) - if #files == 0 then - fs.delete(dir) - pruneDir(fs.getDir(dir)) - end - end - end - end - - local i = 0 - local numFiles = Util.size(install.files) - for k in pairs(install.files) do - currentFile = k - currentProgress = i / numFiles * 100 - self:draw() - self:sync() - fs.delete(k) - pruneDir(fs.getDir(k)) - i = i + 1 - end - - currentProgress = 100 - currentFile = nil - - page.wizard.nextButton.text = 'Exit' - page.wizard.nextButton.event = 'quit' - page.wizard.nextButton:enable() - - page:draw() - page:sync() -end - -function pages.uninstall:draw() - self:clear() - self:write(1, 1, 'Uninstalling files', nil, colors.yellow) - drawCommon(self) -end - -function page:eventHandler(event) - if event.type == 'cancel' then - UI:exitPullEvents() - - elseif event.type == 'reboot' then - os.reboot() - - elseif event.type == 'quit' then - UI:exitPullEvents() - - else - return UI.Page.eventHandler(self, event) - end - return true -end - -function page:enable() - UI.Page.enable(self) - self:setFocus(page.wizard.nextButton) - if UI.term.width < 32 then - page.wizard.cancelButton:disable() - page.wizard.previousButton.x = 2 - end -end - -getFileList() - -local wizardPages = { } -for k,v in ipairs(steps) do - if not pages[v] then - error('Invalid step: ' .. v) - end - wizardPages[k] = pages[v] - wizardPages[k].index = k - wizardPages[k].x = 2 - wizardPages[k].y = 2 - wizardPages[k].ey = -3 - wizardPages[k].ex = -2 -end -page.wizard:add(wizardPages) - -if Util.key(steps, 'install') and install.preInstall then - install.preInstall(page, UI) -end - -UI:setPage(page) -local s, m = pcall(function() UI:pullEvents() end) -if not s then - UI.term:reset() - _G.printError(m) -end diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index f4653a2..78e3a13 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -58,6 +58,7 @@ local page = UI.Page { }, output = UI.Embedded { y = -6, + visible = true, backgroundColor = colors.gray, }, } @@ -328,6 +329,7 @@ function page:executeStatement(statement) local s, m local oterm = term.redirect(self.output.win) + self.output.win.scrollBottom() pcall(function() s, m = self:rawExecute(command) end) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 2fb9871..797a1a7 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -252,7 +252,7 @@ end function page.container:setCategory(categoryName, animate) -- reset the viewport window self.children = { } - self.offy = 0 + self:reset() local function filter(it, f) local ot = { } @@ -334,10 +334,10 @@ function page.container:setCategory(categoryName, animate) for k,child in ipairs(self.children) do if r == 1 then child.x = math.random(1, self.width) - child.y = math.random(1, self.height) + child.y = math.random(1, self.height - 3) elseif r == 2 then child.x = self.width - child.y = self.height + child.y = self.height - 3 elseif r == 3 then child.x = math.floor(self.width / 2) child.y = math.floor(self.height / 2) @@ -349,7 +349,7 @@ function page.container:setCategory(categoryName, animate) child.y = row if k == #self.children then child.x = self.width - child.y = self.height + child.y = self.height - 3 end end child.tween = Tween.new(6, child, { x = col, y = row }, 'linear') @@ -369,10 +369,10 @@ function page.container:setCategory(categoryName, animate) end self:initChildren() - if animate then -- need to fix transitions under layers - local function transition(args) + if animate then + local function transition() local i = 1 - return function(device) + return function() self:clear() for _,child in pairs(self.children) do child.tween:update(1) @@ -380,7 +380,6 @@ function page.container:setCategory(categoryName, animate) child.y = math.floor(child.y) child:draw() end - args.canvas:blit(device, args, args) i = i + 1 return i < 7 end diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index a52964f..ea4bab9 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -45,8 +45,10 @@ local page = UI.Page { help = 'Download the latest package list', }, action = UI.SlideOut { - backgroundColor = colors.cyan, + backgroundColor = colors.brown, + y = 3, titleBar = UI.TitleBar { + backgroundColor = colors.brown, event = 'hide-action', }, button = UI.Button { @@ -56,9 +58,6 @@ local page = UI.Page { output = UI.Embedded { y = 5, ey = -2, x = 2, ex = -2, }, - statusBar = UI.StatusBar { - backgroundColor = colors.cyan, - }, }, statusBar = UI.StatusBar { }, } @@ -101,9 +100,10 @@ function page.grid:getRowTextColor(row, selected) end function page.action:show() + self.output.win:clear() UI.SlideOut.show(self) - self.output:draw() - self.output.win.redraw() + --self.output:draw() + --self.output.win.redraw() end function page:run(operation, name) @@ -116,6 +116,7 @@ function page:run(operation, name) print(cmd .. '\n') term.setTextColor(colors.white) local s, m = Util.run(_ENV, '/sys/apps/package.lua', operation, name) + if not s and m then _G.printError(m) end diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 737a999..2648cd6 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -24,7 +24,7 @@ local page = UI.Page { wizard = UI.Wizard { ey = -2, pages = { - splash = UI.Window { + splash = UI.WizardPage { index = 1, intro = UI.TextArea { textColor = colors.yellow, @@ -33,7 +33,7 @@ local page = UI.Page { value = string.format(splashIntro, Ansi.white), }, }, - label = UI.Window { + label = UI.WizardPage { index = 2, labelText = UI.Text { x = 3, y = 2, @@ -51,7 +51,7 @@ local page = UI.Page { value = string.format(labelIntro, Ansi.white), }, }, - password = UI.Window { + password = UI.WizardPage { index = 3, labelText = UI.Text { x = 3, y = 2, @@ -73,7 +73,7 @@ local page = UI.Page { value = string.format(passwordIntro, Ansi.white), }, }, - packages = UI.Window { + packages = UI.WizardPage { index = 4, button = UI.Button { x = 3, y = -3, diff --git a/sys/apps/shell b/sys/apps/shell index 24805dd..3877073 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -361,16 +361,21 @@ local Config = require('config') local Entry = require('entry') local History = require('history') local Input = require('input') -local Terminal = require('terminal') local colors = _G.colors local os = _G.os local term = _G.term local textutils = _G.textutils +local oldTerm local terminal = term.current() ---Terminal.scrollable(terminal, 100) -terminal.noAutoScroll = true + +if not terminal.scrollUp then + local Terminal = require('terminal') + terminal = Terminal.window(term.current()) + terminal.setMaxScroll(200) + oldTerm = term.redirect(terminal) +end local config = { standard = { @@ -555,6 +560,9 @@ local function shellRead(history) term.setCursorBlink(true) local function redraw() + if terminal.scrollBottom then + terminal.scrollBottom() + end local _,cy = term.getCursorPos() term.setCursorPos(3, cy) local filler = #entry.value < lastLen @@ -571,11 +579,11 @@ local function shellRead(history) local ie = Input:translate(event, p1, p2, p3) if ie then - if ie.code == 'scroll_up' then - --terminal.scrollUp() + if ie.code == 'scroll_up' and terminal.scrollUp then + terminal.scrollUp() - elseif ie.code == 'scroll_down' then - --terminal.scrollDown() + elseif ie.code == 'scroll_down' and terminal.scrollDown then + terminal.scrollDown() elseif ie.code == 'terminate' then bExit = true @@ -652,3 +660,7 @@ while not bExit do end end end + +if oldTerm then + term.redirect(oldTerm) +end diff --git a/sys/autorun/log.lua b/sys/autorun/log.lua index 224d6e9..fe8de05 100644 --- a/sys/autorun/log.lua +++ b/sys/autorun/log.lua @@ -25,11 +25,13 @@ local function systemLog() if y > 1 then local currentTab = kernel.getFocused() - if currentTab.terminal.scrollUp and not currentTab.terminal.noAutoScroll then - if dir == -1 then - currentTab.terminal.scrollUp() - else - currentTab.terminal.scrollDown() + if currentTab == routine then + if currentTab.terminal.scrollUp and not currentTab.terminal.noAutoScroll then + if dir == -1 then + currentTab.terminal.scrollUp() + else + currentTab.terminal.scrollDown() + end end end end diff --git a/sys/kernel.lua b/sys/kernel.lua index cbd6806..407f217 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -14,13 +14,12 @@ local kernel = _G.kernel local os = _G.os local shell = _ENV.shell local term = _G.term -local window = _G.window local w, h = term.getSize() kernel.terminal = term.current() -kernel.window = window.create(kernel.terminal, 1, 1, w, h, false) -Terminal.scrollable(kernel.window) +kernel.window = Terminal.window(kernel.terminal, 1, 1, w, h, false) +kernel.window.setMaxScroll(100) local focusedRoutineEvents = Util.transpose { 'char', 'key', 'key_up', @@ -30,6 +29,7 @@ local focusedRoutineEvents = Util.transpose { _G._debug = function(pattern, ...) local oldTerm = term.redirect(kernel.window) + kernel.window.scrollBottom() Util.print(pattern, ...) term.redirect(oldTerm) end From 53e0fa3795bb1c24bc43d61e265f58d60ae91545 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 7 Feb 2019 03:10:05 -0500 Subject: [PATCH 063/231] fix lua path, mwm, cleanup injector --- sys/apis/injector.lua | 26 +++----- sys/apis/terminal.lua | 12 ++++ sys/apis/trace.lua | 97 ++++++++++++++++++++++++++++++ sys/apis/ui/canvas.lua | 63 +------------------ sys/apps/cedit.lua | 4 ++ sys/apps/cshell.lua | 8 ++- sys/apps/package.lua | 20 ++----- sys/apps/shell | 2 +- sys/apps/system/path.lua | 99 +++++++++++++++++++++++------- sys/apps/system/requires.lua | 103 ++++++++++++++++++++++++++++++++ sys/boot/opus.boot | 9 +++ sys/extensions/4.user.lua | 13 ++-- sys/extensions/6.packages.lua | 19 +----- sys/extensions/7.multishell.lua | 12 +++- 14 files changed, 342 insertions(+), 145 deletions(-) create mode 100644 sys/apis/trace.lua create mode 100644 sys/apps/system/requires.lua diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 7877a4c..17e27d5 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -23,8 +23,6 @@ table.insert(luaPaths, 5, '/sys/apis/?.lua') table.insert(luaPaths, 6, '/sys/apis/?/init.lua') local DEFAULT_PATH = table.concat(luaPaths, ';') -local DEFAULT_BRANCH = _ENV.OPUS_BRANCH or _G.OPUS_BRANCH or 'develop-1.8' -local DEFAULT_UPATH = GIT_URL .. '/kepler155c/opus/' .. DEFAULT_BRANCH .. '/sys/apis' local fs = _G.fs local http = _G.http @@ -32,7 +30,7 @@ local os = _G.os local string = _G.string if not http._patched then - -- fix broken http get + -- fix broken http get (http.get is not coroutine safe) local syncLocks = { } local function sync(obj, fn) @@ -110,6 +108,12 @@ return function(env) end if fs.exists(sPath) and not fs.isDir(sPath) then return loadfile(sPath, env) + elseif sPath:match("^(https?:)") then + print('loading ' .. sPath) + local c = loadUrl(sPath) + if c then + return load(c, modname, nil, env) + end end end end @@ -138,24 +142,9 @@ return function(env) end end - local function urlSearcher(modname) - local fname = modname:gsub('%.', '/') .. '.lua' - - if fname:sub(1, 1) ~= '/' then - for entry in string.gmatch(env.package.upath, "[^;]+") do - local url = entry .. '/' .. fname - local c = loadUrl(url) - if c then - return load(c, modname, nil, env) - end - end - end - end - -- place package and require function into env env.package = { path = env.LUA_PATH or _G.LUA_PATH or DEFAULT_PATH, - upath = env.LUA_UPATH or _G.LUA_UPATH or DEFAULT_UPATH, config = '/\n:\n?\n!\n-', preload = { }, loaded = { @@ -172,7 +161,6 @@ return function(env) pathSearcher, pastebinSearcher, gitSearcher, - urlSearcher, } } diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index fc9f49f..5d2ccdd 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -28,6 +28,8 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) }) canvas.offy = 0 + win.canvas = canvas + local function update() if isVisible then canvas:render(parent) @@ -98,6 +100,16 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) end win.setTextColour = win.setTextColor + function win.getPaletteColor(n) + return parent.getPaletteColor(n) + end + win.getPaletteColour = win.getPaletteColor + + function win.setPaletteColor(n, r, g, b) + return parent.setPaletteColor(n, r, g, b) + end + win.setPaletteColour = win.setPaletteColor + function win.setBackgroundColor(c) bg = c end diff --git a/sys/apis/trace.lua b/sys/apis/trace.lua new file mode 100644 index 0000000..78cc535 --- /dev/null +++ b/sys/apis/trace.lua @@ -0,0 +1,97 @@ +-- stack trace by SquidDev (MIT License) +-- https://raw.githubusercontent.com/SquidDev-CC/mbs/master/lib/stack_trace.lua + +local type = type +local debug_traceback = type(debug) == "table" and type(debug.traceback) == "function" and debug.traceback + +local function traceback(x) + -- Attempt to detect error() and error("xyz", 0). + -- This probably means they're erroring the program intentionally and so we + -- shouldn't display anything. + if x == nil or (type(x) == "string" and not x:find(":%d+:")) then + return x + end + + if debug_traceback then + -- The parens are important, as they prevent a tail call occuring, meaning + -- the stack level is preserved. This ensures the code behaves identically + -- on LuaJ and PUC Lua. + return (debug_traceback(tostring(x), 2)) + else + local level = 3 + local out = { tostring(x), "stack traceback:" } + while true do + local _, msg = pcall(error, "", level) + if msg == "" then break end + + out[#out + 1] = " " .. msg + level = level + 1 + end + + return table.concat(out, "\n") + end +end + +local function trim_traceback(target, marker) + local ttarget, tmarker = {}, {} + for line in target:gmatch("([^\n]*)\n?") do ttarget[#ttarget + 1] = line end + for line in marker:gmatch("([^\n]*)\n?") do tmarker[#tmarker + 1] = line end + + -- 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 + + -- Trim elements from this file and xpcall invocations + while t_len >= 1 and ttarget[t_len]:find("^\tstack_trace%.lua:%d+:") or + ttarget[t_len] == "\t[C]: in function 'xpcall'" or ttarget[t_len] == " xpcall: " do + table.remove(ttarget, t_len) + t_len = t_len - 1 + end + + return ttarget +end + +--- Run a function with +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 + -- which is not ideal + local res = table.pack(xpcall(function() + return fn(table.unpack(args)) + end, traceback)) + + if not res[1] then + trace = traceback("trace.lua:1:") + end + local ok, err = res[1], res[2] + + if not ok and err ~= nil then + trace = trim_traceback(err, trace) + + -- Find the position where the stack traceback actually starts + local trace_starts + for i = #trace, 1, -1 do + if trace[i] == "stack traceback:" then trace_starts = i; break end + end + + -- If this traceback is more than 15 elements long, keep the first 9, last 5 + -- and put an ellipsis between the rest + local max = 12 + if trace_starts and #trace - trace_starts > max then + local keep_starts = trace_starts + 9 + for i = #trace - trace_starts - max, 0, -1 do table.remove(trace, keep_starts + i) end + table.insert(trace, keep_starts, " ...") + end + + return false, table.concat(trace, "\n") + end + + return table.unpack(res, 1, res.n) +end diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index 931e9bd..3fbc15d 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -246,17 +246,17 @@ function Canvas:blitClipped(device, offset) end function Canvas:redraw(device) ---[[ +-- self:dirty() +-- self:render(device) if #self.layers > 0 then for _,layer in pairs(self.layers) do self:punch(layer) end self:blitClipped(device) else - self:blit(device) + self:renderLayers(device) end self:clean() -]] end function Canvas:isDirty() @@ -384,61 +384,4 @@ function Canvas:applyPalette(palette) self.palette = palette end -function Canvas.convertWindow(win, parent, wx, wy) - local w, h = win.getSize() - - win.canvas = Canvas({ - x = wx, - y = wy, - width = w, - height = h, - isColor = win.isColor(), - }) - - function win.clear() - win.canvas:clear(win.getBackgroundColor(), win.getTextColor()) - end - - function win.clearLine() - local _, y = win.getCursorPos() - win.canvas:write(1, - y, - _rep(' ', win.canvas.width), - win.getBackgroundColor(), - win.getTextColor()) - end - - function win.write(str) - local x, y = win.getCursorPos() - win.canvas:write(x, - y, - str, - win.getBackgroundColor(), - win.getTextColor()) - win.setCursorPos(x + #str, y) - end - - function win.blit(text, fg, bg) - local x, y = win.getCursorPos() - win.canvas:blit(x, y, text, bg, fg) - end - - function win.redraw() - win.canvas:redraw(parent) - end - - function win.scroll(n) - table.insert(win.canvas.lines, table.remove(win.canvas.lines, 1)) - win.canvas.lines[#win.canvas.lines].text = _rep(' ', win.canvas.width) - win.canvas:dirty() - end - - function win.reposition(x, y, width, height) - win.canvas.x, win.canvas.y = x, y - win.canvas:resize(width or win.canvas.width, height or win.canvas.height) - end - - win.clear() -end - return Canvas diff --git a/sys/apps/cedit.lua b/sys/apps/cedit.lua index d1c1295..8032688 100644 --- a/sys/apps/cedit.lua +++ b/sys/apps/cedit.lua @@ -8,6 +8,10 @@ if not args[1] then error('Syntax: cedit ') end +if not _G.http.websocket then + error('Requires CC: Tweaked') +end + if not _G.cloud_catcher then print('Paste key: ') local key = read() diff --git a/sys/apps/cshell.lua b/sys/apps/cshell.lua index 9d54e84..7bc6af6 100644 --- a/sys/apps/cshell.lua +++ b/sys/apps/cshell.lua @@ -1,5 +1,9 @@ -local read = _G.read -local shell = _ENV.shell +local read = _G.read +local shell = _ENV.shell + +if not _G.http.websocket then + error('Requires CC: Tweaked') +end if not _G.cloud_catcher then print('Paste key: ') diff --git a/sys/apps/package.lua b/sys/apps/package.lua index b377134..45016cd 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -50,21 +50,13 @@ local function install(name, isUpdate) name)) local packageDir = fs.combine('packages', name) - local method = args[2] or 'local' - if method == 'remote' then - Util.writeTable(packageDir .. '/.install', { - mount = string.format('%s gitfs %s', packageDir, manifest.repository), - }) - Util.writeTable(fs.combine(packageDir, '.package'), manifest) - else - local list = Git.list(manifest.repository) - local showProgress = progress(Util.size(list)) - for path, entry in pairs(list) do - Util.download(entry.url, fs.combine(packageDir, path)) - showProgress() - end + + local list = Git.list(manifest.repository) + local showProgress = progress(Util.size(list)) + for path, entry in pairs(list) do + Util.download(entry.url, fs.combine(packageDir, path)) + showProgress() end - return end if action == 'list' then diff --git a/sys/apps/shell b/sys/apps/shell index 3877073..d9da2e2 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -65,7 +65,7 @@ local function run(env, ...) end if isUrl then - tProgramStack[#tProgramStack + 1] = path:match("^https?://([^/:]+:?[0-9]*/?.*)$") + tProgramStack[#tProgramStack + 1] = path -- path:match("^https?://([^/:]+:?[0-9]*/?.*)$") else tProgramStack[#tProgramStack + 1] = path end diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index f2a7c98..7e3abff 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -2,47 +2,102 @@ local Config = require('config') local UI = require('ui') local Util = require('util') -local pathTab = UI.Tab { +local tab = UI.Tab { tabTitle = 'Path', description = 'Set the shell path', tabClose = true, entry = UI.TextEntry { x = 2, y = 2, ex = -2, limit = 256, - value = Config.load('shell').path, - shadowText = 'enter system path', + shadowText = 'enter new path', accelerators = { enter = 'update_path', }, + help = 'add a new path', }, grid = UI.Grid { - y = 4, + y = 4, ey = -3, disableHeader = true, columns = { { key = 'value' } }, autospace = true, + sort = 'index', + help = 'double-click to remove, shift-arrow to move', + accelerators = { + delete = 'remove', + }, }, + statusBar = UI.StatusBar { }, + accelerators = { + [ 'shift-up' ] = 'move_up', + [ 'shift-down' ] = 'move_down', + }, } -function pathTab.grid:draw() - self.values = { } - local env = Config.load('shell') - for _,v in ipairs(Util.split(env.path, '(.-):')) do - table.insert(self.values, { value = v }) - end - self:update() - UI.Grid.draw(self) +function tab:updateList(path) + self.grid.values = { } + for k,v in ipairs(Util.split(path, '(.-):')) do + table.insert(self.grid.values, { index = k, value = v }) + end + self.grid:update() end -function pathTab:eventHandler(event) - if event.type == 'update_path' then - local env = Config.load('shell') - env.path = self.entry.value - Config.update('shell', env) - self.grid:setIndex(self.grid:getIndex()) - self.grid:draw() - self:emit({ type = 'success_message', message = 'reboot to take effect' }) +function tab:enable() + local env = Config.load('shell') + self:updateList(env.path) + UI.Tab.enable(self) +end + +function tab:save() + local t = { } + for _, v in ipairs(self.grid.values) do + table.insert(t, v.value) + end + local env = Config.load('shell') + env.path = table.concat(t, ':') + self:updateList(env.path) + Config.update('shell', env) +end + +function tab:eventHandler(event) + if event.type == 'update_path' then + table.insert(self.grid.values, { + value = self.entry.value, + }) + self:save() + self.entry:reset() + self.entry:draw() + self.grid:draw() return true - end + + elseif event.type == 'grid_select' or event.type == 'remove' then + local selected = self.grid:getSelected() + if selected then + table.remove(self.grid.values, selected.index) + self:save() + self.grid:draw() + end + + elseif event.type == 'focus_change' then + self.statusBar:setStatus(event.focused.help) + + elseif event.type == 'move_up' then + local entry = self.grid:getSelected() + if entry.index > 1 then + table.insert(self.grid.values, entry.index - 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index - 1) + self:save() + self.grid:draw() + end + + elseif event.type == 'move_down' then + local entry = self.grid:getSelected() + if entry.index < #self.grid.values then + table.insert(self.grid.values, entry.index + 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index + 1) + self:save() + self.grid:draw() + end + end end -return pathTab +return tab diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua new file mode 100644 index 0000000..46eaed8 --- /dev/null +++ b/sys/apps/system/requires.lua @@ -0,0 +1,103 @@ +local Config = require('config') +local UI = require('ui') +local Util = require('util') + +local tab = UI.Tab { + tabTitle = 'Requires', + description = 'Require path', + tabClose = true, + entry = UI.TextEntry { + x = 2, y = 2, ex = -2, + limit = 256, + shadowText = 'Enter new require path', + accelerators = { + enter = 'update_path', + }, + help = 'add a new path', + }, + grid = UI.Grid { + y = 4, ey = -3, + disableHeader = true, + columns = { { key = 'value' } }, + autospace = true, + sort = 'index', + help = 'double-click to remove, shift-arrow to move', + accelerators = { + delete = 'remove', + }, + }, + statusBar = UI.StatusBar { }, + accelerators = { + [ 'shift-up' ] = 'move_up', + [ 'shift-down' ] = 'move_down', + }, +} + +function tab:updateList(lua_path) + self.grid.values = { } + for k,v in ipairs(Util.split(lua_path, '(.-);')) do + table.insert(self.grid.values, { index = k, value = v }) + end + self.grid:update() +end + +function tab:enable() + local env = Config.load('shell') + self:updateList(env.lua_path) + UI.Tab.enable(self) +end + +function tab:save() + local t = { } + for _, v in ipairs(self.grid.values) do + table.insert(t, v.value) + end + local env = Config.load('shell') + env.lua_path = table.concat(t, ';') + self:updateList(env.lua_path) + Config.update('shell', env) +end + +function tab:eventHandler(event) + if event.type == 'update_path' then + table.insert(self.grid.values, { + value = self.entry.value, + }) + self:save() + self.entry:reset() + self.entry:draw() + self.grid:draw() + return true + + elseif event.type == 'grid_select' or event.type == 'remove' then + local selected = self.grid:getSelected() + if selected then + table.remove(self.grid.values, selected.index) + self:save() + self.grid:draw() + end + + elseif event.type == 'focus_change' then + self.statusBar:setStatus(event.focused.help) + + elseif event.type == 'move_up' then + local entry = self.grid:getSelected() + if entry.index > 1 then + table.insert(self.grid.values, entry.index - 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index - 1) + self:save() + self.grid:draw() + end + + elseif event.type == 'move_down' then + local entry = self.grid:getSelected() + if entry.index < #self.grid.values then + table.insert(self.grid.values, entry.index + 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index + 1) + self:save() + self.grid:draw() + end + end +end + +return tab diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index 8c5c413..2f64980 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -48,7 +48,16 @@ if fs.exists('sys/apis/injector.lua') then _G.requireInjector = run('sys/apis/injector.lua') else -- not local, run the file system directly from git + if package and package.path then + package.path = package.path .. ';' .. BASE .. '/sys/apis' + else + sandboxEnv.package = { + path = BASE .. '/sys/apis' + } + end + _G.requireInjector = runUrl('sys/apis/injector.lua') + runUrl('sys/extensions/2.vfs.lua') -- install file system diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 722ec9a..49f8583 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -10,11 +10,9 @@ if not fs.exists('usr/autorun') then fs.makeDir('usr/autorun') end -local lua_path = package.path - -- TODO: Temporary local upgrade = Util.readTable('usr/config/shell') -if upgrade and not upgrade.upgraded then +if upgrade and not upgrade.upgraded or upgrade.upgraded ~= 1 then fs.delete('usr/config/shell') end @@ -22,8 +20,8 @@ if not fs.exists('usr/config/shell') then Util.writeTable('usr/config/shell', { aliases = shell.aliases(), path = 'usr/apps', - lua_path = lua_path, - upgraded = true, + lua_path = package.path, + upgraded = 1, }) end @@ -44,8 +42,7 @@ for _, v in pairs(Util.split(shell.path(), '(.-):')) do end shell.setPath(table.concat(path, ':')) --- TODO: replace when stable (old lua path is now incorrect) --- _G.LUA_PATH = config.lua_path -_G.LUA_PATH = package.path + +_G.LUA_PATH = config.lua_path fs.loadTab('usr/config/fstab') diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index 9510e35..b8f6340 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -10,30 +10,14 @@ if not fs.exists('usr/config/packages') then end local appPaths = Util.split(shell.path(), '(.-):') -local luaPaths = Util.split(_G.LUA_PATH, '(.-);') local helpPaths = Util.split(help.path(), '(.-):') table.insert(helpPaths, '/sys/help') -local function addEntry(t, e, n) - for _,v in ipairs(t) do - if v == e then - return true - end - end - table.insert(t, n or 1, e) -end - for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) - if fs.exists(fs.combine(packageDir, '.install')) then - local install = Util.readTable(fs.combine(packageDir, '.install')) - if install and install.mount then - fs.mount(table.unpack(Util.matches(install.mount))) - end - end - addEntry(appPaths, packageDir) + table.insert(appPaths, 1, packageDir) local apiPath = fs.combine(fs.combine('packages', name), 'apis') if fs.exists(apiPath) then fs.mount(fs.combine('sys/apis', name), 'linkfs', apiPath) @@ -47,4 +31,3 @@ end help.setPath(table.concat(helpPaths, ':')) shell.setPath(table.concat(appPaths, ':')) -_G.LUA_PATH = table.concat(luaPaths, ';') diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index 4da07e8..40129fc 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -2,6 +2,7 @@ _G.requireInjector(_ENV) local Config = require('config') local Packages = require('packages') +local trace = require('trace') local Util = require('util') local colors = _G.colors @@ -104,6 +105,15 @@ function multishell.launch( tProgramEnv, sProgramPath, ... ) }) end +local function xprun(env, path, ...) + setmetatable(env, { __index = _G }) + local fn, m = loadfile(path, env) + if fn then + return trace(fn, ...) + end + return fn, m +end + function multishell.openTab(tab) if not tab.title and tab.path then tab.title = fs.getName(tab.path):match('([^%.]+)') @@ -120,7 +130,7 @@ function multishell.openTab(tab) if tab.fn then result, err = Util.runFunction(routine.env, tab.fn, table.unpack(tab.args or { } )) elseif tab.path then - result, err = Util.run(routine.env, tab.path, table.unpack(tab.args or { } )) + result, err = xprun(routine.env, tab.path, table.unpack(tab.args or { } )) else err = 'multishell: invalid tab' end From 8333b3bbec1eb62c366800f42a85e1cf6733051d Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 7 Feb 2019 03:15:40 -0500 Subject: [PATCH 064/231] oops --- sys/extensions/4.user.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 49f8583..96953bf 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -12,7 +12,7 @@ end -- TODO: Temporary local upgrade = Util.readTable('usr/config/shell') -if upgrade and not upgrade.upgraded or upgrade.upgraded ~= 1 then +if upgrade and (not upgrade.upgraded or upgrade.upgraded ~= 1) then fs.delete('usr/config/shell') end From 72b3c7bac962bb6573585d10a3e1c65b0ebbcd75 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 7 Feb 2019 10:09:40 -0500 Subject: [PATCH 065/231] canvas improvements --- sys/apis/ui/canvas.lua | 252 +++++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 124 deletions(-) diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index 3fbc15d..01328dc 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -220,45 +220,6 @@ function Canvas:clear(bg, fg) end end -function Canvas:punch(rect) - local offset = { x = 0, y = 0 } - - - self.regions:subRect(rect.x + offset.x, rect.y + offset.y, rect.ex + offset.x, rect.ey + offset.y) -end - -function Canvas:blitClipped(device, offset) - offset = { x = self.x, y = self.y } - local parent = self.parent - while parent do - offset.x = offset.x + parent.x - 1 - offset.y = offset.y + parent.y - 1 - parent = parent.parent - end - for _,region in ipairs(self.regions.region) do - self:blitRect(device, - { x = region[1], - y = region[2], - ex = region[3], - ey = region[4] }, - { x = region[1] + offset.x - 1, y = region[2] + offset.y - 1 }) - end -end - -function Canvas:redraw(device) --- self:dirty() --- self:render(device) - if #self.layers > 0 then - for _,layer in pairs(self.layers) do - self:punch(layer) - end - self:blitClipped(device) - else - self:renderLayers(device) - end - self:clean() -end - function Canvas:isDirty() for i = 1, #self.lines do if self.lines[i].dirty then @@ -284,92 +245,7 @@ function Canvas:clean() end end -function Canvas:renderLayers(device, offset) - if not offset then - offset = { x = self.x, y = self.y } - end - if #self.layers > 0 then - self.regions = Region.new(1, 1, self.ex, self.ey) - - for i = 1, #self.layers do - local canvas = self.layers[i] - if canvas.visible then - - -- punch out this area from the parent's canvas - self:punch(canvas) - - -- get the area to render for this layer - canvas.regions = Region.new(canvas.x, canvas.y, canvas.ex, canvas.ey) - - -- determine if we should render this layer by punching - -- out any layers that overlap this one - for j = i + 1, #self.layers do - if self.layers[j].visible then - canvas:punch(self.layers[j]) - end - end - end - end - - for _, canvas in ipairs(self.layers) do - if canvas.visible and #canvas.regions.region > 0 then - canvas:renderLayers(device, { - x = canvas.x, --offset.x + self.x - 1, - y = canvas.y, - }) - end - end - - self:blitClipped(device, offset) - - --elseif #self.regions.region > 0 then - -- self:blitClipped(device, offset) - - else - offset = { x = self.x, y = self.y } - local parent = self.parent - while parent do - offset.x = offset.x + parent.x - 1 - offset.y = offset.y + parent.y - 1 - parent = parent.parent - end - self:blitRect(device, nil, offset) - end - self:clean() -end - -function Canvas:render(device) - --_G._p = self - if #self.layers > 0 then - self:renderLayers(device) - else - self:blitRect(device) - self:clean() - end -end - -function Canvas:blitRect(device, src, tgt) - src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 } - tgt = tgt or self - - for i = 0, src.ey - src.y do - local line = self.lines[src.y + i + (self.offy or 0)] - if line and line.dirty then - local t, fg, bg = line.text, line.fg, line.bg - if src.x > 1 or src.ex < self.ex then - t = _sub(t, src.x, src.ex) - fg = _sub(fg, src.x, src.ex) - bg = _sub(bg, src.x, src.ex) - end - device.setCursorPos(tgt.x, tgt.y + i) - device.blit(t, fg, bg) - end - end - --os.sleep(.1) -end - function Canvas:applyPalette(palette) - local lookup = { } for n = 1, 16 do lookup[self.palette[2 ^ (n - 1)]] = palette[2 ^ (n - 1)] @@ -384,4 +260,132 @@ function Canvas:applyPalette(palette) self.palette = palette end +function Canvas:render(device) + if #self.layers > 0 then + self:__renderLayers(device, { x = 0, y = 0 }) + else + self:__blitRect(device) + self:clean() + end +end + +-- regions are comprised of absolute values that coorespond to the output device. +-- canvases have coordinates relative to their parent. +-- canvas layer's stacking order is determined by the position within the array. +-- layers in the beginning of the array are overlayed by layers further down in +-- the array. +function Canvas:__renderLayers(device, offset) + if #self.layers > 0 then + self.regions = self.regions or Region.new(self.x, self.y, self.ex, self.ey) + + for i = 1, #self.layers do + local canvas = self.layers[i] + if canvas.visible then + + -- punch out this area from the parent's canvas + self:__punch(canvas, offset) + + -- get the area to render for this layer + canvas.regions = Region.new( + canvas.x + offset.x, + canvas.y + offset.y, + canvas.ex + offset.x, + canvas.ey + offset.y) + + -- punch out any layers that overlap this one + for j = i + 1, #self.layers do + if self.layers[j].visible then + canvas:__punch(self.layers[j], offset) + end + end + if #canvas.regions.region > 0 then + canvas:__renderLayers(device, { + x = canvas.x + offset.x - 1, + y = canvas.y + offset.y - 1, + }) + end + canvas.regions = nil + end + end + + self:__blitClipped(device, offset) + self.regions = nil + + elseif self.regions and #self.regions.region > 0 then + self:__blitClipped(device, offset) + self.regions = nil + + else + offset = { x = self.x, y = self.y } + local parent = self.parent + while parent do + offset.x = offset.x + parent.x - 1 + offset.y = offset.y + parent.y - 1 + parent = parent.parent + end + self:__blitRect(device, nil, offset) + self.regions = nil + end + self:clean() +end + +function Canvas:__blitClipped(device, offset) + for _,region in ipairs(self.regions.region) do + self:__blitRect(device, + { x = region[1] - offset.x, + y = region[2] - offset.y, + ex = region[3] - offset.x, + ey = region[4] - offset.y}, + { x = region[1], y = region[2] }) + end +end + +function Canvas:__punch(rect, offset) + self.regions:subRect( + rect.x + offset.x, + rect.y + offset.y, + rect.ex + offset.x, + rect.ey + offset.y) +end + +function Canvas:__blitRect(device, src, tgt) + src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 } + tgt = tgt or self + + --[[ + -- for visualizing updates on the screen + local drew + for i = 0, src.ey - src.y do + local line = self.lines[src.y + i + (self.offy or 0)] + if line and line.dirty then + drew = true + local t, fg, bg = line.text, line.fg, line.bg + if src.x > 1 or src.ex < self.ex then + t = _sub(t, src.x, src.ex) + fg = _rep(1, src.ex-src.x + 1) + bg = _rep(2, src.ex-src.x + 1) + end + device.setCursorPos(tgt.x, tgt.y + i) + device.blit(t, fg, bg) + end + end + if drew then + os.sleep(.3) + end + ]] + for i = 0, src.ey - src.y do + local line = self.lines[src.y + i + (self.offy or 0)] + if line and line.dirty then + local t, fg, bg = line.text, line.fg, line.bg + if src.x > 1 or src.ex < self.ex then + t = _sub(t, src.x, src.ex) + fg = _sub(fg, src.x, src.ex) + bg = _sub(bg, src.x, src.ex) + end + device.setCursorPos(tgt.x, tgt.y + i) + device.blit(t, fg, bg) + end + end +end + return Canvas From 8c1abb21ca569a36536b3b254c075284c7589dee Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 8 Feb 2019 19:21:20 -0500 Subject: [PATCH 066/231] resizing + injector fixes --- sys/apis/injector.lua | 18 +++++++++++------- sys/apis/terminal.lua | 9 +++++++-- sys/apis/ui.lua | 4 +--- sys/apis/ui/canvas.lua | 27 +++++++++++++++++---------- sys/apis/ui/components/SlideOut.lua | 13 +++++++------ sys/apis/ui/components/Viewport.lua | 10 +++++++--- sys/apps/Lua.lua | 6 +++++- sys/apps/Overview.lua | 3 ++- sys/apps/PackageManager.lua | 1 + sys/extensions/4.user.lua | 1 + 10 files changed, 59 insertions(+), 33 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 17e27d5..7f6fc37 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -103,17 +103,21 @@ return function(env) local sPath = string.gsub(pattern, "%?", fname) -- TODO: if there's no shell, we should not be checking relative paths below -- as they will resolve to root directory - if env.shell and type(env.shell.getRunningProgram) == 'function' and sPath:sub(1, 1) ~= "/" then - sPath = fs.combine(fs.getDir(env.shell.getRunningProgram() or ''), sPath) - end - if fs.exists(sPath) and not fs.isDir(sPath) then - return loadfile(sPath, env) - elseif sPath:match("^(https?:)") then - print('loading ' .. sPath) + if sPath:match("^(https?:)") then local c = loadUrl(sPath) if c then return load(c, modname, nil, env) end + else + if env.shell and + type(env.shell.getRunningProgram) == 'function' and + sPath:sub(1, 1) ~= "/" then + + sPath = fs.combine(fs.getDir(env.shell.getRunningProgram() or ''), sPath) + end + if fs.exists(sPath) and not fs.isDir(sPath) then + return loadfile(sPath, env) + end end end end diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 5d2ccdd..5755d52 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -101,12 +101,17 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) win.setTextColour = win.setTextColor function win.getPaletteColor(n) - return parent.getPaletteColor(n) + if parent.getPaletteColor then + return parent.getPaletteColor(n) + end + return 0, 0, 0 end win.getPaletteColour = win.getPaletteColor function win.setPaletteColor(n, r, g, b) - return parent.setPaletteColor(n, r, g, b) + if parent.setPaletteColor then + return parent.setPaletteColor(n, r, g, b) + end end win.setPaletteColour = win.setPaletteColor diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 36e4bc1..f9e8602 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -504,9 +504,7 @@ function UI.Window:layout() end end --- bad name... should be called something like postInit --- normally used to determine sizes since the parent is --- only known at this point +-- Called when the window's parent has be assigned function UI.Window:setParent() self.oh, self.ow = self.height, self.width self.ox, self.oy = self.x, self.y diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index 01328dc..c0f62e6 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -66,6 +66,7 @@ function Canvas:resize(w, h) for i = 1, self.height do self.lines[i] = { dirty = true } end + self:clear() end self.ex = self.x + w - 1 @@ -261,10 +262,20 @@ function Canvas:applyPalette(palette) end function Canvas:render(device) + local offset = { x = 0, y = 0 } + local parent = self.parent + while parent do + offset.x = offset.x + parent.x - 1 + offset.y = offset.y + parent.y - 1 + parent = parent.parent + end if #self.layers > 0 then - self:__renderLayers(device, { x = 0, y = 0 }) + self:__renderLayers(device, offset) else - self:__blitRect(device) + self:__blitRect(device, nil, { + x = self.x + offset.x, + y = self.y + offset.y + }) self:clean() end end @@ -316,14 +327,10 @@ function Canvas:__renderLayers(device, offset) self.regions = nil else - offset = { x = self.x, y = self.y } - local parent = self.parent - while parent do - offset.x = offset.x + parent.x - 1 - offset.y = offset.y + parent.y - 1 - parent = parent.parent - end - self:__blitRect(device, nil, offset) + self:__blitRect(device, nil, { + x = self.x + offset.x, + y = self.y + offset.y + }) self.regions = nil end self:clean() diff --git a/sys/apis/ui/components/SlideOut.lua b/sys/apis/ui/components/SlideOut.lua index 5994c69..9e85251 100644 --- a/sys/apis/ui/components/SlideOut.lua +++ b/sys/apis/ui/components/SlideOut.lua @@ -7,12 +7,13 @@ UI.SlideOut.defaults = { UIElement = 'SlideOut', pageType = 'modal', } -function UI.SlideOut:setParent() - -- TODO: size should be set at this point - self:layout() - self.canvas = self:addLayer() - - UI.Window.setParent(self) +function UI.SlideOut:layout() + UI.Window.layout(self) + if not self.canvas then + self.canvas = self:addLayer() + else + self.canvas:resize(self.width, self.height) + end end function UI.SlideOut:enable() diff --git a/sys/apis/ui/components/Viewport.lua b/sys/apis/ui/components/Viewport.lua index e8289bd..b0e2a30 100644 --- a/sys/apis/ui/components/Viewport.lua +++ b/sys/apis/ui/components/Viewport.lua @@ -19,9 +19,13 @@ UI.Viewport.defaults = { [ 'control-f' ] = 'scroll_pageDown', }, } -function UI.Viewport:setParent() - UI.Window.setParent(self) - self.canvas = self:addLayer() +function UI.Viewport:layout() + UI.Window.layout(self) + if not self.canvas then + self.canvas = self:addLayer() + else + self.canvas:resize(self.width, self.height) + end end function UI.Viewport:enable() diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index 78e3a13..4414475 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -1,4 +1,8 @@ -_G.requireInjector(_ENV) +if not _G.requireInjector then + local BASE ='https://raw.githubusercontent.com/kepler155c/opus/develop-1.8/sys/apis' + _ENV.LUA_PATH=BASE .. '/?.lua' + load(_G.http.get(BASE .. '/injector.lua').readAll())()(_ENV) +end local History = require('history') local UI = require('ui') diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 797a1a7..7deedda 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -100,10 +100,11 @@ local page = UI.Page { newApp = UI.Button { text = '+', event = 'new', }, + --[[ volume = UI.Button { x = 3, text = '\15', event = 'volume', - } + },]] }, editor = UI.SlideOut { y = -12, height = 12, diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index ea4bab9..73cd78b 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -57,6 +57,7 @@ local page = UI.Page { }, output = UI.Embedded { y = 5, ey = -2, x = 2, ex = -2, + visible = true, }, }, statusBar = UI.StatusBar { }, diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 96953bf..169155d 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -44,5 +44,6 @@ end shell.setPath(table.concat(path, ':')) _G.LUA_PATH = config.lua_path +_G.settings.set('require.path', config.lua_path) fs.loadTab('usr/config/fstab') From 195dbd365aa8113511200c7359adacaa5339dce7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 8 Feb 2019 21:02:41 -0500 Subject: [PATCH 067/231] check for recursive requires + Lua update --- sys/apis/injector.lua | 9 ++++- sys/apps/Lua.lua | 70 +++++++++++++++++++----------------- sys/apps/system/requires.lua | 2 +- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 7f6fc37..2eb14dc 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -89,14 +89,21 @@ return function(env) end local function loadedSearcher(modname) - if env.package.loaded[modname] then + if env.package.loaded[modname] then return function() return env.package.loaded[modname] end end end + local sentinel = { } + local function pathSearcher(modname) + if env.package.loaded[modname] == sentinel then + error("loop or previous error loading module '" .. modname .. "'", 0) + end + env.package.loaded[modname] = sentinel + local fname = modname:gsub('%.', '/') for pattern in string.gmatch(env.package.path, "[^;]+") do diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index 4414475..dd50147 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -45,28 +45,33 @@ local page = UI.Page { [ 'control-space' ] = 'autocomplete', }, }, - grid = UI.ScrollingGrid { - y = 3, ey = -2, - columns = { - { heading = 'Key', key = 'name' }, - { heading = 'Value', key = 'value' }, + tabs = UI.Tabs { + y = 3, + [1] = UI.Tab { + tabTitle = 'Formatted', + grid = UI.ScrollingGrid { + columns = { + { heading = 'Key', key = 'name' }, + { heading = 'Value', key = 'value' }, + }, + sortColumn = 'name', + autospace = true, + }, + }, + [2] = UI.Tab { + tabTitle = 'Output', + output = UI.Embedded { + visible = true, + maxScroll = 1000, + backgroundColor = colors.black, + }, }, - sortColumn = 'name', - autospace = true, - }, - titleBar = UI.TitleBar { - title = 'Output', - y = -1, - event = 'show_output', - closeInd = '^' - }, - output = UI.Embedded { - y = -6, - visible = true, - backgroundColor = colors.gray, }, } +page.grid = page.tabs[1].grid +page.output = page.tabs[2].output + function page:setPrompt(value, focus) self.prompt:setValue(value) self.prompt.scroll = 0 @@ -84,9 +89,8 @@ function page:setPrompt(value, focus) end function page:enable() - self:setFocus(self.prompt) UI.Page.enable(self) - self.output:disable() + self:setFocus(self.prompt) end local function autocomplete(env, oLine, x) @@ -145,18 +149,11 @@ function page:eventHandler(event) self:draw() + elseif event.type == 'tab_select' then + self:setFocus(self.prompt) + elseif event.type == 'show_output' then - self.output:enable() - - self.titleBar.oy = -7 - self.titleBar.event = 'hide_output' - self.titleBar.closeInd = 'v' - self.titleBar:resize() - - self.grid.ey = -8 - self.grid:resize() - - self:draw() + self.tabs:selectTab(self.tabs[2]) elseif event.type == 'autocomplete' then local sz = #self.prompt.value @@ -186,8 +183,6 @@ function page:eventHandler(event) local s = tostring(self.prompt.value) if #s > 0 then - history:add(s) - history:back() self:executeStatement(s) else local t = { } @@ -331,9 +326,18 @@ end function page:executeStatement(statement) command = statement + history:add(statement) + history:back() + local s, m local oterm = term.redirect(self.output.win) self.output.win.scrollBottom() + local bg, fg = term.getBackgroundColor(), term.getTextColor() + term.setBackgroundColor(colors.black) + term.setTextColor(colors.yellow) + print('> ' .. tostring(statement)) + term.setBackgroundColor(bg) + term.setTextColor(fg) pcall(function() s, m = self:rawExecute(command) end) diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua index 46eaed8..dfa7a02 100644 --- a/sys/apps/system/requires.lua +++ b/sys/apps/system/requires.lua @@ -13,7 +13,7 @@ local tab = UI.Tab { accelerators = { enter = 'update_path', }, - help = 'add a new path', + help = 'add a new path (reboot required)', }, grid = UI.Grid { y = 4, ey = -3, From fd672ac74e9e70dec122f1b0bb806cbd444d17c7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 9 Feb 2019 21:41:51 -0500 Subject: [PATCH 068/231] checkbox width bug, scroll canvas --- sys/apis/ui.lua | 15 +++++++++++---- sys/apis/ui/components/Checkbox.lua | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index f9e8602..712b600 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -824,12 +824,19 @@ function UI.Window:scrollIntoView() parent:draw() end + -- TODO: fix + local function setOffset(y) + parent.offy = y + if parent.canvas then + parent.canvas.offy = parent.offy + end + parent:draw() + end + if self.y <= parent.offy then - parent.offy = math.max(0, self.y - 1) - parent:draw() + setOffset(math.max(0, self.y - 1)) elseif self.y + self.height > parent.height + parent.offy then - parent.offy = self.y + self.height - parent.height - 1 - parent:draw() + setOffset(self.y + self.height - parent.height - 1) end end diff --git a/sys/apis/ui/components/Checkbox.lua b/sys/apis/ui/components/Checkbox.lua index ac3ec4c..9f2c174 100644 --- a/sys/apis/ui/components/Checkbox.lua +++ b/sys/apis/ui/components/Checkbox.lua @@ -24,7 +24,7 @@ function UI.Checkbox:setParent() if not self.width and not self.ex then self.width = (self.label and #self.label or 0) + 3 else - self.widthh = 3 + self.width = 3 end UI.Window.setParent(self) end From 2eab8b99de90acdb9c4b95c2be28de2b89c4f452 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 10 Feb 2019 13:08:54 -0500 Subject: [PATCH 069/231] canvas fix --- sys/apis/ui/canvas.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index c0f62e6..55f2977 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -56,6 +56,7 @@ end function Canvas:resize(w, h) for i = #self.lines, h do self.lines[i] = { } + self:clearLine(i) end while #self.lines > h do @@ -63,9 +64,6 @@ function Canvas:resize(w, h) end if w ~= self.width then - for i = 1, self.height do - self.lines[i] = { dirty = true } - end self:clear() end From d769b3567284f78eac88dc339f5ec154662e4808 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 10 Feb 2019 23:40:23 -0500 Subject: [PATCH 070/231] pull out shell scrolling til fixed --- sys/apps/shell | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/apps/shell b/sys/apps/shell index d9da2e2..e1010fb 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -371,10 +371,10 @@ local oldTerm local terminal = term.current() if not terminal.scrollUp then - local Terminal = require('terminal') - terminal = Terminal.window(term.current()) - terminal.setMaxScroll(200) - oldTerm = term.redirect(terminal) +-- local Terminal = require('terminal') +-- terminal = Terminal.window(term.current()) +-- terminal.setMaxScroll(200) +-- oldTerm = term.redirect(terminal) end local config = { From 2d411df7d1e7705c3d964ee2938ba01271e145e1 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 11 Feb 2019 20:25:12 -0500 Subject: [PATCH 071/231] scrolling term --- sys/apis/terminal.lua | 14 +++++++------- sys/apps/shell | 8 ++++---- sys/autorun/complete.lua | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 sys/autorun/complete.lua diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 5755d52..bfac681 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -63,15 +63,15 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) function win.clear() canvas.offy = 0 - canvas:clear(bg, fg) for i = #canvas.lines, canvas.height + 1, -1 do canvas.lines[i] = nil end + canvas:clear(bg, fg) update() end function win.clearLine() - canvas:clearLine(cy, bg, fg) + canvas:clearLine(cy + canvas.offy, bg, fg) win.setCursorPos(cx, cy) update() end @@ -127,15 +127,15 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) function win.scroll(n) n = n or 1 if n > 0 then - for _ = 1, n do - canvas.lines[#canvas.lines + 1] = { } - canvas:clearLine(#canvas.lines, bg, fg) + local lines = #canvas.lines + for i = 1, n do + canvas.lines[lines + i] = { } + canvas:clearLine(lines + i, bg, fg) end while #canvas.lines > maxScroll do table.remove(canvas.lines, 1) end - scrollTo(#canvas.lines - canvas.height) - canvas.offy = #canvas.lines - canvas.height + scrollTo(#canvas.lines) canvas:dirty() update() end diff --git a/sys/apps/shell b/sys/apps/shell index e1010fb..d9da2e2 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -371,10 +371,10 @@ local oldTerm local terminal = term.current() if not terminal.scrollUp then --- local Terminal = require('terminal') --- terminal = Terminal.window(term.current()) --- terminal.setMaxScroll(200) --- oldTerm = term.redirect(terminal) + local Terminal = require('terminal') + terminal = Terminal.window(term.current()) + terminal.setMaxScroll(200) + oldTerm = term.redirect(terminal) end local config = { diff --git a/sys/autorun/complete.lua b/sys/autorun/complete.lua new file mode 100644 index 0000000..332c8a3 --- /dev/null +++ b/sys/autorun/complete.lua @@ -0,0 +1,22 @@ +local function completeMultipleChoice(sText, tOptions, bAddSpaces) + local tResults = { } + for n = 1,#tOptions do + local sOption = tOptions[n] + if #sOption + (bAddSpaces and 1 or 0) > #sText and string.sub(sOption, 1, #sText) == sText then + local sResult = string.sub(sOption, #sText + 1) + if bAddSpaces then + table.insert(tResults, sResult .. " ") + else + table.insert(tResults, sResult) + end + end + end + return tResults +end + +_ENV.shell.setCompletionFunction("sys/apps/package.lua", + function(_, index, text) + if index == 1 then + return completeMultipleChoice(text, { "install ", "update ", "uninstall " }) + end + end) From ae6d8e8ebd918fa8c88dcab19710e053bb2458be Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 12 Feb 2019 17:03:50 -0500 Subject: [PATCH 072/231] rename shell -> shell.lua --- startup | 2 +- sys/apis/terminal.lua | 4 ++-- sys/apis/ui/canvas.lua | 10 ++++++---- sys/apis/ui/components/Checkbox.lua | 10 +--------- sys/apps/Files.lua | 2 +- sys/apps/Lua.lua | 7 ++----- sys/apps/Overview.lua | 2 +- sys/apps/PackageManager.lua | 5 +---- sys/apps/{shell => shell.lua} | 8 ++++---- sys/autorun/upgraded.lua | 3 +++ sys/boot/opus.boot | 2 +- sys/kernel.lua | 2 +- sys/network/telnet.lua | 2 +- 13 files changed, 25 insertions(+), 34 deletions(-) rename sys/apps/{shell => shell.lua} (98%) create mode 100644 sys/autorun/upgraded.lua diff --git a/startup b/startup index a6631fb..47678d3 100644 --- a/startup +++ b/startup @@ -6,7 +6,7 @@ local term = _G.term local bootOptions = { { prompt = os.version() }, { prompt = 'Opus' , args = { '/sys/boot/opus.boot' } }, - { prompt = 'Opus Shell' , args = { '/sys/boot/opus.boot', 'sys/apps/shell' } }, + { prompt = 'Opus Shell' , args = { '/sys/boot/opus.boot', 'sys/apps/shell.lua' } }, { prompt = 'Opus Kiosk' , args = { '/sys/boot/kiosk.boot' } }, } local bootOption = 2 diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index bfac681..904f36e 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -25,8 +25,8 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) width = w, height = h, isColor = parent.isColor(), + offy = 0, }) - canvas.offy = 0 win.canvas = canvas @@ -164,7 +164,7 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) function win.redraw() if isVisible then canvas:dirty() - canvas:render(parent) + update() end end diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index 55f2977..d980845 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -198,10 +198,12 @@ function Canvas:blit(x, y, text, bg, fg) end function Canvas:writeLine(y, text, fg, bg) - self.lines[y].dirty = true - self.lines[y].text = text - self.lines[y].fg = fg - self.lines[y].bg = bg + if y > 0 and y <= #self.lines then + self.lines[y].dirty = true + self.lines[y].text = text + self.lines[y].fg = fg + self.lines[y].bg = bg + end end function Canvas:clearLine(y, bg, fg) diff --git a/sys/apis/ui/components/Checkbox.lua b/sys/apis/ui/components/Checkbox.lua index 9f2c174..a780c42 100644 --- a/sys/apis/ui/components/Checkbox.lua +++ b/sys/apis/ui/components/Checkbox.lua @@ -15,20 +15,12 @@ UI.Checkbox.defaults = { backgroundColor = colors.black, backgroundFocusColor = colors.lightGray, height = 1, + width = 3, accelerators = { space = 'checkbox_toggle', mouse_click = 'checkbox_toggle', } } -function UI.Checkbox:setParent() - if not self.width and not self.ex then - self.width = (self.label and #self.label or 0) + 3 - else - self.width = 3 - end - UI.Window.setParent(self) -end - function UI.Checkbox:draw() local bg = self.backgroundColor if self.focused then diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 1053e79..2e065ba 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -347,7 +347,7 @@ function Browser:eventHandler(event) self:run('cedit', file.name) elseif event.type == 'shell' then - self:run('sys/apps/shell') + self:run('sys/apps/shell.lua') elseif event.type == 'refresh' then self:updateDirectory(self.dir) diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index dd50147..a1a3385 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -1,8 +1,5 @@ -if not _G.requireInjector then - local BASE ='https://raw.githubusercontent.com/kepler155c/opus/develop-1.8/sys/apis' - _ENV.LUA_PATH=BASE .. '/?.lua' - load(_G.http.get(BASE .. '/injector.lua').readAll())()(_ENV) -end +-- Lua may be called from outside of shell - inject a require +_G.requireInjector(_ENV) local History = require('history') local UI = require('ui') diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 7deedda..952137d 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -424,7 +424,7 @@ function page:eventHandler(event) shell.switchTab(shell.openTab(event.button.app.run)) elseif event.type == 'shell' then - shell.switchTab(shell.openTab('sys/apps/shell')) + shell.switchTab(shell.openTab('sys/apps/shell.lua')) elseif event.type == 'lua' then shell.switchTab(shell.openTab('sys/apps/Lua.lua')) diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index 73cd78b..cdd1641 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -36,7 +36,6 @@ local page = UI.Page { description = UI.TextArea { x = 16, y = 3, ey = -5, marginRight = 0, marginLeft = 0, - --backgroundColor = colors.white, }, load = UI.Button { x = 22, y = -3, @@ -45,10 +44,8 @@ local page = UI.Page { help = 'Download the latest package list', }, action = UI.SlideOut { - backgroundColor = colors.brown, - y = 3, + backgroundColor = colors.cyan, titleBar = UI.TitleBar { - backgroundColor = colors.brown, event = 'hide-action', }, button = UI.Button { diff --git a/sys/apps/shell b/sys/apps/shell.lua similarity index 98% rename from sys/apps/shell rename to sys/apps/shell.lua index d9da2e2..68fc0b3 100644 --- a/sys/apps/shell +++ b/sys/apps/shell.lua @@ -314,9 +314,9 @@ function shell.newTab(tabInfo, ...) tabInfo.args = args tabInfo.title = fs.getName(path):match('([^%.]+)') - if path ~= 'sys/apps/shell' then + if path ~= 'sys/apps/shell.lua' then table.insert(tabInfo.args, 1, tabInfo.path) - tabInfo.path = 'sys/apps/shell' + tabInfo.path = 'sys/apps/shell.lua' end return _ENV.multishell.openTab(tabInfo) end @@ -329,10 +329,10 @@ function shell.openTab( ... ) local sCommand = tWords[1] if sCommand then local sPath = shell.resolveProgram(sCommand) - if sPath == "sys/apps/shell" then + if sPath == "sys/apps/shell.lua" then return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), sPath, table.unpack(tWords, 2)) else - return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), "sys/apps/shell", sCommand, table.unpack(tWords, 2)) + return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), "sys/apps/shell.lua", sCommand, table.unpack(tWords, 2)) end end end diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua new file mode 100644 index 0000000..4992f7d --- /dev/null +++ b/sys/autorun/upgraded.lua @@ -0,0 +1,3 @@ +if fs.exists('sys/apps/shell') and fs.exists('sys/apps/shell.lua') then + fs.delete('sys/apps/shell') +end diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index 2f64980..69b90d3 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -64,7 +64,7 @@ else fs.mount('', 'gitfs', GIT_REPO) end -local s, m = pcall(run, 'sys/apps/shell', 'sys/kernel.lua', ...) +local s, m = pcall(run, 'sys/apps/shell.lua', 'sys/kernel.lua', ...) if not s then print('\nError loading Opus OS\n') diff --git a/sys/kernel.lua b/sys/kernel.lua index 407f217..bad6b82 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -278,7 +278,7 @@ local function init(...) kernel.hook('kernel_ready', function() local s, m = kernel.run({ title = args[1], - path = 'sys/apps/shell', + path = 'sys/apps/shell.lua', args = args, haltOnExit = true, haltOnError = true, diff --git a/sys/network/telnet.lua b/sys/network/telnet.lua index c0d5f07..e840a6e 100644 --- a/sys/network/telnet.lua +++ b/sys/network/telnet.lua @@ -46,7 +46,7 @@ local function telnetHost(socket) title = 'Telnet client', hidden = true, co = coroutine.create(function() - Util.run(_ENV, 'sys/apps/shell', table.unpack(termInfo.program)) + Util.run(_ENV, 'sys/apps/shell.lua', table.unpack(termInfo.program)) if socket.queue then socket:write(socket.queue) end From a36051bf78832b04eecc6b6d9971eb5fd84423ce Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 13 Feb 2019 20:17:01 -0500 Subject: [PATCH 073/231] remove trace for now --- sys/extensions/7.multishell.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index 40129fc..1cd1bf0 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -109,7 +109,7 @@ local function xprun(env, path, ...) setmetatable(env, { __index = _G }) local fn, m = loadfile(path, env) if fn then - return trace(fn, ...) + return pcall(fn, ...) end return fn, m end From 440b829f62a4e6298d78017e3f03819dedc516d1 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 18 Feb 2019 02:56:28 -0500 Subject: [PATCH 074/231] begin moving turtle specific code from opus into turtle package --- sys/apis/{turtle => }/pathfind.lua | 0 sys/apis/trace.lua | 9 +++-- sys/apis/turtle/home.lua | 42 -------------------- sys/apps/system/turtle.lua | 62 ------------------------------ sys/autorun/gps.lua | 43 --------------------- sys/extensions/6.tl3.lua | 30 ++++++++++----- sys/extensions/7.multishell.lua | 9 +++-- 7 files changed, 33 insertions(+), 162 deletions(-) rename sys/apis/{turtle => }/pathfind.lua (100%) delete mode 100644 sys/apis/turtle/home.lua delete mode 100644 sys/apps/system/turtle.lua delete mode 100644 sys/autorun/gps.lua diff --git a/sys/apis/turtle/pathfind.lua b/sys/apis/pathfind.lua similarity index 100% rename from sys/apis/turtle/pathfind.lua rename to sys/apis/pathfind.lua diff --git a/sys/apis/trace.lua b/sys/apis/trace.lua index 78cc535..6a0a2cb 100644 --- a/sys/apis/trace.lua +++ b/sys/apis/trace.lua @@ -51,6 +51,9 @@ local function trim_traceback(target, marker) t_len = t_len - 1 end + ttarget[#ttarget] = nil -- remove 2 calls added by the added xpcall + ttarget[#ttarget] = nil + return ttarget end @@ -83,14 +86,14 @@ return function (fn, ...) -- If this traceback is more than 15 elements long, keep the first 9, last 5 -- and put an ellipsis between the rest - local max = 12 + local max = 10 if trace_starts and #trace - trace_starts > max then - local keep_starts = trace_starts + 9 + local keep_starts = trace_starts + 7 for i = #trace - trace_starts - max, 0, -1 do table.remove(trace, keep_starts + i) end table.insert(trace, keep_starts, " ...") end - return false, table.concat(trace, "\n") + return false, table.remove(trace, 1), table.concat(trace, "\n") end return table.unpack(res, 1, res.n) diff --git a/sys/apis/turtle/home.lua b/sys/apis/turtle/home.lua deleted file mode 100644 index 29a1cbc..0000000 --- a/sys/apis/turtle/home.lua +++ /dev/null @@ -1,42 +0,0 @@ -local Config = require('config') -local GPS = require('gps') - -local turtle = _G.turtle - -local Home = { } - -function Home.go() - local config = { } - Config.load('gps', config) - - if config.home then - if turtle.enableGPS() then - return turtle.pathfind(config.home) - end - end -end - -function Home.set() - local config = { } - Config.load('gps', config) - - local pt = GPS.getPoint() - if pt then - local originalHeading = turtle.point.heading - local heading = GPS.getHeading() - if heading then - local turns = (turtle.point.heading - originalHeading) % 4 - pt.heading = (heading - turns) % 4 - config.home = pt - Config.update('gps', config) - - pt = GPS.getPoint() - pt.heading = heading - turtle.setPoint(pt, true) - turtle._goto(config.home) - return config.home - end - end -end - -return Home diff --git a/sys/apps/system/turtle.lua b/sys/apps/system/turtle.lua deleted file mode 100644 index fe6fadf..0000000 --- a/sys/apps/system/turtle.lua +++ /dev/null @@ -1,62 +0,0 @@ -local Config = require('config') -local UI = require('ui') - -local fs = _G.fs -local turtle = _G.turtle - -if turtle then - local Home = require('turtle.home') - local values = { } - Config.load('gps', values.home and { values.home } or { }) - - local gpsTab = UI.Tab { - tabTitle = 'GPS', - labelText = UI.Text { - x = 3, y = 2, - value = 'On restart, return to this location' - }, - grid = UI.Grid { - x = 3, ex = -3, y = 4, - height = 2, - values = values, - inactive = true, - columns = { - { heading = 'x', key = 'x' }, - { heading = 'y', key = 'y' }, - { heading = 'z', key = 'z' }, - }, - }, - button1 = UI.Button { - x = 3, y = 7, - text = 'Set home', - event = 'gps_set', - }, - button2 = UI.Button { - ex = -3, y = 7, width = 7, - text = 'Clear', - event = 'gps_clear', - }, - } - function gpsTab:eventHandler(event) - if event.type == 'gps_set' then - self:emit({ type = 'info_message', message = 'Determining location' }) - self:sync() - if Home.set() then - Config.load('gps', values) - self.grid:setValues(values.home and { values.home } or { }) - self.grid:draw() - self:emit({ type = 'success_message', message = 'Location set' }) - else - self:emit({ type = 'error_message', message = 'Unable to determine location' }) - end - return true - elseif event.type == 'gps_clear' then - fs.delete('usr/config/gps') - self.grid:setValues({ }) - self.grid:draw() - return true - end - end - - return gpsTab -end diff --git a/sys/autorun/gps.lua b/sys/autorun/gps.lua deleted file mode 100644 index 856ebad..0000000 --- a/sys/autorun/gps.lua +++ /dev/null @@ -1,43 +0,0 @@ -local modem = _G.device.wireless_modem -local turtle = _G.turtle - -if turtle and modem then - local s, m = turtle.run(function() - - _G.requireInjector(_ENV) - - local Config = require('config') - local config = { - destructive = false, - } - Config.load('gps', config) - - if config.home then - - local s = turtle.enableGPS(2) - if not s then - s = turtle.enableGPS(2) - end - if not s and config.destructive then - turtle.set({ attackPolicy = 'attack', digPolicy = 'turtleSafe' }) - s = turtle.enableGPS(2) - end - - if not s then - error('Unable to get GPS position') - end - - if config.destructive then - turtle.set({ attackPolicy = 'attack', digPolicy = 'turtleSafe' }) - end - - if not turtle.pathfind(config.home) then - error('Failed to return home') - end - end - end) - - if not s and m then - error(m) - end -end diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index a134e78..23fee77 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -2,7 +2,7 @@ if not _G.turtle then return end -local Pathing = require('turtle.pathfind') +local Pathing = require('pathfind') local GPS = require('gps') local Point = require('point') local synchronized = require('sync').sync @@ -661,7 +661,7 @@ end -- go backwards - turning around if necessary to fight mobs / break blocks function turtle.goback() local hi = headings[turtle.point.heading] - return turtle._goto({ + return turtle.go({ x = turtle.point.x - hi.xd, y = turtle.point.y, z = turtle.point.z - hi.zd, @@ -670,8 +670,8 @@ function turtle.goback() end function turtle.gotoYfirst(pt) - if turtle._gotoY(pt.y) then - if turtle._goto(pt) then + if turtle.gotoY(pt.y) then + if turtle.go(pt) then turtle.setHeading(pt.heading) return true end @@ -679,7 +679,7 @@ function turtle.gotoYfirst(pt) end function turtle.gotoYlast(pt) - if turtle._goto({ x = pt.x, z = pt.z, heading = pt.heading }) then + if turtle.go({ x = pt.x, z = pt.z, heading = pt.heading }) then if turtle.gotoY(pt.y) then turtle.setHeading(pt.heading) return true @@ -687,8 +687,18 @@ function turtle.gotoYlast(pt) end end -function turtle._goto(pt) - local dx, dy, dz, dh = pt.x, pt.y, pt.z, pt.heading +function turtle.go(pt) + if not pt.x and not pt.z and pt.y then + if turtle.gotoY(pt.y) then + turtle.setHeading(pt.heading) + return true + end + return false, 'Failed to reach location' + end + + local dx = pt.x or turtle.point.x + local dz = pt.z or turtle.point.z + local dy, dh = pt.y, pt.heading if not turtle.gotoSingleTurn(dx, dy, dz, dh) then if not gotoMultiTurn(dx, dy, dz) then return false, 'Failed to reach location' @@ -699,7 +709,9 @@ function turtle._goto(pt) end -- avoid lint errors -turtle['goto'] = turtle._goto +-- deprecated +turtle['goto'] = turtle.go +turtle['_goto'] = turtle.go function turtle.gotoX(dx) turtle.headTowardsX(dx) @@ -1026,7 +1038,7 @@ function turtle.setMovementStrategy(strategy) if strategy == 'pathing' then movementStrategy = turtle.pathfind elseif strategy == 'goto' then - movementStrategy = turtle._goto + movementStrategy = turtle.go else error('Invalid movement strategy') end diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index 1cd1bf0..271cded 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -109,7 +109,7 @@ local function xprun(env, path, ...) setmetatable(env, { __index = _G }) local fn, m = loadfile(path, env) if fn then - return pcall(fn, ...) + return trace(fn, ...) end return fn, m end @@ -125,12 +125,12 @@ function multishell.openTab(tab) local routine = kernel.newRoutine(tab) routine.co = coroutine.create(function() - local result, err + local result, err, stacktrace if tab.fn then result, err = Util.runFunction(routine.env, tab.fn, table.unpack(tab.args or { } )) elseif tab.path then - result, err = xprun(routine.env, tab.path, table.unpack(tab.args or { } )) + result, err, stacktrace = xprun(routine.env, tab.path, table.unpack(tab.args or { } )) else err = 'multishell: invalid tab' end @@ -138,6 +138,9 @@ function multishell.openTab(tab) if not result and err and err ~= 'Terminated' then if err then printError(tostring(err)) + if stacktrace then -- alternatively log stack to _debug + print(stacktrace) + end end print('\nPress enter to close') routine.isDead = true From c2ee88ba0ec9efd93f1db0718c9659cb82d3d8bd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 18 Feb 2019 03:17:29 -0500 Subject: [PATCH 075/231] fix cursor positioning --- sys/apis/terminal.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 904f36e..6cdacbd 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -82,12 +82,16 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) function win.setCursorPos(x, y) cx, cy = x, y - parent.setCursorPos(x + canvas.x - 1, y + canvas.y - 1) + if isVisible then + parent.setCursorPos(x + canvas.x - 1, y + canvas.y - 1) + end end function win.setCursorBlink(b) blink = b - parent.setCursorBlink(b) + if isVisible then + parent.setCursorBlink(b) + end end function win.isColor() From da35988d5073312924fdabbcc50126a0941999ab Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 19 Feb 2019 08:55:11 -0500 Subject: [PATCH 076/231] kiosk settings --- sys/apps/system/kiosk.lua | 55 ++++++++++++++++++++++++++++++++++++ sys/apps/system/settings.lua | 29 ++++++++++--------- 2 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 sys/apps/system/kiosk.lua diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua new file mode 100644 index 0000000..aac7954 --- /dev/null +++ b/sys/apps/system/kiosk.lua @@ -0,0 +1,55 @@ +local UI = require('ui') + +local device = _G.device +local peripheral = _G.peripheral +local settings = _G.settings + +local tab = UI.Tab { + tabTitle = 'Kiosk', + description = 'Kiosk options', + form = UI.Form { + x = 2, + manualControls = true, + monitor = UI.Chooser { + formLabel = 'Monitor', formKey = 'monitor', + }, + textScale = UI.Chooser { + formLabel = 'Font Size', formKey = 'textScale', + nochoice = 'Small', + choices = { + { name = 'Small', value = '.5' }, + { name = 'Large', value = '1' }, + }, + help = 'Adjust text scaling', + }, + }, +} + +function tab:enable() + local choices = { } + + for k,v in pairs(device) do + if v.type == 'monitor' then + table.insert(choices, { name = k, value = v.name }) + end + end + + self.form.monitor.choices = choices + self.form.monitor.value = settings.get('kiosk.monitor') + + self.form.textScale.value = settings.get('kiosk.textscale') + + UI.Tab.enable(self) +end + +function tab:eventHandler(event) + if event.type == 'choice_change' then + settings.set('kiosk.monitor', self.form.monitor.value) + settings.set('kiosk.textscale', self.form.textScale.value) + settings.save('.settings') + end +end + +if peripheral.find('monitor') then + return tab +end diff --git a/sys/apps/system/settings.lua b/sys/apps/system/settings.lua index dc919ff..f5d35db 100644 --- a/sys/apps/system/settings.lua +++ b/sys/apps/system/settings.lua @@ -3,24 +3,11 @@ local UI = require('ui') local settings = _G.settings if settings then - local values = { } - for _,v in pairs(settings.getNames()) do - local value = settings.get(v) - if not value then - value = false - end - table.insert(values, { - name = v, - value = value, - }) - end - local settingsTab = UI.Tab { tabTitle = 'Settings', description = 'Computercraft configurable settings', grid = UI.Grid { y = 2, - values = values, autospace = true, sortColumn = 'name', columns = { @@ -30,6 +17,22 @@ if settings then }, } + function settingsTab:enable() + local values = { } + for _,v in pairs(settings.getNames()) do + local value = settings.get(v) + if not value then + value = false + end + table.insert(values, { + name = v, + value = value, + }) + end + self.grid:setValues(values) + UI.Tab.enable(self) + end + function settingsTab:eventHandler(event) if event.type == 'grid_select' then if not event.selected.value or type(event.selected.value) == 'boolean' then From c307f4020c6214ffd9584dcdf0b1215a9940d67c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 20 Feb 2019 01:24:37 -0500 Subject: [PATCH 077/231] term bugs + kiosk config --- sys/apis/entry.lua | 2 +- sys/apis/terminal.lua | 4 +++- sys/apps/system/kiosk.lua | 10 +++++++--- sys/extensions/7.multishell.lua | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index 992e967..fd77af9 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -132,7 +132,7 @@ function Entry:process(ie) elseif ie.code == 'mouse_click' then -- need starting x passed in instead of hardcoding 3 - self.pos = math.min(ie.x - 3 + self.scroll, #self.value) + self.pos = math.max(0, math.min(ie.x - 3 + self.scroll, #self.value)) updated = true elseif ie.code == 'mouse_rightclick' then diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 6cdacbd..950741e 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -323,8 +323,9 @@ function Terminal.copy(it, ot) end function Terminal.mirror(ct, dt) + local t = { } for k,f in pairs(ct) do - ct[k] = function(...) + t[k] = function(...) local ret = { f(...) } if dt[k] then dt[k](...) @@ -332,6 +333,7 @@ function Terminal.mirror(ct, dt) return table.unpack(ret) end end + return t end function Terminal.readPassword(prompt) diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua index aac7954..0eda77b 100644 --- a/sys/apps/system/kiosk.lua +++ b/sys/apps/system/kiosk.lua @@ -30,7 +30,7 @@ function tab:enable() for k,v in pairs(device) do if v.type == 'monitor' then - table.insert(choices, { name = k, value = v.name }) + table.insert(choices, { name = k, value = v.side }) end end @@ -44,8 +44,12 @@ end function tab:eventHandler(event) if event.type == 'choice_change' then - settings.set('kiosk.monitor', self.form.monitor.value) - settings.set('kiosk.textscale', self.form.textScale.value) + if self.form.monitor.value then + settings.set('kiosk.monitor', self.form.monitor.value) + end + if self.form.textScale.value then + settings.set('kiosk.textscale', self.form.textScale.value) + end settings.save('.settings') end end diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index 271cded..ea7e5c3 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -139,7 +139,7 @@ function multishell.openTab(tab) if err then printError(tostring(err)) if stacktrace then -- alternatively log stack to _debug - print(stacktrace) + print('\n' .. stacktrace) end end print('\nPress enter to close') From ab4fd29d16fb737cad0c7b7e36c33e04595a4481 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 20 Feb 2019 08:52:27 -0500 Subject: [PATCH 078/231] turtle follow --- sys/apis/gps.lua | 25 ++++++++++++++++--------- sys/apis/trace.lua | 12 +++++++++++- sys/apps/system/kiosk.lua | 4 ++-- sys/extensions/6.tl3.lua | 4 ++-- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/sys/apis/gps.lua b/sys/apis/gps.lua index cf53d61..c7f24e7 100644 --- a/sys/apis/gps.lua +++ b/sys/apis/gps.lua @@ -34,30 +34,37 @@ function GPS.getPoint(timeout, debug) return pt end -function GPS.getHeading(timeout) - +function GPS.getHeading(timeout, destructive) if not turtle then return end local apt = GPS.locate(timeout) if not apt then - return + return false, 'GPS not available' end local heading = turtle.point.heading - while not turtle.forward() do + while true do + if not turtle.inspect() and turtle.forward() then + break + end turtle.turnRight() if turtle.getHeading() == heading then - _G.printError('GPS.getPoint: Unable to move forward') - return + if destructive then + turtle.dig() + if turtle.forward() then + break + end + end + return false, 'GPS.getPoint: Unable to move forward' end end local bpt = GPS.locate() if not bpt then - return + return false, 'GPS not available' end if apt.x < bpt.x then @@ -70,8 +77,8 @@ function GPS.getHeading(timeout) return 3 end -function GPS.getPointAndHeading(timeout) - local heading = GPS.getHeading(timeout) +function GPS.getPointAndHeading(timeout, destructive) + local heading = GPS.getHeading(timeout, destructive) if heading then local pt = GPS.getPoint() if pt then diff --git a/sys/apis/trace.lua b/sys/apis/trace.lua index 6a0a2cb..ddb023c 100644 --- a/sys/apis/trace.lua +++ b/sys/apis/trace.lua @@ -84,15 +84,25 @@ return function (fn, ...) if trace[i] == "stack traceback:" then trace_starts = i; break end end + for _, line in pairs(trace) do + _G._debug(line) + end + -- If this traceback is more than 15 elements long, keep the first 9, last 5 -- and put an ellipsis between the rest local max = 10 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 + for i = #trace - trace_starts - max, 0, -1 do + table.remove(trace, keep_starts + i) + end table.insert(trace, keep_starts, " ...") end + for k, line in pairs(trace) do + trace[k] = line:gsub("in function", " in") + end + return false, table.remove(trace, 1), table.concat(trace, "\n") end diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua index 0eda77b..d75bec2 100644 --- a/sys/apps/system/kiosk.lua +++ b/sys/apps/system/kiosk.lua @@ -28,9 +28,9 @@ local tab = UI.Tab { function tab:enable() local choices = { } - for k,v in pairs(device) do + for _,v in pairs(device) do if v.type == 'monitor' then - table.insert(choices, { name = k, value = v.side }) + table.insert(choices, { name = v.side, value = v.side }) end end diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 23fee77..d3649ba 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -1239,8 +1239,8 @@ function turtle.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspe function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end -- [[ GPS ]] -- -function turtle.enableGPS(timeout) - local pt = GPS.getPointAndHeading(timeout) +function turtle.enableGPS(timeout, destructive) + local pt = GPS.getPointAndHeading(timeout, destructive) if pt then turtle.setPoint(pt, true) return turtle.point From fc46239f448fe8542934ca916511a36b7027140f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 21 Feb 2019 02:03:41 -0500 Subject: [PATCH 079/231] turtle status --- sys/extensions/6.tl3.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index d3649ba..abba19f 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -345,6 +345,9 @@ function turtle.set(args) elseif k == 'moveCallback' then turtle.setMoveCallback(v) + elseif k == 'status' then + turtle.setStatus(v) + else error('Invalid turle.set: ' .. tostring(k)) end From 4485a751bdfba864046df6e4b1fe239ce40d8fb7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 22 Feb 2019 03:52:47 -0500 Subject: [PATCH 080/231] turtle gps rework --- sys/apis/gps.lua | 55 ----------------------------- sys/apis/ui/components/Checkbox.lua | 4 +++ sys/apps/Network.lua | 2 ++ sys/extensions/6.tl3.lua | 10 ------ 4 files changed, 6 insertions(+), 65 deletions(-) diff --git a/sys/apis/gps.lua b/sys/apis/gps.lua index c7f24e7..1b3e223 100644 --- a/sys/apis/gps.lua +++ b/sys/apis/gps.lua @@ -2,7 +2,6 @@ local GPS = { } local device = _G.device local gps = _G.gps -local turtle = _G.turtle function GPS.locate(timeout, debug) local pt = { } @@ -34,60 +33,6 @@ function GPS.getPoint(timeout, debug) return pt end -function GPS.getHeading(timeout, destructive) - if not turtle then - return - end - - local apt = GPS.locate(timeout) - if not apt then - return false, 'GPS not available' - end - - local heading = turtle.point.heading - - while true do - if not turtle.inspect() and turtle.forward() then - break - end - turtle.turnRight() - if turtle.getHeading() == heading then - if destructive then - turtle.dig() - if turtle.forward() then - break - end - end - return false, 'GPS.getPoint: Unable to move forward' - end - end - - local bpt = GPS.locate() - if not bpt then - return false, 'GPS not available' - end - - if apt.x < bpt.x then - return 0 - elseif apt.z < bpt.z then - return 1 - elseif apt.x > bpt.x then - return 2 - end - return 3 -end - -function GPS.getPointAndHeading(timeout, destructive) - local heading = GPS.getHeading(timeout, destructive) - if heading then - local pt = GPS.getPoint() - if pt then - pt.heading = heading - end - return pt - end -end - -- from stock gps API local function trilaterate(A, B, C) local a2b = B.position - A.position diff --git a/sys/apis/ui/components/Checkbox.lua b/sys/apis/ui/components/Checkbox.lua index a780c42..9f0b272 100644 --- a/sys/apis/ui/components/Checkbox.lua +++ b/sys/apis/ui/components/Checkbox.lua @@ -45,6 +45,10 @@ function UI.Checkbox:focus() self:draw() end +function UI.Checkbox:setValue(v) + self.value = v +end + function UI.Checkbox:reset() self.value = false end diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index f209aa1..517c98f 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -23,6 +23,8 @@ local config = Config.load('network', { }) if UI.term.width >= 30 then table.insert(gridColumns, { heading = 'Fuel', key = 'fuel', width = 5 }) +end +if UI.term.width >= 40 then table.insert(gridColumns, { heading = 'Uptime', key = 'uptime' }) end diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index abba19f..3a32a08 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -3,7 +3,6 @@ if not _G.turtle then end local Pathing = require('pathfind') -local GPS = require('gps') local Point = require('point') local synchronized = require('sync').sync local Util = require('util') @@ -1241,15 +1240,6 @@ function turtle.inspectDownAt(pt) return _actionDownAt(actionsAt.inspect, function turtle.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspect, pt) end function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end --- [[ GPS ]] -- -function turtle.enableGPS(timeout, destructive) - local pt = GPS.getPointAndHeading(timeout, destructive) - if pt then - turtle.setPoint(pt, true) - return turtle.point - end -end - -- deprecate function turtle.addFeatures(...) for _,feature in pairs({ ... }) do From 1c859029f15788eed54d2f208a47c96e63a9c159 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 23 Feb 2019 07:27:35 -0500 Subject: [PATCH 081/231] cleanup --- sys/apps/Welcome.lua | 2 +- sys/autorun/upgraded.lua | 1 + sys/extensions/6.tl3.lua | 7 ------- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 2648cd6..0d190b9 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -83,7 +83,7 @@ local page = UI.Page { intro = UI.TextArea { textColor = colors.yellow, inactive = true, - x = 3, ex = -3, y = 2, ey = -3, + x = 3, ex = -3, y = 2, ey = -4, value = string.format(packagesIntro, Ansi.white), }, }, diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index 4992f7d..2ce1d9d 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -1,3 +1,4 @@ if fs.exists('sys/apps/shell') and fs.exists('sys/apps/shell.lua') then fs.delete('sys/apps/shell') end +if fs.exists('sys/autorun/gps.lua') then fs.delete('sys/autorun/gps.lua') end \ No newline at end of file diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 3a32a08..948cb30 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -1240,11 +1240,4 @@ function turtle.inspectDownAt(pt) return _actionDownAt(actionsAt.inspect, function turtle.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspect, pt) end function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end --- deprecate -function turtle.addFeatures(...) - for _,feature in pairs({ ... }) do - require('turtle.' .. feature) - end -end - turtle.reset() From 8ae3b333741762a6bbbc620b9170a11f0d954b12 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 23 Feb 2019 18:36:17 -0500 Subject: [PATCH 082/231] network sniffer --- sys/apis/socket.lua | 6 ++-- sys/apis/util.lua | 10 ++----- sys/apps/Network.lua | 7 +++++ sys/apps/sniff.lua | 69 +++++++++++++++++++++++++++++++++++++++++++ sys/network/proxy.lua | 2 +- 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 sys/apps/sniff.lua diff --git a/sys/apis/socket.lua b/sys/apis/socket.lua index a2d2d7a..75ae3a3 100644 --- a/sys/apis/socket.lua +++ b/sys/apis/socket.lua @@ -131,23 +131,21 @@ function Socket.connect(host, port) os.cancelTimer(timerId) if msg.type == 'CONN' then - socket.dport = dport socket.connected = true -- Logger.log('socket', 'connection established to %d %d->%d', -- host, socket.sport, socket.dport) - _G.transport.open(socket) - return socket + elseif msg.type == 'REJE' then + socket:close() return false, 'Password not set on target or not trusted' end end until e == 'timer' and id == timerId socket:close() - return false, 'Connection timed out' end diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 2150840..658f875 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -119,14 +119,8 @@ function Util.signum(num) end end -function Util.clamp(lo, num, hi) - if num <= lo then - return lo - elseif num >= hi then - return hi - else - return num - end +function Util.clamp(num, low, high) + return num < low and low or num > high and high or num end -- http://lua-users.org/wiki/SimpleRound diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 517c98f..5e17d46 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -128,6 +128,13 @@ local function sendCommand(host, command) end end +function page.ports:eventHandler(event) + if event.type == 'grid_select' then + shell.openForegroundTab('sniff ' .. event.selected.port) + end + return UI.SlideOut.eventHandler(self, event) +end + function page.ports.grid:update() local function findConnection(port) for _,socket in pairs(_G.transport.sockets) do diff --git a/sys/apps/sniff.lua b/sys/apps/sniff.lua new file mode 100644 index 0000000..ada3d77 --- /dev/null +++ b/sys/apps/sniff.lua @@ -0,0 +1,69 @@ +local Event = require('event') +local Terminal = require('terminal') +local Util = require('util') + +local colors = _G.colors +local modem = _G.device.wireless_modem +local term = _G.term +local textutils = _G.textutils + +local terminal = Terminal.window(term.current()) +terminal.setMaxScroll(300) +local oldTerm = term.redirect(terminal) + +local function syntax() + error('Syntax: sniff [port]') +end + +local port = ({ ... })[1] or syntax() +port = tonumber(port) or syntax() + +Event.on('modem_message', + function(_, _, dport, _, data, _) + if dport == port then + terminal.scrollBottom() + terminal.setTextColor(colors.white) + print(textutils.serialize(data)) + end + end) + +Event.on('mouse_scroll', function(_, direction) + if direction == -1 then + terminal.scrollUp() + else + terminal.scrollDown() + end +end) + +local function sniffer(_, _, data) + terminal.scrollBottom() + terminal.setTextColor(colors.yellow) + local ot = term.redirect(terminal) + print(textutils.serialize(data)) + term.redirect(ot) +end + +local socket = _G.transport.sockets[port] +if socket then + if not socket.sniffers then + socket.sniffers = { modem.transmit } + socket.transmit = function(...) + for _,v in pairs(socket.sniffers) do + v(...) + end + end + end + table.insert(socket.sniffers, sniffer) +end + +local s, m = pcall(Event.pullEvents) + +if socket then + Util.removeByValue(socket.sniffers, sniffer) +end + +term.redirect(oldTerm) + +if not s and m then + error(m) +end diff --git a/sys/network/proxy.lua b/sys/network/proxy.lua index 46ec14b..6aaddef 100644 --- a/sys/network/proxy.lua +++ b/sys/network/proxy.lua @@ -32,7 +32,7 @@ Event.addRoutine(function() print('proxy: lost connection from ' .. socket.dhost) break end - socket:write({ proxy[data.fn](table.unpack(data.args)) }) + socket:write({ proxy[data[1]](table.unpack(data, 2)) }) end end end) From 687fc05445ab954b202c8bf7db90801a94751b10 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 24 Feb 2019 06:58:26 -0500 Subject: [PATCH 083/231] Event cleanup --- sys/apis/event.lua | 51 +++++-------------------- sys/apis/ui/components/Notification.lua | 8 +++- sys/apis/ui/components/StatusBar.lua | 5 +-- 3 files changed, 18 insertions(+), 46 deletions(-) diff --git a/sys/apis/event.lua b/sys/apis/event.lua index 5fe4d87..a71ace8 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -5,9 +5,8 @@ local Event = { uid = 1, -- unique id for handlers routines = { }, -- coroutines types = { }, -- event handlers - timers = { }, -- named timers terminate = false, - free = { }, + free = { }, -- allocated unused coroutines } -- Use a pool of coroutines for event handlers @@ -118,24 +117,6 @@ function Event.off(h) end end -local function addTimer(interval, recurring, fn) - local timerId = os.startTimer(interval) - local handler - - handler = Event.on('timer', function(t, id) - if timerId == id then - fn(t, id) - if recurring then - timerId = os.startTimer(interval) - else - Event.off(handler) - end - end - end) - - return handler -end - function Event.onInterval(interval, fn) return Event.addRoutine(function() while true do @@ -146,29 +127,17 @@ function Event.onInterval(interval, fn) end function Event.onTimeout(timeout, fn) - return addTimer(timeout, false, fn) -end - -function Event.addNamedTimer(name, interval, recurring, fn) - Event.cancelNamedTimer(name) - Event.timers[name] = addTimer(interval, recurring, fn) -end - -function Event.cancelNamedTimer(name) - local timer = Event.timers[name] - if timer then - Event.off(timer) - end -end - -function Event.waitForEvent(event, timeout) local timerId = os.startTimer(timeout) - repeat - local e = { os.pullEvent() } - if e[1] == event then - return table.unpack(e) + local handler + + handler = Event.on('timer', function(t, id) + if timerId == id then + fn(t, id) + Event.off(handler) end - until e[1] == 'timer' and e[2] == timerId + end) + + return handler end -- Set a handler for the terminate event. Within the function, return diff --git a/sys/apis/ui/components/Notification.lua b/sys/apis/ui/components/Notification.lua index f71408b..901a68c 100644 --- a/sys/apis/ui/components/Notification.lua +++ b/sys/apis/ui/components/Notification.lua @@ -35,8 +35,12 @@ function UI.Notification:success(value, timeout) end function UI.Notification:cancel() + if self.timer then + Event.off(self.timer) + self.timer = nil + end + if self.canvas then - Event.cancelNamedTimer('notificationTimer') self.enabled = false self.canvas:removeLayer() self.canvas = nil @@ -60,7 +64,7 @@ function UI.Notification:display(value, timeout) self:write(2, k, v) end - Event.addNamedTimer('notificationTimer', timeout or 3, false, function() + self.timer = Event.onTimeout(timeout or 3, function() self:cancel() self:sync() end) diff --git a/sys/apis/ui/components/StatusBar.lua b/sys/apis/ui/components/StatusBar.lua index 183014a..af1d2c4 100644 --- a/sys/apis/ui/components/StatusBar.lua +++ b/sys/apis/ui/components/StatusBar.lua @@ -62,10 +62,9 @@ function UI.StatusBar:getValue(name) end function UI.StatusBar:timedStatus(status, timeout) - timeout = timeout or 3 self:write(2, 1, Util.widthify(status, self.width-2), self.backgroundColor) - Event.addNamedTimer('statusTimer', timeout, false, function() - if self.parent.enabled then + Event.on(timeout or 3, function() + if self.enabled then self:draw() self:sync() end From 8f4324f1d824ad9b1529efad63873af43422295e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 25 Feb 2019 09:02:40 -0500 Subject: [PATCH 084/231] map convience functions (refactor) --- sys/apis/map.lua | 37 +++++++++++++++++++++++++++++++++ sys/apis/ui/components/Form.lua | 5 +---- sys/apis/util.lua | 14 ------------- 3 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 sys/apis/map.lua diff --git a/sys/apis/map.lua b/sys/apis/map.lua new file mode 100644 index 0000000..4fc3bc8 --- /dev/null +++ b/sys/apis/map.lua @@ -0,0 +1,37 @@ +-- convience functions for tables with key/value pairs +local Util = require('util') + +local Map = { } + +function Map.removeMatches(t, values) + local function matchAll(entry) + for k, v in pairs(values) do + if entry[k] ~= v then + return + end + end + return true + end + + for k,v in pairs(t) do + if matchAll(v) then + t[k] = nil + end + end +end + +-- remove table entries if passed function returns false +function Map.prune(t, fn) + for _,k in pairs(Util.keys(t)) do + local v = t[k] + if type(v) == 'table' then + t[k] = Util.prune(v, fn) + end + if not fn(t[k]) then + t[k] = nil + end + end + return t +end + +return Map diff --git a/sys/apis/ui/components/Form.lua b/sys/apis/ui/components/Form.lua index 43b3557..6db3085 100644 --- a/sys/apis/ui/components/Form.lua +++ b/sys/apis/ui/components/Form.lua @@ -122,10 +122,7 @@ function UI.Form:save() end for _,child in pairs(self.children) do if child.formKey then - if (child.pruneEmpty and type(child.value) == 'string' and #child.value == 0) or - (child.pruneEmpty and type(child.value) == 'boolean' and not child.value) then - self.values[child.formKey] = nil - elseif child.validate == 'numeric' then + if child.validate == 'numeric' then self.values[child.formKey] = tonumber(child.value) else self.values[child.formKey] = child.value diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 658f875..8b3d26b 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -187,20 +187,6 @@ function Util.deepMerge(obj, args) end end --- remove table entries if passed function returns false -function Util.prune(t, fn) - for _,k in pairs(Util.keys(t)) do - local v = t[k] - if type(v) == 'table' then - t[k] = Util.prune(v, fn) - end - if not fn(t[k]) then - t[k] = nil - end - end - return t -end - function Util.transpose(t) local tt = { } for k,v in pairs(t) do From ad60fce9b0ca3b90785eb42cb83887d59f8d4616 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 26 Feb 2019 08:17:53 -0500 Subject: [PATCH 085/231] util refactor --- sys/apis/map.lua | 14 +++++++++++++- sys/apis/util.lua | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sys/apis/map.lua b/sys/apis/map.lua index 4fc3bc8..9e4ab93 100644 --- a/sys/apis/map.lua +++ b/sys/apis/map.lua @@ -3,6 +3,10 @@ local Util = require('util') local Map = { } +-- TODO: refactor +Map.merge = Util.merge +Map.shallowCopy = Util.shallowCopy + function Map.removeMatches(t, values) local function matchAll(entry) for k, v in pairs(values) do @@ -25,7 +29,7 @@ function Map.prune(t, fn) for _,k in pairs(Util.keys(t)) do local v = t[k] if type(v) == 'table' then - t[k] = Util.prune(v, fn) + t[k] = Map.prune(v, fn) end if not fn(t[k]) then t[k] = nil @@ -34,4 +38,12 @@ function Map.prune(t, fn) return t end +function Map.size(list) + local length = 0 + for _ in pairs(list) do + length = length + 1 + end + return length +end + return Map diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 8b3d26b..16d00b4 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -277,8 +277,9 @@ function Util.filter(it, f) end function Util.reduce(t, fn, acc) + acc = acc or 0 for _, v in pairs(t) do - fn(acc, v) + acc = fn(acc, v) end return acc end From cc1a2bfbf40cca83dbc0544fe289d7436510e086 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 26 Feb 2019 18:03:09 -0500 Subject: [PATCH 086/231] fix ui resizing (due to canvas changes) --- sys/apis/ui.lua | 1 + sys/apis/ui/components/ActiveLayer.lua | 12 +++++---- sys/apis/ui/components/Embedded.lua | 7 +++++ sys/apps/system/kiosk.lua | 8 +++++- sys/apps/system/network.lua | 36 ++++++++++++++------------ sys/apps/system/password.lua | 12 +++++---- 6 files changed, 49 insertions(+), 27 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 712b600..361484d 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -263,6 +263,7 @@ function Manager:click(target, code, button, x, y) if clickEvent.element.focus then target:setFocus(clickEvent.element) end +_G._p = clickEvent self:inputEvent(clickEvent.element, clickEvent) target:sync() diff --git a/sys/apis/ui/components/ActiveLayer.lua b/sys/apis/ui/components/ActiveLayer.lua index 8f84a4e..94354fe 100644 --- a/sys/apis/ui/components/ActiveLayer.lua +++ b/sys/apis/ui/components/ActiveLayer.lua @@ -5,11 +5,13 @@ UI.ActiveLayer = class(UI.Window) UI.ActiveLayer.defaults = { UIElement = 'ActiveLayer', } -function UI.ActiveLayer:setParent() - self:layout(self) - self.canvas = self:addLayer() - - UI.Window.setParent(self) +function UI.ActiveLayer:layout() + UI.Window.layout(self) + if not self.canvas then + self.canvas = self:addLayer() + else + self.canvas:resize(self.width, self.height) + end end function UI.ActiveLayer:enable(...) diff --git a/sys/apis/ui/components/Embedded.lua b/sys/apis/ui/components/Embedded.lua index 626516f..ad4db59 100644 --- a/sys/apis/ui/components/Embedded.lua +++ b/sys/apis/ui/components/Embedded.lua @@ -32,6 +32,13 @@ function UI.Embedded:setParent() self.win.clear() end +function UI.Embedded:layout() + UI.Window.layout(self) + if self.win then + self.win.reposition(self.x, self.y, self.width, self.height) + end +end + function UI.Embedded:draw() self.canvas:dirty() end diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua index d75bec2..56fe588 100644 --- a/sys/apps/system/kiosk.lua +++ b/sys/apps/system/kiosk.lua @@ -1,5 +1,6 @@ local UI = require('ui') +local colors = _G.colors local device = _G.device local peripheral = _G.peripheral local settings = _G.settings @@ -8,7 +9,7 @@ local tab = UI.Tab { tabTitle = 'Kiosk', description = 'Kiosk options', form = UI.Form { - x = 2, + x = 2, ex = -2, manualControls = true, monitor = UI.Chooser { formLabel = 'Monitor', formKey = 'monitor', @@ -22,6 +23,11 @@ local tab = UI.Tab { }, help = 'Adjust text scaling', }, + labelText = UI.TextArea { + x = 2, ex = -2, y = 5, + textColor = colors.yellow, + value = 'Settings apply to kiosk mode selected during startup' + }, }, } diff --git a/sys/apps/system/network.lua b/sys/apps/system/network.lua index 4f2199e..11f3c00 100644 --- a/sys/apps/system/network.lua +++ b/sys/apps/system/network.lua @@ -1,3 +1,4 @@ +local Ansi = require('ansi') local Config = require('config') local UI = require('ui') @@ -6,17 +7,20 @@ local device = _G.device local tab = UI.Tab { tabTitle = 'Network', description = 'Networking options', - form = UI.Form { - x = 2, - manualControls = true, - modem = UI.Chooser { - formLabel = 'Modem', formKey = 'modem', - nochoice = 'auto', - }, - update = UI.Button { - x = 9, y = 4, - text = 'Update', event = 'form_complete', - }, + info = UI.TextArea { + x = 3, y = 4, + value = string.format( +[[%sSet the primary modem used for wireless communications.%s + +Reboot to take effect.]], Ansi.yellow, Ansi.reset) + }, + label = UI.Text { + x = 3, y = 2, + value = 'Modem', + }, + modem = UI.Chooser { + x = 10, ex = -3, y = 2, + nochoice = 'auto', }, } @@ -34,19 +38,19 @@ function tab:enable() end end - self.form.modem.choices = choices - self.form.modem.width = width + 4 + self.modem.choices = choices + --self.modem.width = width + 4 local config = Config.load('os') - self.form.modem.value = config.wirelessModem or 'auto' + self.modem.value = config.wirelessModem or 'auto' UI.Tab.enable(self) end function tab:eventHandler(event) - if event.type == 'form_complete' then + if event.type == 'choice_change' then local config = Config.load('os') - config.wirelessModem = self.form.modem.value + config.wirelessModem = self.modem.value Config.update('os', config) self:emit({ type = 'success_message', message = 'reboot to take effect' }) return true diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua index 4c45616..5f705a6 100644 --- a/sys/apps/system/password.lua +++ b/sys/apps/system/password.lua @@ -2,18 +2,20 @@ local Security = require('security') local SHA1 = require('sha1') local UI = require('ui') +local colors = _G.colors + local passwordTab = UI.Tab { tabTitle = 'Password', description = 'Wireless network password', oldPass = UI.TextEntry { - x = 2, y = 2, ex = -2, + x = 3, ex = -3, y = 2, limit = 32, mask = true, shadowText = 'old password', inactive = not Security.getPassword(), }, newPass = UI.TextEntry { - y = 3, x = 2, ex = -2, + x = 3, ex = -3, y = 3, limit = 32, mask = true, shadowText = 'new password', @@ -22,13 +24,13 @@ local passwordTab = UI.Tab { }, }, button = UI.Button { - x = 2, y = 5, + x = 3, y = 5, text = 'Update', event = 'update_password', }, info = UI.TextArea { - x = 2, ex = -2, - y = 7, + x = 3, ex = -3, y = 7, + textColor = colors.yellow, inactive = true, value = 'Add a password to enable other computers to connect to this one.', } From 4dc6062043cd13964a30c4c697d4ba9acb053c51 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 27 Feb 2019 08:10:09 -0500 Subject: [PATCH 087/231] cleanup --- sys/apis/ui.lua | 1 - sys/apis/ui/components/Text.lua | 7 ++++++- sys/apps/Tasks.lua | 19 ++++++++----------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 361484d..712b600 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -263,7 +263,6 @@ function Manager:click(target, code, button, x, y) if clickEvent.element.focus then target:setFocus(clickEvent.element) end -_G._p = clickEvent self:inputEvent(clickEvent.element, clickEvent) target:sync() diff --git a/sys/apis/ui/components/Text.lua b/sys/apis/ui/components/Text.lua index 96310ec..186bd58 100644 --- a/sys/apis/ui/components/Text.lua +++ b/sys/apis/ui/components/Text.lua @@ -16,5 +16,10 @@ function UI.Text:setParent() end function UI.Text:draw() - self:write(1, 1, Util.widthify(self.value or '', self.width), self.backgroundColor) + if self.align and self.align == 'center' then + self:clear() + self:centeredWrite(1, self.value or '') + else + self:write(1, 1, Util.widthify(self.value or '', self.width)) + end end diff --git a/sys/apps/Tasks.lua b/sys/apps/Tasks.lua index 5bcd043..9b35be2 100644 --- a/sys/apps/Tasks.lua +++ b/sys/apps/Tasks.lua @@ -1,8 +1,5 @@ -_G.requireInjector(_ENV) - local Event = require('event') local UI = require('ui') -local Util = require('util') local kernel = _G.kernel local multishell = _ENV.multishell @@ -51,15 +48,15 @@ function page:eventHandler(event) end function page.grid:getDisplayValues(row) - row = Util.shallowCopy(row) local elapsed = os.clock()-row.timestamp - if elapsed < 60 then - row.timestamp = string.format("%ds", math.floor(elapsed)) - else - row.timestamp = string.format("%sm", math.floor(elapsed/6)/10) - end - row.status = row.isDead and 'error' or coroutine.status(row.co) - return row + return { + uid = row.uid, + title = row.title, + status = row.isDead and 'error' or coroutine.status(row.co), + timestamp = elapsed < 60 and + string.format("%ds", math.floor(elapsed)) or + string.format("%sm", math.floor(elapsed/6)/10), + } end Event.onInterval(1, function() From 69e6af231492f9ea8415a4507e033df4c73bc092 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 27 Feb 2019 17:15:20 -0500 Subject: [PATCH 088/231] rename justify property to align --- sys/apis/ui/components/Grid.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/apis/ui/components/Grid.lua b/sys/apis/ui/components/Grid.lua index c5ce6db..331d4ae 100644 --- a/sys/apis/ui/components/Grid.lua +++ b/sys/apis/ui/components/Grid.lua @@ -22,14 +22,14 @@ function Writer:init(element, y) self.x = 1 end -function Writer:write(s, width, justify, bg, fg) +function Writer:write(s, width, align, bg, fg) local len = #tostring(s or '') if len > width then s = _sub(s, 1, width) end local padding = len < width and _rep(' ', width - len) if padding then - if justify == 'right' then + if align == 'right' then s = padding .. s else s = s .. padding @@ -301,7 +301,7 @@ function UI.Grid:drawHeadings() end sb:write(ind .. col.heading, col.cw + 1, - col.justify, + col.align, self.headerBackgroundColor, color) end @@ -341,7 +341,7 @@ function UI.Grid:drawRows() for _,col in pairs(self.columns) do sb:write(ind .. safeValue(row[col.key] or ''), col.cw + 1, - col.justify, + col.align, bg, fg) ind = ' ' From 1e011c8bbd46198463347ad319ab8eb47bd65ae6 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 1 Mar 2019 11:27:27 -0500 Subject: [PATCH 089/231] refactor --- sys/apis/util.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 16d00b4..73e0a52 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -27,6 +27,13 @@ function Util.tryTimes(attempts, f, ...) return unpack(result) end +function Util.Timer() + local ct = os.clock() + return function() + return os.clock() - ct + end +end + function Util.throttle(fn) local ts = os.clock() local timeout = .095 From 7a57d74e6800a26ad0e2647fa80810f461fcb9ca Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 1 Mar 2019 14:16:55 -0500 Subject: [PATCH 090/231] neural status --- sys/network/snmp.lua | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sys/network/snmp.lua b/sys/network/snmp.lua index 50297b1..628ebda 100644 --- a/sys/network/snmp.lua +++ b/sys/network/snmp.lua @@ -152,9 +152,28 @@ local function sendInfo() info.status = device.neuralInterface.status pcall(function() if not info.status and device.neuralInterface.getMetaOwner then - info.status = 'health: ' .. - math.floor(device.neuralInterface.getMetaOwner().health / - device.neuralInterface.getMetaOwner().maxHealth * 100) + local meta = device.neuralInterface.getMetaOwner() + if meta.isWet then + info.status = 'Swimming' + elseif meta.isElytraFlying then + info.status = 'Flying' + elseif meta.isBurning then + info.status = 'Burning' + elseif meta.isDead then + info.status = 'Deceased' + elseif meta.isOnLadder then + info.status = 'Climbing' + elseif meta.isRiding then + info.status = 'Riding' + elseif meta.isSneaking then + info.status = 'Sneaking' + elseif meta.isSprinting then + info.status = 'Running' + else + info.status = 'health: ' .. + math.floor(meta.health / + meta.maxHealth * 100) + end end end) end From ce9ffa6c3a0fc02eb2b884f922fc84c20844c3b9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 6 Mar 2019 11:48:09 -0500 Subject: [PATCH 091/231] alignment update --- sys/apis/ui/components/Text.lua | 7 +--- sys/apis/util.lua | 68 ++++++++++++++++++++++----------- sys/extensions/6.packages.lua | 4 +- sys/network/snmp.lua | 9 +++-- 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/sys/apis/ui/components/Text.lua b/sys/apis/ui/components/Text.lua index 186bd58..68926d2 100644 --- a/sys/apis/ui/components/Text.lua +++ b/sys/apis/ui/components/Text.lua @@ -16,10 +16,5 @@ function UI.Text:setParent() end function UI.Text:draw() - if self.align and self.align == 'center' then - self:clear() - self:centeredWrite(1, self.value or '') - else - self:write(1, 1, Util.widthify(self.value or '', self.width)) - end + self:write(1, 1, Util.widthify(self.value, self.width, self.align)) end diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 73e0a52..4e45641 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -6,6 +6,10 @@ local os = _G.os local term = _G.term local textutils = _G.textutils +local _sformat = string.format +local _srep = string.rep +local _ssub = string.sub + function Util.tryTimed(timeout, f, ...) local c = os.clock() repeat @@ -27,13 +31,15 @@ function Util.tryTimes(attempts, f, ...) return unpack(result) end -function Util.Timer() +function Util.timer() local ct = os.clock() return function() return os.clock() - ct end end +Util.Timer = Util.timer -- deprecate + function Util.throttle(fn) local ts = os.clock() local timeout = .095 @@ -56,11 +62,11 @@ function Util.tostring(pattern, ...) for k, v in pairs(tbl) do local value if type(v) == 'table' then - value = string.format('table: %d', Util.size(v)) + value = _sformat('table: %d', Util.size(v)) else value = tostring(v) end - str = str .. string.format(' %s: %s\n', k, value) + str = str .. _sformat(' %s: %s\n', k, value) end --if #str < width then --str = str:gsub('\n', '') .. ' }' @@ -71,7 +77,7 @@ function Util.tostring(pattern, ...) end if type(pattern) == 'string' then - return string.format(pattern, ...) + return _sformat(pattern, ...) elseif type(pattern) == 'table' then return serialize(pattern, term.current().getSize()) end @@ -473,7 +479,7 @@ end function Util.download(url, filename) local contents, msg = Util.httpGet(url) if not contents then - error(string.format('Failed to download %s\n%s', url, msg), 2) + error(_sformat('Failed to download %s\n%s', url, msg), 2) end if filename then @@ -519,11 +525,11 @@ end function Util.toBytes(n) if not tonumber(n) then error('Util.toBytes: n must be a number', 2) end if n >= 1000000 or n <= -1000000 then - return string.format('%sM', math.floor(n/1000000 * 10) / 10) + return _sformat('%sM', math.floor(n/1000000 * 10) / 10) elseif n >= 10000 or n <= -10000 then - return string.format('%sK', math.floor(n/1000)) + return _sformat('%sK', math.floor(n/1000)) elseif n >= 1000 or n <= -1000 then - return string.format('%sK', math.floor(n/1000 * 10) / 10) + return _sformat('%sK', math.floor(n/1000 * 10) / 10) end return tostring(n) end @@ -551,17 +557,33 @@ function Util.matches(str, pattern) end function Util.startsWith(s, match) - return string.sub(s, 1, #match) == match + return _ssub(s, 1, #match) == match end -function Util.widthify(s, len) +-- return a fixed length string using specified alignment +function Util.widthify(s, len, align) s = s or '' local slen = #s - if slen < len then - s = s .. string.rep(' ', len - #s) - elseif slen > len then - s = s:sub(1, len) + + if slen > len then + return _ssub(s, 1, len) + elseif slen == len then + return s end + + if align == 'center' then + local space = math.floor((len-slen) / 2) + local filler = _srep(' ', space + 1) + s = _ssub(filler, 1, space) .. s + s = s .. _srep(' ', len - #s) + + elseif align == 'right' then + s = _srep(' ', len - #s) .. s + + else -- 'left' + s = s .. _srep(' ', len - #s) + end + return s end @@ -628,8 +650,8 @@ function Util.args(arg) local k = 1 while k <= #arg do local v = arg[k] - if string.sub(v, 1, 1) == '-' then - local opt = string.sub(v, 2) + if _ssub(v, 1, 1) == '-' then + local opt = _ssub(v, 2) options[opt] = arg[k + 1] k = k + 1 else @@ -645,20 +667,20 @@ local function getopt( arg, options ) local tab = {} for k, v in ipairs(arg) do if type(v) == 'string' then - if string.sub( v, 1, 2) == "--" then + if _ssub( v, 1, 2) == "--" then local x = string.find( v, "=", 1, true ) - if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 ) - else tab[ string.sub( v, 3 ) ] = true + if x then tab[ _ssub( v, 3, x-1 ) ] = _ssub( v, x+1 ) + else tab[ _ssub( v, 3 ) ] = true end - elseif string.sub( v, 1, 1 ) == "-" then + elseif _ssub( v, 1, 1 ) == "-" then local y = 2 local l = string.len(v) local jopt while ( y <= l ) do - jopt = string.sub( v, y, y ) + jopt = _ssub( v, y, y ) if string.find( options, jopt, 1, true ) then if y < l then - tab[ jopt ] = string.sub( v, y+1 ) + tab[ jopt ] = _ssub( v, y+1 ) y = l else tab[ jopt ] = arg[ k + 1 ] @@ -677,7 +699,7 @@ end function Util.showOptions(options) print('Arguments: ') for _, v in pairs(options) do - print(string.format('-%s %s', v.arg, v.desc)) + print(_sformat('-%s %s', v.arg, v.desc)) end end diff --git a/sys/extensions/6.packages.lua b/sys/extensions/6.packages.lua index b8f6340..9baf271 100644 --- a/sys/extensions/6.packages.lua +++ b/sys/extensions/6.packages.lua @@ -18,12 +18,12 @@ for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) table.insert(appPaths, 1, packageDir) - local apiPath = fs.combine(fs.combine('packages', name), 'apis') + local apiPath = fs.combine(packageDir, 'apis') if fs.exists(apiPath) then fs.mount(fs.combine('sys/apis', name), 'linkfs', apiPath) end - local helpPath = '/' .. fs.combine(fs.combine('packages', name), 'help') + local helpPath = '/' .. fs.combine(packageDir, 'help') if fs.exists(helpPath) then table.insert(helpPaths, helpPath) end diff --git a/sys/network/snmp.lua b/sys/network/snmp.lua index 628ebda..07ccc0a 100644 --- a/sys/network/snmp.lua +++ b/sys/network/snmp.lua @@ -150,9 +150,10 @@ local function sendInfo() end if device.neuralInterface then info.status = device.neuralInterface.status - pcall(function() - if not info.status and device.neuralInterface.getMetaOwner then + if not info.status and device.neuralInterface.getMetaOwner then + pcall(function() local meta = device.neuralInterface.getMetaOwner() + if meta.isWet then info.status = 'Swimming' elseif meta.isElytraFlying then @@ -174,8 +175,8 @@ local function sendInfo() math.floor(meta.health / meta.maxHealth * 100) end - end - end) + end) + end end device.wireless_modem.transmit(999, os.getComputerID(), info) end From a4145951f79074021ff3a32f9a148e9b6d461569 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 6 Mar 2019 16:56:41 -0500 Subject: [PATCH 092/231] bulk download --- sys/apis/bulkget.lua | 33 +++++++++++++++++++++++++++++++++ sys/apps/package.lua | 16 ++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 sys/apis/bulkget.lua diff --git a/sys/apis/bulkget.lua b/sys/apis/bulkget.lua new file mode 100644 index 0000000..1135847 --- /dev/null +++ b/sys/apis/bulkget.lua @@ -0,0 +1,33 @@ +local Util = require('util') + +local parallel = _G.parallel + +local BulkGet = { } + +function BulkGet.download(list, callback) + local t = { } + local failed = false + + for _ = 1, 5 do + table.insert(t, function() + while true do + local entry = table.remove(list) + if not entry then + break + end + local s, m = Util.download(entry.url, entry.path) + if not s then + failed = true + end + callback(entry, s, m) + if failed then + break + end + end + end) + end + + parallel.waitForAll(table.unpack(t)) +end + +return BulkGet diff --git a/sys/apps/package.lua b/sys/apps/package.lua index 45016cd..f604e3c 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -1,3 +1,4 @@ +local BulkGet = require('bulkget') local Git = require('git') local Packages = require('packages') local Util = require('util') @@ -53,10 +54,21 @@ local function install(name, isUpdate) local list = Git.list(manifest.repository) local showProgress = progress(Util.size(list)) + + local getList = { } for path, entry in pairs(list) do - Util.download(entry.url, fs.combine(packageDir, path)) - showProgress() + table.insert(getList, { + path = fs.combine(packageDir, path), + url = entry.url + }) end + + BulkGet.download(getList, function(_, s, m) + if not s then + error(m) + end + showProgress() + end) end if action == 'list' then From 89f95ca45b5c73855a8266423230b261ed14c0bd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 7 Mar 2019 13:14:16 -0500 Subject: [PATCH 093/231] stack traces --- sys/apis/util.lua | 17 +++++++---------- sys/apps/Network.lua | 10 ++++++---- sys/apps/shell.lua | 3 ++- sys/extensions/7.multishell.lua | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 4e45641..d016feb 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -567,24 +567,21 @@ function Util.widthify(s, len, align) if slen > len then return _ssub(s, 1, len) + elseif slen == len then return s - end - if align == 'center' then - local space = math.floor((len-slen) / 2) - local filler = _srep(' ', space + 1) - s = _ssub(filler, 1, space) .. s - s = s .. _srep(' ', len - #s) + elseif align == 'center' then + local space = math.floor((len - slen) / 2) + s = _srep(' ', space) .. s + return s .. _srep(' ', len - #s) elseif align == 'right' then - s = _srep(' ', len - #s) .. s + return _srep(' ', len - slen) .. s - else -- 'left' - s = s .. _srep(' ', len - #s) end - return s + return s .. _srep(' ', len - slen) end -- http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76 diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 5e17d46..c8232ff 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -15,17 +15,17 @@ UI:configure('Network', ...) local gridColumns = { { heading = 'Label', key = 'label' }, - { heading = 'Dist', key = 'distance' }, + { heading = 'Dist', key = 'distance', align = 'right' }, { heading = 'Status', key = 'status' }, } local config = Config.load('network', { }) if UI.term.width >= 30 then - table.insert(gridColumns, { heading = 'Fuel', key = 'fuel', width = 5 }) + table.insert(gridColumns, { heading = 'Fuel', key = 'fuel', width = 5, align = 'right' }) end if UI.term.width >= 40 then - table.insert(gridColumns, { heading = 'Uptime', key = 'uptime' }) + table.insert(gridColumns, { heading = 'Uptime', key = 'uptime', align = 'right' }) end local page = UI.Page { @@ -262,8 +262,10 @@ function page.grid:getDisplayValues(row) if row.uptime then if row.uptime < 60 then row.uptime = string.format("%ds", math.floor(row.uptime)) + elseif row.uptime < 3600 then + row.uptime = string.format("%sm", math.floor(row.uptime / 60)) else - row.uptime = string.format("%sm", math.floor(row.uptime/6)/10) + row.uptime = string.format("%sh", math.floor(row.uptime / 3600)) end end if row.fuel then diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index 68fc0b3..8946e0a 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -13,6 +13,7 @@ sandboxEnv.shell = shell _G.requireInjector(_ENV) +local trace = require('trace') local Util = require('util') local DIR = (parentShell and parentShell.dir()) or "" @@ -88,7 +89,7 @@ function shell.run(...) local env = setmetatable(Util.shallowCopy(sandboxEnv), { __index = _G }) _G.requireInjector(env) - local r = { pcall(run, env, ...) } + local r = { trace(run, env, ...) } if _ENV.multishell then _ENV.multishell.setTitle(_ENV.multishell.getCurrent(), oldTitle or 'shell') diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index ea7e5c3..d5de390 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -139,7 +139,7 @@ function multishell.openTab(tab) if err then printError(tostring(err)) if stacktrace then -- alternatively log stack to _debug - print('\n' .. stacktrace) + --print('\n' .. stacktrace) end end print('\nPress enter to close') From a9d03b06e9e068538b5744c9427020f2fa1155da Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 8 Mar 2019 16:25:56 -0500 Subject: [PATCH 094/231] phase out peripheral.lookup --- sys/apis/peripheral.lua | 122 -------------------------------- sys/apis/proxy.lua | 32 +++++++++ sys/apis/ui.lua | 5 +- sys/apps/password.lua | 2 - sys/apps/telnet.lua | 2 - sys/apps/trust.lua | 2 - sys/apps/vnc.lua | 2 - sys/autorun/hotkeys.lua | 12 ++-- sys/extensions/7.multishell.lua | 2 +- sys/network/peripheral.lua | 86 ---------------------- sys/network/proxy.lua | 39 +++++++--- 11 files changed, 69 insertions(+), 237 deletions(-) create mode 100644 sys/apis/proxy.lua delete mode 100644 sys/network/peripheral.lua diff --git a/sys/apis/peripheral.lua b/sys/apis/peripheral.lua index 33a1df1..a176268 100644 --- a/sys/apis/peripheral.lua +++ b/sys/apis/peripheral.lua @@ -1,9 +1,5 @@ -local Event = require('event') -local Socket = require('socket') local Util = require('util') -local os = _G.os - local Peripheral = Util.shallowCopy(_G.peripheral) function Peripheral.getList() @@ -121,122 +117,4 @@ function Peripheral.get(args) end end -local function getProxy(pi) - local socket, msg = Socket.connect(pi.host, 189) - - if not socket then - error("Timed out attaching peripheral: " .. pi.uri .. '\n' .. msg) - end - - -- write the uri of the periperal we are requesting... - -- ie. type/monitor - socket:write(pi.path) - local proxy = socket:read(3) - - if not proxy then - error("Timed out attaching peripheral: " .. pi.uri) - end - - if type(proxy) == 'string' then - error(proxy) - end - - local methods = proxy.methods - proxy.methods = nil - - for _,method in pairs(methods) do - proxy[method] = function(...) - socket:write({ fn = method, args = { ... } }) - local resp = socket:read() - if not resp then - error("Timed out communicating with peripheral: " .. pi.uri) - end - return table.unpack(resp) - end - end - - if proxy.blit then - local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit', - 'setTextColor', 'setTextColour', 'setBackgroundColor', - 'setBackgroundColour', 'scroll', 'setCursorBlink', } - local queue = nil - - for _,method in pairs(methods) do - proxy[method] = function(...) - if not queue then - queue = { } - Event.onTimeout(0, function() - if not socket:write({ fn = 'fastBlit', args = { queue } }) then - error("Timed out communicating with peripheral: " .. pi.uri) - end - queue = nil - socket:read() - end) - end - if not socket.connected then - error("Timed out communicating with peripheral: " .. pi.uri) - end - - table.insert(queue, { - fn = method, - args = { ... }, - }) - end - end - end - - if proxy.type == 'monitor' then - Event.addRoutine(function() - while true do - local data = socket:read() - if not data then - break - end - if data.fn and data.fn == 'event' then - os.queueEvent(table.unpack(data.data)) - end - end - end) - end - - return proxy -end - ---[[ - Parse a uri into it's components - - Examples: - monitor = { name = 'monitor' } - side/top = { side = 'top' } - method/list = { method = 'list' } - 12://name/monitor = { host = 12, name = 'monitor' } -]]-- -local function parse(uri) - local pi = Util.split(uri:gsub('^%d*://', ''), '(.-)/') - - if #pi == 1 then - pi = { - 'name', - pi[1], - } - end - - return { - host = uri:match('^(%d*)%:'), -- 12 - uri = uri, -- 12://name/monitor - path = uri:gsub('^%d*://', ''), -- name/monitor - [ pi[1] ] = pi[2], -- name = 'monitor' - } -end - -function Peripheral.lookup(uri) - local pi = parse(uri) - - if pi.host and _G.device.wireless_modem then - return getProxy(pi) - end - - return Peripheral.get(pi) -end - return Peripheral diff --git a/sys/apis/proxy.lua b/sys/apis/proxy.lua new file mode 100644 index 0000000..4603d57 --- /dev/null +++ b/sys/apis/proxy.lua @@ -0,0 +1,32 @@ +local Socket = require('socket') + +local Proxy = { } + +function Proxy.create(remoteId, uri) + local socket, msg = Socket.connect(remoteId, 188) + + if not socket then + error(msg) + end + + socket.co = coroutine.running() + + socket:write(uri) + local methods = socket:read() or error('Timed out') + + local hijack = { } + for _,method in pairs(methods) do + hijack[method] = function(...) + socket:write({ method, ... }) + local resp = socket:read() + if not resp then + error('timed out: ' .. method) + end + return table.unpack(resp) + end + end + + return hijack, socket +end + +return Proxy diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 712b600..70b6dbc 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -2,7 +2,6 @@ local Canvas = require('ui.canvas') local class = require('class') local Event = require('event') local Input = require('input') -local Peripheral = require('peripheral') local Transition = require('ui.transition') local Util = require('util') @@ -12,6 +11,7 @@ local colors = _G.colors local device = _G.device local fs = _G.fs local os = _G.os +local peripheral = _G.peripheral local term = _G.term --[[ @@ -178,13 +178,12 @@ function Manager:configure(appName, ...) Util.merge(defaults.device, optionValues) if defaults.device.name then - local dev if defaults.device.name == 'terminal' then dev = term.current() else - dev = Peripheral.lookup(defaults.device.name) --- device[defaults.device.name] + dev = peripheral.wrap(defaults.device.name) end if not dev then diff --git a/sys/apps/password.lua b/sys/apps/password.lua index eb3c5b0..ca0f5b5 100644 --- a/sys/apps/password.lua +++ b/sys/apps/password.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Security = require('security') local SHA1 = require('sha1') local Terminal = require('terminal') diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 25c6c05..8a736a3 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Event = require('event') local Socket = require('socket') local Terminal = require('terminal') diff --git a/sys/apps/trust.lua b/sys/apps/trust.lua index b8cb705..da8ff55 100644 --- a/sys/apps/trust.lua +++ b/sys/apps/trust.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Crypto = require('crypto') local Security = require('security') local SHA1 = require('sha1') diff --git a/sys/apps/vnc.lua b/sys/apps/vnc.lua index 5b17700..0540125 100644 --- a/sys/apps/vnc.lua +++ b/sys/apps/vnc.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Event = require('event') local Socket = require('socket') local Terminal = require('terminal') diff --git a/sys/autorun/hotkeys.lua b/sys/autorun/hotkeys.lua index 9c9dfce..3c97e0e 100644 --- a/sys/autorun/hotkeys.lua +++ b/sys/autorun/hotkeys.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Util = require('util') local kernel = _G.kernel @@ -21,10 +19,12 @@ keyboard.addHotkey('control-backspace', function() local tab = kernel.find(uid) if not tab.isOverview then multishell.terminate(uid) - tab = Util.shallowCopy(tab) - tab.isDead = false - tab.focused = true - multishell.openTab(tab) + multishell.openTab({ + path = tab.path, + env = tab.env, + args = tab.args, + focused = true, + }) end end) diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index d5de390..9bbfb2c 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -24,7 +24,7 @@ local multishell = { } shell.setEnv('multishell', multishell) -multishell.term = parentTerm --deprecated +multishell.term = parentTerm --deprecated use device.terminal local config = { standard = { diff --git a/sys/network/peripheral.lua b/sys/network/peripheral.lua deleted file mode 100644 index 89e2b86..0000000 --- a/sys/network/peripheral.lua +++ /dev/null @@ -1,86 +0,0 @@ ---[[ - Allow sharing of local peripherals. -]]-- - -local Event = require('event') -local Peripheral = require('peripheral') -local Socket = require('socket') - -Event.addRoutine(function() - print('peripheral: listening on port 189') - while true do - local socket = Socket.server(189) - - print('peripheral: connection from ' .. socket.dhost) - - Event.addRoutine(function() - local uri = socket:read(2) - if uri then - local peripheral = Peripheral.lookup(uri) - --- only 1 proxy of this device can happen at one time --- need to prevent multiple shares - if not peripheral then - print('peripheral: invalid peripheral ' .. uri) - socket:write('Invalid peripheral: ' .. uri) - else - print('peripheral: proxing ' .. uri) - local proxy = { - methods = { } - } - - if peripheral.blit then - --peripheral = Util.shallowCopy(peripheral) - peripheral.fastBlit = function(data) - for _,v in ipairs(data) do - peripheral[v.fn](unpack(v.args)) - end - end - end - - for k,v in pairs(peripheral) do - if type(v) == 'function' then - table.insert(proxy.methods, k) - else - proxy[k] = v - end - end - - socket:write(proxy) - - if proxy.type == 'monitor' then - peripheral.eventChannel = function(...) - socket:write({ - fn = 'event', - data = { ... } - }) - end - end - - while true do - local data = socket:read() - if not data then - print('peripheral: lost connection from ' .. socket.dhost) - break - end - if not _G.device[peripheral.name] then - print('periperal: detached') - socket:close() - break - end - if peripheral[data.fn] then - -- need to trigger an error on the other end - -- local s, m = pcall() - socket:write({ peripheral[data.fn](table.unpack(data.args)) }) - else - socket:write({ false, "Invalid function: " .. data.fn }) - end - end - - peripheral.eventChannel = nil - peripheral.fastBlit = nil - end - end - end) - end -end) diff --git a/sys/network/proxy.lua b/sys/network/proxy.lua index 6aaddef..c721896 100644 --- a/sys/network/proxy.lua +++ b/sys/network/proxy.lua @@ -1,5 +1,17 @@ local Event = require('event') local Socket = require('socket') +local Util = require('util') + +local function getProxy(path) + local x = Util.split(path, '(.-)/') + local proxy = _G + for _, v in pairs(x) do + proxy = proxy[v] + if not proxy then + break + end + end +end Event.addRoutine(function() while true do @@ -9,30 +21,35 @@ Event.addRoutine(function() print('proxy: connection from ' .. socket.dhost) Event.addRoutine(function() - local api = socket:read(2) - if api then - local proxy = _G[api] + local path = socket:read(2) + if path then + local api = getProxy(path) - if not proxy then + if not api then print('proxy: invalid API') return end local methods = { } - for k,v in pairs(proxy) do + for k,v in pairs(api) do if type(v) == 'function' then table.insert(methods, k) end end socket:write(methods) - while true do - local data = socket:read() - if not data then - print('proxy: lost connection from ' .. socket.dhost) - break + local s, m = pcall(function() + while true do + local data = socket:read() + if not data then + print('proxy: lost connection from ' .. socket.dhost) + break + end + socket:write({ api[data[1]](table.unpack(data, 2)) }) end - socket:write({ proxy[data[1]](table.unpack(data, 2)) }) + end) + if not s and m then + _G.printError(m) end end end) From 6f7e27827e430143f2b5e2b33dc0197a8a011fe0 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 8 Mar 2019 16:47:39 -0500 Subject: [PATCH 095/231] phase out peripheral.lookup --- sys/apis/proxy.lua | 2 +- sys/apps/Network.lua | 17 ++++------------- sys/network/proxy.lua | 3 +++ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/sys/apis/proxy.lua b/sys/apis/proxy.lua index 4603d57..eb3d819 100644 --- a/sys/apis/proxy.lua +++ b/sys/apis/proxy.lua @@ -12,7 +12,7 @@ function Proxy.create(remoteId, uri) socket.co = coroutine.running() socket:write(uri) - local methods = socket:read() or error('Timed out') + local methods = socket:read(2) or error('Timed out') local hijack = { } for _,method in pairs(methods) do diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index c8232ff..efc71de 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -6,7 +6,6 @@ local Util = require('util') local colors = _G.colors local device = _G.device -local multishell = _ENV.multishell local network = _G.network local os = _G.os local shell = _ENV.shell @@ -178,19 +177,10 @@ function page:eventHandler(event) local t = self.grid:getSelected() if t then if event.type == 'telnet' then - multishell.openTab({ - path = 'sys/apps/telnet.lua', - focused = true, - args = { t.id }, - title = t.label, - }) + shell.openForegroundTab('telnet ' .. t.id) + elseif event.type == 'vnc' then - multishell.openTab({ - path = 'sys/apps/vnc.lua', - focused = true, - args = { t.id }, - title = t.label, - }) + shell.openForegroundTab('vnc.lua ' .. t.id) os.queueEvent('overview_shortcut', { title = t.label, category = "VNC", @@ -199,6 +189,7 @@ function page:eventHandler(event) \031e\\/\031 \0319c", run = "vnc.lua " .. t.id, }) + elseif event.type == 'clear' then Util.clear(network) page.grid:update() diff --git a/sys/network/proxy.lua b/sys/network/proxy.lua index c721896..7e0f284 100644 --- a/sys/network/proxy.lua +++ b/sys/network/proxy.lua @@ -11,6 +11,7 @@ local function getProxy(path) break end end + return proxy end Event.addRoutine(function() @@ -27,6 +28,7 @@ Event.addRoutine(function() if not api then print('proxy: invalid API') + socket:close() return end @@ -52,6 +54,7 @@ Event.addRoutine(function() _G.printError(m) end end + socket:close() end) end end) From a569c2c90085bfc626c1a542c6acd94f59c04833 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 8 Mar 2019 20:50:50 -0500 Subject: [PATCH 096/231] pathing heading possible fix --- sys/apis/pathfind.lua | 4 +- sys/apis/ui/glasses.lua | 196 --------------------------------------- sys/extensions/6.tl3.lua | 10 +- 3 files changed, 3 insertions(+), 207 deletions(-) delete mode 100644 sys/apis/ui/glasses.lua diff --git a/sys/apis/pathfind.lua b/sys/apis/pathfind.lua index ce0fa69..ffb5d25 100644 --- a/sys/apis/pathfind.lua +++ b/sys/apis/pathfind.lua @@ -173,8 +173,8 @@ local function pathTo(dest, options) -- use single turn method so the turtle doesn't turn around -- when encountering obstacles - -- if not turtle.gotoSingleTurn(pt.x, pt.y, pt.z, pt.heading) then - if not turtle.goto(pt) then + if not turtle.gotoSingleTurn(pt.x, pt.y, pt.z, pt.heading) then + --if not turtle.goto(pt) then local bpt = Point.nearestTo(turtle.point, pt) table.insert(blocks, bpt) diff --git a/sys/apis/ui/glasses.lua b/sys/apis/ui/glasses.lua deleted file mode 100644 index cd8a26f..0000000 --- a/sys/apis/ui/glasses.lua +++ /dev/null @@ -1,196 +0,0 @@ -local class = require('class') -local UI = require('ui') -local Event = require('event') -local Peripheral = require('peripheral') - ---[[-- Glasses device --]]-- -local Glasses = class() -function Glasses:init(args) - - local defaults = { - backgroundColor = colors.black, - textColor = colors.white, - textScale = .5, - backgroundOpacity = .5, - multiplier = 2.6665, --- multiplier = 2.333, - } - defaults.width, defaults.height = term.getSize() - - UI:setProperties(defaults, args) - UI:setProperties(self, defaults) - - self.bridge = Peripheral.get({ - type = 'openperipheral_bridge', - method = 'addBox', - }) - self.bridge.clear() - - self.setBackgroundColor = function(...) end - self.setTextColor = function(...) end - - self.t = { } - for i = 1, self.height do - self.t[i] = { - text = string.rep(' ', self.width+1), - --text = self.bridge.addText(0, 40+i*4, string.rep(' ', self.width+1), 0xffffff), - bg = { }, - textFields = { }, - } - end -end - -function Glasses:setBackgroundBox(boxes, ax, bx, y, bgColor) - local colors = { - [ colors.black ] = 0x000000, - [ colors.brown ] = 0x7F664C, - [ colors.blue ] = 0x253192, - [ colors.red ] = 0xFF0000, - [ colors.gray ] = 0x272727, - [ colors.lime ] = 0x426A0D, - [ colors.green ] = 0x2D5628, - [ colors.white ] = 0xFFFFFF - } - - local function overlap(box, ax, bx) - if bx < box.ax or ax > box.bx then - return false - end - return true - end - - for _,box in pairs(boxes) do - if overlap(box, ax, bx) then - if box.bgColor == bgColor then - ax = math.min(ax, box.ax) - bx = math.max(bx, box.bx) - box.ax = box.bx + 1 - elseif ax == box.ax then - box.ax = bx + 1 - elseif ax > box.ax then - if bx < box.bx then - table.insert(boxes, { -- split - ax = bx + 1, - bx = box.bx, - bgColor = box.bgColor - }) - box.bx = ax - 1 - break - else - box.ax = box.bx + 1 - end - elseif ax < box.ax then - if bx > box.bx then - box.ax = box.bx + 1 -- delete - else - box.ax = bx + 1 - end - end - end - end - if bgColor ~= colors.black then - table.insert(boxes, { - ax = ax, - bx = bx, - bgColor = bgColor - }) - end - - local deleted - repeat - deleted = false - for k,box in pairs(boxes) do - if box.ax > box.bx then - if box.box then - box.box.delete() - end - table.remove(boxes, k) - deleted = true - break - end - if not box.box then - box.box = self.bridge.addBox( - math.floor(self.x + (box.ax - 1) * self.multiplier), - self.y + y * 4, - math.ceil((box.bx - box.ax + 1) * self.multiplier), - 4, - colors[bgColor], - self.backgroundOpacity) - else - box.box.setX(self.x + math.floor((box.ax - 1) * self.multiplier)) - box.box.setWidth(math.ceil((box.bx - box.ax + 1) * self.multiplier)) - end - end - until not deleted -end - -function Glasses:write(x, y, text, bg) - - if x < 1 then - error(' less ', 6) - end - if y <= #self.t then - local line = self.t[y] - local str = line.text - str = str:sub(1, x-1) .. text .. str:sub(x + #text) - self.t[y].text = str - - for _,tf in pairs(line.textFields) do - tf.delete() - end - line.textFields = { } - - local function split(st) - local words = { } - local offset = 0 - while true do - local b,e,w = st:find('(%S+)') - if not b then - break - end - table.insert(words, { - offset = b + offset - 1, - text = w, - }) - offset = offset + e - st = st:sub(e + 1) - end - return words - end - - local words = split(str) - for _,word in pairs(words) do - local tf = self.bridge.addText(self.x + word.offset * self.multiplier, - self.y+y*4, '', 0xffffff) - tf.setScale(self.textScale) - tf.setZ(1) - tf.setText(word.text) - table.insert(line.textFields, tf) - end - - self:setBackgroundBox(line.bg, x, x + #text - 1, y, bg) - end -end - -function Glasses:clear(bg) - for _,line in pairs(self.t) do - for _,tf in pairs(line.textFields) do - tf.delete() - end - line.textFields = { } - line.text = string.rep(' ', self.width+1) --- self.t[i].text.setText('') - end -end - -function Glasses:reset() - self:clear() - self.bridge.clear() - self.bridge.sync() -end - -function Glasses:sync() - self.bridge.sync() -end - -return Glasses diff --git a/sys/extensions/6.tl3.lua b/sys/extensions/6.tl3.lua index 948cb30..ab4d93f 100644 --- a/sys/extensions/6.tl3.lua +++ b/sys/extensions/6.tl3.lua @@ -680,15 +680,6 @@ function turtle.gotoYfirst(pt) end end -function turtle.gotoYlast(pt) - if turtle.go({ x = pt.x, z = pt.z, heading = pt.heading }) then - if turtle.gotoY(pt.y) then - turtle.setHeading(pt.heading) - return true - end - end -end - function turtle.go(pt) if not pt.x and not pt.z and pt.y then if turtle.gotoY(pt.y) then @@ -715,6 +706,7 @@ end turtle['goto'] = turtle.go turtle['_goto'] = turtle.go +-- TODO: localize these goto functions function turtle.gotoX(dx) turtle.headTowardsX(dx) From bd9b2825be5f6190c8706c1288c82f47ffcc074c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 10 Mar 2019 19:36:56 -0400 Subject: [PATCH 097/231] icon update - thx LDD --- sys/apps/Network.lua | 2 +- sys/etc/app.db | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index efc71de..eeb00bf 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -263,7 +263,7 @@ function page.grid:getDisplayValues(row) row.fuel = row.fuel > 0 and Util.toBytes(row.fuel) or '' end if row.distance then - row.distance = Util.round(row.distance, 1) + row.distance = Util.toBytes(Util.round(row.distance, 1)) end return row end diff --git a/sys/etc/app.db b/sys/etc/app.db index f1349ff..edd19bd 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -11,6 +11,9 @@ title = "Cloud", category = "Apps", run = "cshell.lua", + iconExt = "\0300\031f\159\131\135\0310\128\128\031f\139\131\030f\0310\144\ +\0300\128\031f\137\144\0310\128\030a\136\149\133\0300\128\ +\0300\031f\144\134\136\132\031a\142\138\138\030f\0310\159", }, [ "53ebc572b4a44802ba114729f07bdaaf5409a9d7" ] = { title = "Network", From 04af12b452ab6d7570e6c97e08cca5a187838cf6 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 11 Mar 2019 23:48:22 -0400 Subject: [PATCH 098/231] remove dependency on device global --- sys/apis/ui.lua | 8 ++++---- sys/apis/util.lua | 4 ++++ sys/apps/system/kiosk.lua | 9 +++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 70b6dbc..cafd5aa 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -8,7 +8,6 @@ local Util = require('util') local _rep = string.rep local _sub = string.sub local colors = _G.colors -local device = _G.device local fs = _G.fs local os = _G.os local peripheral = _G.peripheral @@ -914,9 +913,9 @@ UI.Device.defaults = { function UI.Device:postInit() self.device = self.device or term.current() - if self.deviceType then - self.device = device[self.deviceType] - end + --if self.deviceType then + -- self.device = device[self.deviceType] + --end if not self.device.setTextScale then self.device.setTextScale = function() end @@ -1197,6 +1196,7 @@ end loadComponents() +UI.theme = { } UI:loadTheme('usr/config/ui.theme') if Util.getVersion() >= 1.76 then UI:loadTheme('sys/etc/ext.theme') diff --git a/sys/apis/util.lua b/sys/apis/util.lua index d016feb..53ee6cd 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -404,6 +404,10 @@ function Util.readFile(fname) end end +function Util.backupFile(fname) + fs.copy(fname, fname .. '.bak') +end + function Util.writeFile(fname, data) if not fname or not data then error('Util.writeFile: invalid parameters', 2) end local file = io.open(fname, "w") diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua index 56fe588..89a24e2 100644 --- a/sys/apps/system/kiosk.lua +++ b/sys/apps/system/kiosk.lua @@ -1,7 +1,6 @@ local UI = require('ui') local colors = _G.colors -local device = _G.device local peripheral = _G.peripheral local settings = _G.settings @@ -34,11 +33,9 @@ local tab = UI.Tab { function tab:enable() local choices = { } - for _,v in pairs(device) do - if v.type == 'monitor' then - table.insert(choices, { name = v.side, value = v.side }) - end - end + peripheral.find('monitor', function(side) + table.insert(choices, { name = side, value = side }) + end) self.form.monitor.choices = choices self.form.monitor.value = settings.get('kiosk.monitor') From 08791e87a3a0f454045c6434d3ced08399954c7c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 11 Mar 2019 23:54:00 -0400 Subject: [PATCH 099/231] oops --- sys/apis/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 53ee6cd..b2f7900 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -404,7 +404,7 @@ function Util.readFile(fname) end end -function Util.backupFile(fname) +function Util.backup(fname) fs.copy(fname, fname .. '.bak') end From 86be65f02633a5ec01a3212df3b315c441c87ac7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 12 Mar 2019 02:00:07 -0400 Subject: [PATCH 100/231] oops 2 --- sys/apis/util.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index b2f7900..771bcbb 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -405,7 +405,11 @@ function Util.readFile(fname) end function Util.backup(fname) - fs.copy(fname, fname .. '.bak') + local backup = fname .. '.bak' + if backup then + fs.delete(backup) + end + fs.copy(fname, backup) end function Util.writeFile(fname, data) From e2508c9037866319683dbc01f325ed818a4ee33e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 12 Mar 2019 20:04:28 -0400 Subject: [PATCH 101/231] cleanup --- sys/apis/util.lua | 10 ++++++++++ sys/apps/cedit.lua | 1 + sys/apps/cshell.lua | 1 + sys/extensions/2.vfs.lua | 3 +++ sys/help/CloudCatcher | 5 +++++ 5 files changed, 20 insertions(+) create mode 100644 sys/help/CloudCatcher diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 771bcbb..2a3fb64 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -414,6 +414,16 @@ end function Util.writeFile(fname, data) if not fname or not data then error('Util.writeFile: invalid parameters', 2) end + + if fs.exists(fname) then + local diff = #data - fs.getSize(fname) + if diff > 0 then + if fs.getFreeSpace(fs.getDir(fname)) < diff then + error('Insufficient disk space for ' .. fname) + end + end + end + local file = io.open(fname, "w") if not file then error('Unable to open ' .. fname, 2) diff --git a/sys/apps/cedit.lua b/sys/apps/cedit.lua index 8032688..5abcee0 100644 --- a/sys/apps/cedit.lua +++ b/sys/apps/cedit.lua @@ -13,6 +13,7 @@ if not _G.http.websocket then end if not _G.cloud_catcher then + print('Visit https://cloud-catcher.squiddev.cc') print('Paste key: ') local key = read() if #key == 0 then diff --git a/sys/apps/cshell.lua b/sys/apps/cshell.lua index 7bc6af6..91b1eab 100644 --- a/sys/apps/cshell.lua +++ b/sys/apps/cshell.lua @@ -6,6 +6,7 @@ if not _G.http.websocket then end if not _G.cloud_catcher then + print('Visit https://cloud-catcher.squiddev.cc') print('Paste key: ') local key = read() if #key == 0 then diff --git a/sys/extensions/2.vfs.lua b/sys/extensions/2.vfs.lua index 3558c60..d80474c 100644 --- a/sys/extensions/2.vfs.lua +++ b/sys/extensions/2.vfs.lua @@ -113,6 +113,7 @@ local function splitpath(path) end local function getNode(dir) + if not dir then error('Invalid directory', 2) end local cd = fs.combine(dir, '') local parts = splitpath(cd) local node = fs.nodes @@ -176,6 +177,8 @@ function fs.listEx(dir) end function fs.copy(s, t) + if not s then error('copy: bad argument #1') end + if not t then error('copy: bad argument #2') end local sp = getNode(s) local tp = getNode(t) if sp == tp and sp.fs.copy then diff --git a/sys/help/CloudCatcher b/sys/help/CloudCatcher new file mode 100644 index 0000000..e50dd86 --- /dev/null +++ b/sys/help/CloudCatcher @@ -0,0 +1,5 @@ +Cloud Catcher is a web terminal for ComputerCraft, allowing you to interact with any in-game computer in the browser, as well as edit files remotely! + +To get started, visit https://cloud-catcher.squiddev.cc/cloud.lua for a session key. + +Within Files, press 'c' to edit a file using Cloud Catcher. From 0c910820036d9c65ae62f8ea0a27c1da012ff186 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 15 Mar 2019 08:26:56 -0400 Subject: [PATCH 102/231] modules as devices --- sys/extensions/1.device.lua | 3 +-- sys/extensions/3.modules.lua | 47 ++++++++++++++++++++++++++++++++++++ sys/help/CloudCatcher | 2 +- 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 sys/extensions/3.modules.lua diff --git a/sys/extensions/1.device.lua b/sys/extensions/1.device.lua index d580563..f8bc7a9 100644 --- a/sys/extensions/1.device.lua +++ b/sys/extensions/1.device.lua @@ -59,8 +59,7 @@ end) kernel.hook('peripheral_detach', function(_, eventData) local side = eventData[1] if side then - local dev = Util.find(device, 'side', side) - if dev then + for _, dev in pairs(Util.findAll(device, 'side', side)) do os.queueEvent('device_detach', dev.name, dev) if dev._children then for _,v in pairs(dev._children) do diff --git a/sys/extensions/3.modules.lua b/sys/extensions/3.modules.lua new file mode 100644 index 0000000..f2411a3 --- /dev/null +++ b/sys/extensions/3.modules.lua @@ -0,0 +1,47 @@ +local Util = require('util') + +local device = _G.device +local kernel = _G.kernel +local os = _G.os +local peripheral = _G.peripheral + +local containers = { + manipulator = true, + neuralInterface = true, +} + +local function getModules(dev, side) + local list = { } + + if dev then + for _, module in pairs(dev.listModules()) do + list[module] = Util.shallowCopy(dev) + list[module].name = module + list[module].type = module + list[module].side = side + end + end + return list +end + +for _,v in pairs(device) do + if containers[v.type] then + local list = getModules(v, v.side) + for k, dev in pairs(list) do + device[k] = dev + end + end +end + +-- register modules as peripherals +kernel.hook('device_attach', function(_, eventData) + local dev = eventData[2] + + if dev and containers[dev.type] then + local list = getModules(peripheral.wrap(dev.side), dev.side) + for k,v in pairs(list) do + device[k] = v + os.queueEvent('device_attach', k, v) + end + end +end) diff --git a/sys/help/CloudCatcher b/sys/help/CloudCatcher index e50dd86..7494099 100644 --- a/sys/help/CloudCatcher +++ b/sys/help/CloudCatcher @@ -1,5 +1,5 @@ Cloud Catcher is a web terminal for ComputerCraft, allowing you to interact with any in-game computer in the browser, as well as edit files remotely! -To get started, visit https://cloud-catcher.squiddev.cc/cloud.lua for a session key. +To get started, visit https://cloud-catcher.squiddev.cc for a session key. Within Files, press 'c' to edit a file using Cloud Catcher. From 340636806cf78c4f7da0572fb867d2d482adc115 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 15 Mar 2019 09:21:24 -0400 Subject: [PATCH 103/231] modules as devices-fail --- sys/extensions/3.modules.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/extensions/3.modules.lua b/sys/extensions/3.modules.lua index f2411a3..4e53d41 100644 --- a/sys/extensions/3.modules.lua +++ b/sys/extensions/3.modules.lua @@ -10,6 +10,8 @@ local containers = { neuralInterface = true, } +if true then return end + local function getModules(dev, side) local list = { } From e5312ca6abf739e9d8bad61dbb6627d6ff5ae802 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 17 Mar 2019 23:54:44 -0400 Subject: [PATCH 104/231] better errors + modules as devices (try #2) + pretty lua output --- sys/apis/event.lua | 2 +- sys/apis/injector.lua | 2 ++ sys/apps/Lua.lua | 39 ++++++++++++++++++++++++------------ sys/extensions/3.modules.lua | 13 +++++++----- sys/kernel.lua | 2 +- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/sys/apis/event.lua b/sys/apis/event.lua index a71ace8..b563f2f 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -67,7 +67,7 @@ function Routine:resume(event, ...) end if not s and event ~= 'terminate' then - error('\n' .. (m or 'Error processing event')) + error(m or 'Error processing event', -1) end return s, m diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 2eb14dc..5497b24 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -29,6 +29,7 @@ local http = _G.http local os = _G.os local string = _G.string +--[[ if not http._patched then -- fix broken http get (http.get is not coroutine safe) local syncLocks = { } @@ -65,6 +66,7 @@ if not http._patched then return s, m end end +--]] local function loadUrl(url) local c diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index a1a3385..12bc072 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -20,6 +20,7 @@ _G.requireInjector(sandboxEnv) UI:configure('Lua', ...) local command = '' +local counter = 1 local history = History.load('usr/.lua_history', 25) local page = UI.Page { @@ -209,10 +210,6 @@ end function page:setResult(result) local t = { } - local oterm = term.redirect(self.output.win) - Util.print(result) - term.redirect(oterm) - local function safeValue(v) if type(v) == 'string' or type(v) == 'number' then return v @@ -297,24 +294,39 @@ end function page:rawExecute(s) local fn, m + local wrapped fn = load('return (' ..s.. ')', 'lua', nil, sandboxEnv) if fn then fn = load('return {' ..s.. '}', 'lua', nil, sandboxEnv) + wrapped = true end if fn then fn, m = pcall(fn) - if #m == 1 then + if #m <= 1 and wrapped then m = m[1] end - return fn, m + else + fn, m = load(s, 'lua', nil, sandboxEnv) + if fn then + fn, m = pcall(fn) + end end - fn, m = load(s, 'lua', nil, sandboxEnv) if fn then - fn, m = pcall(fn) + if m or wrapped then + local bg, fg = term.getBackgroundColor(), term.getTextColor() + term.setTextColor(colors.cyan) + term.setBackgroundColor(colors.black) + term.write(string.format('out [%d]: ', counter)) + term.setBackgroundColor(bg) + term.setTextColor(fg) + Util.print(m or 'nil') + end + else + _G.printError(m) end return fn, m @@ -331,17 +343,18 @@ function page:executeStatement(statement) self.output.win.scrollBottom() local bg, fg = term.getBackgroundColor(), term.getTextColor() term.setBackgroundColor(colors.black) - term.setTextColor(colors.yellow) - print('> ' .. tostring(statement)) + term.setTextColor(colors.green) + term.write(string.format('in [%d]: ', counter)) term.setBackgroundColor(bg) term.setTextColor(fg) + print(tostring(statement)) + pcall(function() s, m = self:rawExecute(command) end) - if not s then - _G.printError(m) - end + term.redirect(oterm) + counter = counter + 1 if s and m then self:setResult(m) diff --git a/sys/extensions/3.modules.lua b/sys/extensions/3.modules.lua index 4e53d41..6eb8c57 100644 --- a/sys/extensions/3.modules.lua +++ b/sys/extensions/3.modules.lua @@ -10,8 +10,6 @@ local containers = { neuralInterface = true, } -if true then return end - local function getModules(dev, side) local list = { } @@ -30,7 +28,10 @@ for _,v in pairs(device) do if containers[v.type] then local list = getModules(v, v.side) for k, dev in pairs(list) do - device[k] = dev + -- neural and attached modules have precedence over manipulator modules + if not device[k] or v.type ~= 'manipulator' then + device[k] = dev + end end end end @@ -42,8 +43,10 @@ kernel.hook('device_attach', function(_, eventData) if dev and containers[dev.type] then local list = getModules(peripheral.wrap(dev.side), dev.side) for k,v in pairs(list) do - device[k] = v - os.queueEvent('device_attach', k, v) + if not device[k] or dev.type ~= 'manipulator' then + device[k] = v + os.queueEvent('device_attach', k, v) + end end end end) diff --git a/sys/kernel.lua b/sys/kernel.lua index bad6b82..b81fd9e 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -92,7 +92,7 @@ function Routine:resume(event, ...) term.redirect(previousTerm) if not ok and self.haltOnError then - error(result) + error(result, -1) end if coroutine.status(self.co) == 'dead' then Util.removeByValue(kernel.routines, self) From cd6ed79d1119c3dfdc7ddb1a61651447d07518c6 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 19 Mar 2019 01:42:42 -0400 Subject: [PATCH 105/231] array api --- sys/apis/array.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 sys/apis/array.lua diff --git a/sys/apis/array.lua b/sys/apis/array.lua new file mode 100644 index 0000000..b6ba255 --- /dev/null +++ b/sys/apis/array.lua @@ -0,0 +1,13 @@ +local Array = { } + +function Array.filter(it, f) + local ot = { } + for _,v in pairs(it) do + if f(v) then + table.insert(ot, v) + end + end + return ot +end + +return Array From ea8e98188012d0434ec968906aebcde9ce9c2f38 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 22 Mar 2019 01:40:29 -0400 Subject: [PATCH 106/231] better cloud edit --- sys/apps/System.lua | 2 +- sys/apps/cedit.lua | 17 +++++++++---- sys/apps/cshell.lua | 16 ++++++++---- sys/apps/system/cloud.lua | 53 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 sys/apps/system/cloud.lua diff --git a/sys/apps/System.lua b/sys/apps/System.lua index 601edfe..5b1595a 100644 --- a/sys/apps/System.lua +++ b/sys/apps/System.lua @@ -10,7 +10,7 @@ local systemPage = UI.Page { tabs = UI.Tabs { settings = UI.Tab { tabTitle = 'Category', - grid = UI.Grid { + grid = UI.ScrollingGrid { y = 2, columns = { { heading = 'Name', key = 'name' }, diff --git a/sys/apps/cedit.lua b/sys/apps/cedit.lua index 5abcee0..f62a063 100644 --- a/sys/apps/cedit.lua +++ b/sys/apps/cedit.lua @@ -1,3 +1,5 @@ +local Config = require('config') + local multishell = _ENV.multishell local os = _G.os local read = _G.read @@ -13,12 +15,17 @@ if not _G.http.websocket then end if not _G.cloud_catcher then - print('Visit https://cloud-catcher.squiddev.cc') - print('Paste key: ') - local key = read() - if #key == 0 then - return + local key = Config.load('cloud').key + + if not key then + print('Visit https://cloud-catcher.squiddev.cc') + print('Paste key: ') + key = read() + if #key == 0 then + return + end end + -- open an unfocused tab local id = shell.openTab('cloud ' .. key) print('Connecting...') diff --git a/sys/apps/cshell.lua b/sys/apps/cshell.lua index 91b1eab..44cee34 100644 --- a/sys/apps/cshell.lua +++ b/sys/apps/cshell.lua @@ -1,3 +1,5 @@ +local Config = require('config') + local read = _G.read local shell = _ENV.shell @@ -6,11 +8,15 @@ if not _G.http.websocket then end if not _G.cloud_catcher then - print('Visit https://cloud-catcher.squiddev.cc') - print('Paste key: ') - local key = read() - if #key == 0 then - return + local key = Config.load('cloud').key + + if not key then + print('Visit https://cloud-catcher.squiddev.cc') + print('Paste key: ') + key = read() + if #key == 0 then + return + end end print('Connecting...') shell.run('cloud ' .. key) diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua new file mode 100644 index 0000000..5feeb6d --- /dev/null +++ b/sys/apps/system/cloud.lua @@ -0,0 +1,53 @@ +local Ansi = require('ansi') +local Config = require('config') +local UI = require('ui') + +local colors = _G.colors + +local config = Config.load('cloud') + +local tab = UI.Tab { + tabTitle = 'Cloud', + description = 'Cloud catcher options', + key = UI.TextEntry { + x = 3, ex = -3, y = 2, + limit = 32, + value = config.key, + shadowText = 'Cloud key', + accelerators = { + enter = 'update_key', + }, + }, + button = UI.Button { + x = 3, y = 4, + text = 'Update', + event = 'update_key', + }, + labelText = UI.TextArea { + x = 2, ex = -2, y = 6, + textColor = colors.yellow, + marginRight = 0, + value = string.format( +[[Use a non-changing cloud key. Note that only a single computer can use this session at one time. +To obtain a key, visit: +%shttps://cloud-catcher.squiddev.cc%s then bookmark: +%shttps://cloud-catcher.squiddev.cc/?id=%sKEY + ]], + Ansi.orange, Ansi.reset, Ansi.orange, Ansi.black), + }, +} + +function tab:eventHandler(event) + if event.type == 'update_key' then + if #self.key.value > 0 then + config.key = self.key.value + else + config.key = nil + end + Config.update('cloud', config) + self:emit({ type = 'success_message', message = 'Updated' }) + end +end + +return tab + From 235e8d11de7f1a65c59c7b83b04e08bd87f3ab91 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 23 Mar 2019 12:20:48 -0400 Subject: [PATCH 107/231] cleanup --- sys/apps/Overview.lua | 4 +- sys/apps/system/cloud.lua | 86 +++++++++++++++++++------------------ sys/autorun/upgraded.lua | 2 +- sys/etc/{app.db => apps.db} | 0 4 files changed, 48 insertions(+), 44 deletions(-) rename sys/etc/{app.db => apps.db} (100%) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 952137d..58c65b8 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -11,6 +11,7 @@ local UI = require('ui') local Util = require('util') local colors = _G.colors +local device = _G.device local fs = _G.fs local os = _G.os local pocket = _G.pocket @@ -168,9 +169,10 @@ local function loadApplications() pocket = not not pocket, advancedPocket = pocket and term.isColor(), advancedComputer = not turtle and not pocket and term.isColor(), + neuralInterface = not not device.neuralInterface, } - applications = Util.readTable('sys/etc/app.db') + applications = Util.readTable('sys/etc/apps.db') for dir in pairs(Packages:installed()) do local path = fs.combine('packages/' .. dir, 'etc/apps.db') diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua index 5feeb6d..fce0536 100644 --- a/sys/apps/system/cloud.lua +++ b/sys/apps/system/cloud.lua @@ -4,50 +4,52 @@ local UI = require('ui') local colors = _G.colors -local config = Config.load('cloud') +if _G.http.websocket then + local config = Config.load('cloud') -local tab = UI.Tab { - tabTitle = 'Cloud', - description = 'Cloud catcher options', - key = UI.TextEntry { - x = 3, ex = -3, y = 2, - limit = 32, - value = config.key, - shadowText = 'Cloud key', - accelerators = { - enter = 'update_key', - }, - }, - button = UI.Button { - x = 3, y = 4, - text = 'Update', - event = 'update_key', - }, - labelText = UI.TextArea { - x = 2, ex = -2, y = 6, - textColor = colors.yellow, - marginRight = 0, - value = string.format( -[[Use a non-changing cloud key. Note that only a single computer can use this session at one time. -To obtain a key, visit: -%shttps://cloud-catcher.squiddev.cc%s then bookmark: -%shttps://cloud-catcher.squiddev.cc/?id=%sKEY - ]], - Ansi.orange, Ansi.reset, Ansi.orange, Ansi.black), - }, -} + local tab = UI.Tab { + tabTitle = 'Cloud', + description = 'Cloud catcher options', + key = UI.TextEntry { + x = 3, ex = -3, y = 2, + limit = 32, + value = config.key, + shadowText = 'Cloud key', + accelerators = { + enter = 'update_key', + }, + }, + button = UI.Button { + x = 3, y = 4, + text = 'Update', + event = 'update_key', + }, + labelText = UI.TextArea { + x = 2, ex = -2, y = 6, + textColor = colors.yellow, + marginRight = 0, + value = string.format( + [[Use a non-changing cloud key. Note that only a single computer can use this session at one time. + To obtain a key, visit: + %shttps://cloud-catcher.squiddev.cc%s then bookmark: + %shttps://cloud-catcher.squiddev.cc/?id=%sKEY + ]], + Ansi.white, Ansi.reset, Ansi.white, Ansi.white), + }, + } -function tab:eventHandler(event) - if event.type == 'update_key' then - if #self.key.value > 0 then - config.key = self.key.value - else - config.key = nil + function tab:eventHandler(event) + if event.type == 'update_key' then + if #self.key.value > 0 then + config.key = self.key.value + else + config.key = nil + end + Config.update('cloud', config) + self:emit({ type = 'success_message', message = 'Updated' }) end - Config.update('cloud', config) - self:emit({ type = 'success_message', message = 'Updated' }) - end + end + + return tab end -return tab - diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index 2ce1d9d..c23d1e9 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -1,4 +1,4 @@ if fs.exists('sys/apps/shell') and fs.exists('sys/apps/shell.lua') then fs.delete('sys/apps/shell') end -if fs.exists('sys/autorun/gps.lua') then fs.delete('sys/autorun/gps.lua') end \ No newline at end of file +if fs.exists('sys/etc/app.db') then fs.delete('sys/etc/app.db') end \ No newline at end of file diff --git a/sys/etc/app.db b/sys/etc/apps.db similarity index 100% rename from sys/etc/app.db rename to sys/etc/apps.db From 7bab4e5bf533b777ab53bc3b9e96c99d10bce3ff Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 24 Mar 2019 03:44:38 -0400 Subject: [PATCH 108/231] ui built in theme for ext chars --- sys/apis/ui.lua | 30 +++++++++++++++++++++++++++--- sys/apis/ui/components/Form.lua | 2 +- sys/etc/ext.theme | 28 ---------------------------- 3 files changed, 28 insertions(+), 32 deletions(-) delete mode 100644 sys/etc/ext.theme diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index cafd5aa..11a631a 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -213,7 +213,7 @@ function Manager:loadTheme(filename) if not theme then error(err) end - self.theme = theme + Util.deepMerge(self.theme, theme) end end @@ -1197,10 +1197,34 @@ end loadComponents() UI.theme = { } -UI:loadTheme('usr/config/ui.theme') if Util.getVersion() >= 1.76 then - UI:loadTheme('sys/etc/ext.theme') + UI.theme = { + ScrollBar = { + lineChar = '|', + sliderChar = '\127', + upArrowChar = '\30', + downArrowChar = '\31', + }, + Checkbox = { + checkedIndicator = '\4', + leftMarker = '\124', + rightMarker = '\124', + }, + Chooser = { + leftIndicator = '\17', + rightIndicator = '\16', + }, + Grid = { + focusIndicator = '\183', + inverseSortIndicator = '\24', + }, + TitleBar = { + frameChar = '\140', + closeInd = '\215', + }, + } end +UI:loadTheme('usr/config/ui.theme') UI:setDefaultDevice(UI.Device({ device = term.current() })) diff --git a/sys/apis/ui/components/Form.lua b/sys/apis/ui/components/Form.lua index 6db3085..8ba925e 100644 --- a/sys/apis/ui/components/Form.lua +++ b/sys/apis/ui/components/Form.lua @@ -72,7 +72,7 @@ function UI.Form:createForm() value = child.formLabel, }) end - if child.formKey or child.formLabel then + if child.formLabel then y = y + 1 end end diff --git a/sys/etc/ext.theme b/sys/etc/ext.theme deleted file mode 100644 index 492529e..0000000 --- a/sys/etc/ext.theme +++ /dev/null @@ -1,28 +0,0 @@ -{ - ScrollBar = { - lineChar = '|', - sliderChar = '\127', - upArrowChar = '\30', - downArrowChar = '\31', - }, - Button = { - --focusIndicator = '\183', - }, - Checkbox = { - checkedIndicator = '\4', - leftMarker = '\124', - rightMarker = '\124', - }, - Chooser = { - leftIndicator = '\17', - rightIndicator = '\16', - }, - Grid = { - focusIndicator = '\183', - inverseSortIndicator = '\24', - }, - TitleBar = { - frameChar = '\140', - closeInd = '\215', - }, -} From 8c5044762522ccdce91c942a8294655573c5f499 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 24 Mar 2019 16:05:38 -0400 Subject: [PATCH 109/231] input: dont generate control-char combos --- sys/apis/input.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/apis/input.lua b/sys/apis/input.lua index d03036d..65db6e9 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -89,9 +89,11 @@ function input:translate(event, code, p1, p2) end elseif event == 'char' then - if not self:modifierPressed() then + if not self.pressed[keys.leftAlt] and + not self.pressed[keys.rightAlt] then self.fired = true - return { code = event, ch = input:toCode(code) } + return { code = event, ch = code } +-- return { code = event, ch = input:toCode(code) } end elseif event == 'key_up' then From 398953af545e8d02d55ad4cf2d1e2424fc86d165 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 24 Mar 2019 16:29:49 -0400 Subject: [PATCH 110/231] input: dont generate control-char combos --- sys/apis/input.lua | 4 ++-- sys/extensions/1.device.lua | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/sys/apis/input.lua b/sys/apis/input.lua index 65db6e9..75ee1de 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -89,8 +89,8 @@ function input:translate(event, code, p1, p2) end elseif event == 'char' then - if not self.pressed[keys.leftAlt] and - not self.pressed[keys.rightAlt] then + if not keyboard.state[keys.leftAlt] and + not keyboard.state[keys.rightAlt] then self.fired = true return { code = event, ch = code } -- return { code = event, ch = input:toCode(code) } diff --git a/sys/extensions/1.device.lua b/sys/extensions/1.device.lua index f8bc7a9..9196c42 100644 --- a/sys/extensions/1.device.lua +++ b/sys/extensions/1.device.lua @@ -30,6 +30,7 @@ local Util = require('util') local device = _G.device local kernel = _G.kernel local keyboard = _G.device.keyboard +local keys = _G.keys local mouse = _G.device.mouse local os = _G.os @@ -71,17 +72,25 @@ kernel.hook('peripheral_detach', function(_, eventData) end end) +local modifiers = Util.transpose { + keys.leftCtrl, keys.rightCtrl, + keys.leftShift, keys.rightShift, + keys.leftAlt, keys.rightAlt, +} + kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData) local code = eventData[1] -- maintain global keyboard state - if event == 'key' then - keyboard.state[code] = true - elseif event == 'key_up' then - if not keyboard.state[code] then - return true -- ensure key ups are only generated if a key down was sent - end + if modifiers[code] then + if event == 'key' then + keyboard.state[code] = true + elseif event == 'key_up' then +-- if not keyboard.state[code] then +-- return true -- ensure key ups are only generated if a key down was sent +-- end keyboard.state[code] = nil + end end -- and fire hotkeys @@ -107,8 +116,8 @@ kernel.hook({ 'mouse_click', 'mouse_up', 'mouse_drag' }, function(event, eventDa end) kernel.hook('kernel_focus', function() - Util.clear(keyboard.state) - Util.clear(mouse.state) + --Util.clear(keyboard.state) + --Util.clear(mouse.state) end) function keyboard.addHotkey(code, fn) From 3f9c219f6bb6ab5718599d26f0ed2d336bf633e0 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 24 Mar 2019 17:00:42 -0400 Subject: [PATCH 111/231] keyboard handling --- sys/apis/input.lua | 10 +++++----- sys/extensions/1.device.lua | 10 ++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/sys/apis/input.lua b/sys/apis/input.lua index 75ee1de..a47213a 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -39,11 +39,11 @@ function input:toCode(ch, code) -- the key-up event for alt keys is not generated if the minecraft -- window loses focus - -- - -- if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or - -- code == keys.leftAlt or code == keys.rightAlt then - -- table.insert(result, 'alt') - -- end + + if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or + code == keys.leftAlt or code == keys.rightAlt then + table.insert(result, 'alt') + end if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or code == keys.leftShift or code == keys.rightShift then diff --git a/sys/extensions/1.device.lua b/sys/extensions/1.device.lua index 9196c42..2dbdb91 100644 --- a/sys/extensions/1.device.lua +++ b/sys/extensions/1.device.lua @@ -75,21 +75,18 @@ end) local modifiers = Util.transpose { keys.leftCtrl, keys.rightCtrl, keys.leftShift, keys.rightShift, - keys.leftAlt, keys.rightAlt, + --keys.leftAlt, keys.rightAlt, } kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData) local code = eventData[1] - -- maintain global keyboard state + -- maintain global keyboard modifier state if modifiers[code] then if event == 'key' then keyboard.state[code] = true elseif event == 'key_up' then --- if not keyboard.state[code] then --- return true -- ensure key ups are only generated if a key down was sent --- end - keyboard.state[code] = nil + keyboard.state[code] = nil end end @@ -98,6 +95,7 @@ kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData) if hotkey and keyboard.hotkeys[hotkey.code] then keyboard.hotkeys[hotkey.code](event, eventData) + return true end end) From daa86d50b26f0c440cd53b25e914293bdbe53cb4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 26 Mar 2019 00:31:25 -0400 Subject: [PATCH 112/231] package manager update + UI built-in extended char detection --- sys/apis/packages.lua | 22 ++++++++++------- sys/apis/ui.lua | 32 ++----------------------- sys/apis/ui/components/Checkbox.lua | 6 ++--- sys/apis/ui/components/Chooser.lua | 4 ++-- sys/apis/ui/components/Grid.lua | 4 ++-- sys/apis/ui/components/Notification.lua | 27 ++++++++++++++++----- sys/apis/ui/components/ScrollBar.lua | 6 ++--- sys/apis/ui/components/TitleBar.lua | 4 ++-- sys/apps/Files.lua | 3 ++- sys/apps/PackageManager.lua | 18 +++++--------- sys/apps/package.lua | 2 +- 11 files changed, 57 insertions(+), 71 deletions(-) diff --git a/sys/apis/packages.lua b/sys/apis/packages.lua index ffbc803..6148e28 100644 --- a/sys/apis/packages.lua +++ b/sys/apis/packages.lua @@ -39,15 +39,7 @@ function Packages:downloadList() end end -function Packages:getManifest(package) - local fname = 'packages/' .. package .. '/.package' - if fs.exists(fname) then - local c = Util.readTable(fname) - if c then - c.repository = c.repository:gsub('{{OPUS_BRANCH}}', _G.OPUS_BRANCH) - return c - end - end +function Packages:downloadManifest(package) local list = self:list() local url = list and list[package] @@ -63,4 +55,16 @@ function Packages:getManifest(package) end end +function Packages:getManifest(package) + local fname = 'packages/' .. package .. '/.package' + if fs.exists(fname) then + local c = Util.readTable(fname) + if c and c.repository then + c.repository = c.repository:gsub('{{OPUS_BRANCH}}', _G.OPUS_BRANCH) + return c + end + end + return self:downloadManifest(package) +end + return Packages diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 11a631a..2646a34 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -35,6 +35,8 @@ end local Manager = class() function Manager:init() self.devices = { } + self.theme = { } + self.extChars = Util.getVersion() >= 1.76 local function keyFunction(event, code, held) local ie = Input:translate(event, code, held) @@ -1195,37 +1197,7 @@ local function loadComponents() end loadComponents() - -UI.theme = { } -if Util.getVersion() >= 1.76 then - UI.theme = { - ScrollBar = { - lineChar = '|', - sliderChar = '\127', - upArrowChar = '\30', - downArrowChar = '\31', - }, - Checkbox = { - checkedIndicator = '\4', - leftMarker = '\124', - rightMarker = '\124', - }, - Chooser = { - leftIndicator = '\17', - rightIndicator = '\16', - }, - Grid = { - focusIndicator = '\183', - inverseSortIndicator = '\24', - }, - TitleBar = { - frameChar = '\140', - closeInd = '\215', - }, - } -end UI:loadTheme('usr/config/ui.theme') - UI:setDefaultDevice(UI.Device({ device = term.current() })) return UI diff --git a/sys/apis/ui/components/Checkbox.lua b/sys/apis/ui/components/Checkbox.lua index 9f0b272..6356ebf 100644 --- a/sys/apis/ui/components/Checkbox.lua +++ b/sys/apis/ui/components/Checkbox.lua @@ -7,9 +7,9 @@ UI.Checkbox = class(UI.Window) UI.Checkbox.defaults = { UIElement = 'Checkbox', nochoice = 'Select', - checkedIndicator = 'X', - leftMarker = '[', - rightMarker = ']', + checkedIndicator = UI.extChars and '\4' or 'X', + leftMarker = UI.extChars and '\124' or '[', + rightMarker = UI.extChars and '\124' or ']', value = false, textColor = colors.white, backgroundColor = colors.black, diff --git a/sys/apis/ui/components/Chooser.lua b/sys/apis/ui/components/Chooser.lua index f6e632d..0284fbf 100644 --- a/sys/apis/ui/components/Chooser.lua +++ b/sys/apis/ui/components/Chooser.lua @@ -11,8 +11,8 @@ UI.Chooser.defaults = { nochoice = 'Select', backgroundFocusColor = colors.lightGray, textInactiveColor = colors.gray, - leftIndicator = '<', - rightIndicator = '>', + leftIndicator = UI.extChars and '\17' or '<', + rightIndicator = UI.extChars and '\16' or '>', height = 1, } function UI.Chooser:setParent() diff --git a/sys/apis/ui/components/Grid.lua b/sys/apis/ui/components/Grid.lua index 331d4ae..262faee 100644 --- a/sys/apis/ui/components/Grid.lua +++ b/sys/apis/ui/components/Grid.lua @@ -65,9 +65,9 @@ UI.Grid.defaults = { headerSortColor = colors.yellow, unfocusedTextSelectedColor = colors.white, unfocusedBackgroundSelectedColor = colors.gray, - focusIndicator = '>', + focusIndicator = UI.extChars and '\183' or '>', sortIndicator = ' ', - inverseSortIndicator = '^', + inverseSortIndicator = UI.extChars and '\24' or '^', values = { }, columns = { }, accelerators = { diff --git a/sys/apis/ui/components/Notification.lua b/sys/apis/ui/components/Notification.lua index 901a68c..ada09cb 100644 --- a/sys/apis/ui/components/Notification.lua +++ b/sys/apis/ui/components/Notification.lua @@ -10,7 +10,9 @@ UI.Notification = class(UI.Window) UI.Notification.defaults = { UIElement = 'Notification', backgroundColor = colors.gray, + closeInd = '\215', height = 3, + timeout = 3, } function UI.Notification:draw() end @@ -49,8 +51,8 @@ end function UI.Notification:display(value, timeout) self.enabled = true - local lines = Util.wordWrap(value, self.width - 2) - self.height = #lines + 1 + local lines = Util.wordWrap(value, self.width - 3) + self.height = #lines self.y = self.parent.height - self.height + 1 if self.canvas then self.canvas:removeLayer() @@ -63,9 +65,22 @@ function UI.Notification:display(value, timeout) for k,v in pairs(lines) do self:write(2, k, v) end + self:write(self.width, 1, self.closeInd) - self.timer = Event.onTimeout(timeout or 3, function() - self:cancel() - self:sync() - end) + timeout = timeout or self.timeout + if timeout > 0 then + self.timer = Event.onTimeout(timeout or self.timeout, function() + self:cancel() + self:sync() + end) + end +end + +function UI.Notification:eventHandler(event) + if event.type == 'mouse_click' then + if event.x == self.width then + self:cancel() + return true + end + end end diff --git a/sys/apis/ui/components/ScrollBar.lua b/sys/apis/ui/components/ScrollBar.lua index 8be6de9..2299502 100644 --- a/sys/apis/ui/components/ScrollBar.lua +++ b/sys/apis/ui/components/ScrollBar.lua @@ -8,9 +8,9 @@ UI.ScrollBar = class(UI.Window) UI.ScrollBar.defaults = { UIElement = 'ScrollBar', lineChar = '|', - sliderChar = '#', - upArrowChar = '^', - downArrowChar = 'v', + sliderChar = UI.extChars and '\127' or '#', + upArrowChar = UI.extChars and '\30' or '^', + downArrowChar = UI.extChars and '\31' or 'v', scrollbarColor = colors.lightGray, width = 1, x = -1, diff --git a/sys/apis/ui/components/TitleBar.lua b/sys/apis/ui/components/TitleBar.lua index 0a464ab..872d78b 100644 --- a/sys/apis/ui/components/TitleBar.lua +++ b/sys/apis/ui/components/TitleBar.lua @@ -41,8 +41,8 @@ UI.TitleBar.defaults = { textColor = colors.white, backgroundColor = colors.cyan, title = '', - frameChar = '-', - closeInd = '*', + frameChar = UI.extChars and '\140' or '-', + closeInd = UI.extChars and '\215' or '*', } function UI.TitleBar:draw() local sb = SB(self.width) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 2e065ba..9b14146 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -83,6 +83,7 @@ local Browser = UI.Page { { key = 'totalSize', width = 6 }, }, }, + notification = UI.Notification { }, associations = UI.SlideOut { backgroundColor = colors.cyan, menuBar = UI.MenuBar { @@ -215,7 +216,7 @@ function Browser.statusBar:draw() end function Browser:setStatus(status, ...) - self.statusBar:timedStatus(string.format(status, ...)) + self.notification:info(string.format(status, ...)) end function Browser:unmarkAll() diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index cdd1641..6ed2d41 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -37,12 +37,6 @@ local page = UI.Page { x = 16, y = 3, ey = -5, marginRight = 0, marginLeft = 0, }, - load = UI.Button { - x = 22, y = -3, - text = 'Update packages', - event = 'reload', - help = 'Download the latest package list', - }, action = UI.SlideOut { backgroundColor = colors.cyan, titleBar = UI.TitleBar { @@ -144,10 +138,6 @@ function page:eventHandler(event) self.description:draw() self:updateSelection(event.selected) - elseif event.type == 'reload' then - Packages:downloadList() - self:loadPackages() - elseif event.type == 'action' then local selected = self.grid:getSelected() if selected then @@ -178,7 +168,11 @@ function page:eventHandler(event) UI.Page.eventHandler(self, event) end -page:loadPackages() - UI:setPage(page) +page.statusBar:setStatus('Downloading...') +page:sync() +Packages:downloadList() +page:loadPackages() +page:sync() + UI:pullEvents() diff --git a/sys/apps/package.lua b/sys/apps/package.lua index f604e3c..d1e2071 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -36,7 +36,7 @@ local function progress(max) end local function install(name, isUpdate) - local manifest = Packages:getManifest(name) or error('Invalid package') + local manifest = Packages:downloadManifest(name) or error('Invalid package') if manifest.required then for _, v in pairs(manifest.required) do From ade354660faefb78ffa0ec89c97953a8ae0e7197 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 26 Mar 2019 02:10:10 -0400 Subject: [PATCH 113/231] notifications anchor option --- sys/apis/ui.lua | 5 ++++- sys/apis/ui/components/Notification.lua | 24 +++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 2646a34..5a3b257 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -374,8 +374,11 @@ function Manager:mergeProperties(obj, args) end function Manager:pullEvents(...) - Event.pullEvents(...) + local s, m = pcall(Event.pullEvents, ...) self.term:reset() + if not s and m then + error(m, -1) + end end function Manager:exitPullEvents() diff --git a/sys/apis/ui/components/Notification.lua b/sys/apis/ui/components/Notification.lua index ada09cb..19d0e86 100644 --- a/sys/apis/ui/components/Notification.lua +++ b/sys/apis/ui/components/Notification.lua @@ -13,6 +13,7 @@ UI.Notification.defaults = { closeInd = '\215', height = 3, timeout = 3, + anchor = 'bottom', } function UI.Notification:draw() end @@ -27,7 +28,7 @@ function UI.Notification:error(value, timeout) end function UI.Notification:info(value, timeout) - self.backgroundColor = colors.gray + self.backgroundColor = colors.lightGray self:display(value, timeout) end @@ -50,29 +51,34 @@ function UI.Notification:cancel() end function UI.Notification:display(value, timeout) + self:cancel() self.enabled = true local lines = Util.wordWrap(value, self.width - 3) self.height = #lines - self.y = self.parent.height - self.height + 1 - if self.canvas then - self.canvas:removeLayer() - end - self.canvas = self:addLayer(self.backgroundColor, self.textColor) - self:addTransition('expandUp', { ticks = self.height }) + if self.anchor == 'bottom' then + self.y = self.parent.height - self.height + 1 + self.canvas = self:addLayer(self.backgroundColor, self.textColor) + self:addTransition('expandUp', { ticks = self.height }) + else + self.canvas = self:addLayer(self.backgroundColor, self.textColor) + self.y = 1 + end self.canvas:setVisible(true) self:clear() for k,v in pairs(lines) do self:write(2, k, v) end - self:write(self.width, 1, self.closeInd) timeout = timeout or self.timeout if timeout > 0 then - self.timer = Event.onTimeout(timeout or self.timeout, function() + self.timer = Event.onTimeout(timeout, function() self:cancel() self:sync() end) + else + self:write(self.width, 1, self.closeInd) + self:sync() end end From 82f6d3451df57584e3727739c6eb24c021d10ccb Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 26 Mar 2019 09:08:39 -0400 Subject: [PATCH 114/231] pastebin as an api --- sys/apis/pastebin.lua | 146 ++++++++++++++++++++++++ sys/apis/ui/components/Notification.lua | 2 +- sys/apps/Files.lua | 31 +++-- sys/apps/pastebin.lua | 75 ++++++++++++ sys/apps/system/cloud.lua | 2 + sys/autorun/apps.lua | 3 + 6 files changed, 249 insertions(+), 10 deletions(-) create mode 100644 sys/apis/pastebin.lua create mode 100644 sys/apps/pastebin.lua diff --git a/sys/apis/pastebin.lua b/sys/apis/pastebin.lua new file mode 100644 index 0000000..d78c10c --- /dev/null +++ b/sys/apis/pastebin.lua @@ -0,0 +1,146 @@ + +--- Attempts to guess the pastebin ID from the given code or URL +local function extractId(paste) + local patterns = { + "^([%a%d]+)$", + "^https?://pastebin.com/([%a%d]+)$", + "^pastebin.com/([%a%d]+)$", + "^https?://pastebin.com/raw/([%a%d]+)$", + "^pastebin.com/raw/([%a%d]+)$", + } + + for i = 1, #patterns do + local code = paste:match( patterns[i] ) + if code then return code end + end + + return nil +end + +function download(url) + if not http then + return false, "Pastebin requires http API" + end + + if type( url ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( url ) .. ")", 2 ) + end + + local paste = extractId( url ) + if not paste then + return false, "Invalid pastebin code." + end + + -- Add a cache buster so that spam protection is re-checked + local cacheBuster = ("%x"):format(math.random(0, 2^30)) + local response, err = http.get( + "https://pastebin.com/raw/"..textutils.urlEncode( paste ).."?cb="..cacheBuster + ) + + if response then + -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html + local headers = response.getResponseHeaders() + if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then + return false, "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) + end + + local sResponse = response.readAll() + response.close() + return true, sResponse + end + + return false, err +end + +function put(sPath) + if not http then + return false, "Pastebin requires http API" + end + + if type( sPath ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) + end + + -- Upload a file to pastebin.com + -- Determine file to upload + if not fs.exists( sPath ) or fs.isDir( sPath ) then + return false, "No such file" + end + + -- Read in the file + local sName = fs.getName( sPath ) + local file = fs.open( sPath, "r" ) + local sText = file.readAll() + file.close() + + -- POST the contents to pastebin + local key = "0ec2eb25b6166c0c27a394ae118ad829" + local response = http.post( + "https://pastebin.com/api/api_post.php", + "api_option=paste&".. + "api_dev_key="..key.."&".. + "api_paste_format=lua&".. + "api_paste_name="..textutils.urlEncode(sName).."&".. + "api_paste_code="..textutils.urlEncode(sText) + ) + + if response then + local sResponse = response.readAll() + response.close() + + local sCode = string.match( sResponse, "[^/]+$" ) + + return true, sCode + end + return false, "Failed." +end + +function get(sCode, sPath) + if not http then + return false, "Pastebin requires http API" + end + + if type( sCode ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) + end + + if type( sPath ) ~= "string" then + error( "bad argument #2 (expected string, got " .. type( sPath ) .. ")", 2 ) + end + + if fs.exists( sPath ) then + return false, "File already exists" + end + + -- GET the contents from pastebin + local res, msg = download(sCode) + if not res then + return res, msg + end + + local file = fs.open( sPath, "w" ) + file.write( msg ) + file.close() + + return true +end + +function run(sCode, ...) + if not http then + return false, "Pastebin requires http API" + end + + if type( sCode ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) + end + + local res, msg = download(sCode) + if not res then + return res, msg + end + local func, err = load(msg, sCode, "t", _ENV) + if not func then + return func, err + end + return pcall(func, ...) +end diff --git a/sys/apis/ui/components/Notification.lua b/sys/apis/ui/components/Notification.lua index 19d0e86..33a5745 100644 --- a/sys/apis/ui/components/Notification.lua +++ b/sys/apis/ui/components/Notification.lua @@ -10,7 +10,7 @@ UI.Notification = class(UI.Window) UI.Notification.defaults = { UIElement = 'Notification', backgroundColor = colors.gray, - closeInd = '\215', + closeInd = UI.extChars and '\215' or '*', height = 3, timeout = 3, anchor = 'bottom', diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 9b14146..3c1dd4f 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -9,6 +9,8 @@ local multishell = _ENV.multishell local os = _G.os local shell = _ENV.shell +local FILE = 1 + UI:configure('Files', ...) local config = Config.load('Files', { @@ -38,12 +40,13 @@ local Browser = UI.Page { buttons = { { text = '^-', event = 'updir' }, { text = 'File', dropdown = { - { text = 'Run', event = 'run' }, - { text = 'Edit e', event = 'edit' }, - { text = 'Cloud edit c', event = 'cedit' }, - { text = 'Shell s', event = 'shell' }, + { text = 'Run', event = 'run', flags = FILE }, + { text = 'Edit e', event = 'edit', flags = FILE }, + { text = 'Cloud edit c', event = 'cedit', flags = FILE }, + { text = 'Pastebin put p', event = 'cedit', flags = FILE }, + { text = 'Shell s', event = 'shell' }, UI.MenuBar.spacer, - { text = 'Quit q', event = 'quit' }, + { text = 'Quit q', event = 'quit' }, } }, { text = 'Edit', dropdown = { { text = 'Cut ^x', event = 'cut' }, @@ -140,6 +143,7 @@ local Browser = UI.Page { c = 'cedit', e = 'edit', s = 'shell', + p = 'pastebin', r = 'refresh', space = 'mark', backspace = 'updir', @@ -162,10 +166,8 @@ end function Browser.menuBar:getActive(menuItem) local file = Browser.grid:getSelected() - if file then - if menuItem.event == 'edit' or menuItem.event == 'run' then - return not file.isDir - end + if menuItem.flags == FILE then + return file and not file.isDir end return true end @@ -346,6 +348,7 @@ function Browser:eventHandler(event) elseif event.type == 'cedit' and file then self:run('cedit', file.name) + self:setStatus('Started cloud edit') elseif event.type == 'shell' then self:run('sys/apps/shell.lua') @@ -358,6 +361,16 @@ function Browser:eventHandler(event) elseif event.type == 'associate' then self.associations:show() + elseif event.type == 'pastebin' then + if file and not file.isDir then + local s, m = pastebin.put(file.fullName) + if s then + self.notification:success(string.format('Uploaded as %s', m), 0) + else + self.notification:error(m) + end + end + elseif event.type == 'toggle_hidden' then config.showHidden = not config.showHidden Config.update('Files', config) diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua new file mode 100644 index 0000000..66057ca --- /dev/null +++ b/sys/apps/pastebin.lua @@ -0,0 +1,75 @@ + +local function printUsage() + print( "Usages:" ) + print( "pastebin put " ) + print( "pastebin get " ) + print( "pastebin run " ) +end + +local tArgs = { ... } +if #tArgs < 2 then + printUsage() + return +end + +if not http then + printError( "Pastebin requires http API" ) + printError( "Set http_enable to true in ComputerCraft.cfg" ) + return +end + +local sCommand = tArgs[1] +if sCommand == "put" then + -- Upload a file to pastebin.com + -- Determine file to upload + local sFile = tArgs[2] + local sPath = shell.resolve( sFile ) + if not fs.exists( sPath ) or fs.isDir( sPath ) then + print( "No such file" ) + return + end + + local success, msg = pastebin.put(sFile) + + if success then + print( "Uploaded as "..msg ) + print( "Run \"pastebin get "..msg.."\" to download anywhere" ) + + else + print( msg ) + end + +elseif sCommand == "get" then + -- Download a file from pastebin.com + if #tArgs < 3 then + printUsage() + return + end + + -- Determine file to download + local sCode = tArgs[2] + local sFile = tArgs[3] + local sPath = shell.resolve( sFile ) + if fs.exists( sPath ) then + print( "File already exists" ) + return + end + + local success, msg = pastebin.get(sCode, sPath) + + if success then + print( "Downloaded as "..sFile ) + else + print(msg) + end +elseif sCommand == "run" then + local sCode = tArgs[2] + + local success, msg = pastebin.run(sCode, table.unpack(tArgs, 3)) + if not success then + print(msg) + end +else + printUsage() + return +end diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua index fce0536..d766f4d 100644 --- a/sys/apps/system/cloud.lua +++ b/sys/apps/system/cloud.lua @@ -4,6 +4,8 @@ local UI = require('ui') local colors = _G.colors +-- -t80x30 + if _G.http.websocket then local config = Config.load('cloud') diff --git a/sys/autorun/apps.lua b/sys/autorun/apps.lua index c66656b..97bec3e 100644 --- a/sys/autorun/apps.lua +++ b/sys/autorun/apps.lua @@ -2,3 +2,6 @@ fs.mount('sys/apps/pain.lua', 'urlfs', 'http://pastebin.com/raw/wJQ7jav0') fs.mount('sys/apps/update.lua', 'urlfs', 'http://pastebin.com/raw/UzGHLbNC') fs.mount('sys/apps/Enchat.lua', 'urlfs', 'https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua') fs.mount('sys/apps/cloud.lua', 'urlfs', 'https://cloud-catcher.squiddev.cc/cloud.lua') + +-- baking this in before a PR to cc:tweaked +os.loadAPI('sys/apis/pastebin.lua') \ No newline at end of file From 8fede6f507ec5a1775dbb655625e3a60a7387c26 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 27 Mar 2019 15:21:31 -0400 Subject: [PATCH 115/231] run autorun programs in shell mode --- sys/apps/autorun.lua | 70 ++++++++++++++++++++++++++++++ sys/autorun/clipboard.lua | 2 - sys/autorun/hotkeys.lua | 4 ++ sys/autorun/log.lua | 31 ++++++++------ sys/autorun/welcome.lua | 2 +- sys/extensions/1.device.lua | 5 --- sys/extensions/7.multishell.lua | 76 ++------------------------------- sys/kernel.lua | 33 ++++++++++++-- 8 files changed, 127 insertions(+), 96 deletions(-) create mode 100644 sys/apps/autorun.lua diff --git a/sys/apps/autorun.lua b/sys/apps/autorun.lua new file mode 100644 index 0000000..e7febc1 --- /dev/null +++ b/sys/apps/autorun.lua @@ -0,0 +1,70 @@ +local Packages = require('packages') + +local colors = _G.colors +local fs = _G.fs +local keys = _G.keys +local multishell = _ENV.multishell +local os = _G.os +local shell = _ENV.shell +local term = _G.term + +local success = true + +local function runDir(directory) + if not fs.exists(directory) then + return true + end + + local files = fs.list(directory) + table.sort(files) + + for _,file in ipairs(files) do + os.sleep(0) + local result, err = shell.run(directory .. '/' .. file) + + if result then + if term.isColor() then + term.setTextColor(colors.green) + end + term.write('[PASS] ') + term.setTextColor(colors.white) + term.write(fs.combine(directory, file)) + print() + else + if term.isColor() then + term.setTextColor(colors.red) + end + term.write('[FAIL] ') + term.setTextColor(colors.white) + term.write(fs.combine(directory, file)) + if err then + _G.printError('\n' .. err) + end + print() + success = false + end + end +end + +runDir('sys/autorun') +for name in pairs(Packages:installed()) do + local packageDir = 'packages/' .. name .. '/autorun' + runDir(packageDir) +end +runDir('usr/autorun') + +if not success then + if multishell then + --multishell.setFocus(multishell.getCurrent()) + end + _G.printError('A startup program has errored') + print('Press enter to continue') + + while true do + local e, code = os.pullEventRaw('key') + if e == 'terminate' or e == 'key' and code == keys.enter then + break + end + end +end + diff --git a/sys/autorun/clipboard.lua b/sys/autorun/clipboard.lua index 2dd8017..ad3286f 100644 --- a/sys/autorun/clipboard.lua +++ b/sys/autorun/clipboard.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local Util = require('util') local kernel = _G.kernel diff --git a/sys/autorun/hotkeys.lua b/sys/autorun/hotkeys.lua index 3c97e0e..cf50efb 100644 --- a/sys/autorun/hotkeys.lua +++ b/sys/autorun/hotkeys.lua @@ -4,6 +4,10 @@ local kernel = _G.kernel local keyboard = _G.device.keyboard local multishell = _ENV.multishell +if not multishell or not multishell.getTabs then + return +end + -- overview keyboard.addHotkey('control-o', function() for _,tab in pairs(multishell.getTabs()) do diff --git a/sys/autorun/log.lua b/sys/autorun/log.lua index fe8de05..4f53ed4 100644 --- a/sys/autorun/log.lua +++ b/sys/autorun/log.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - --[[ Adds a task and the control-d hotkey to view the kernel log. --]] @@ -13,12 +11,14 @@ local term = _G.term local function systemLog() local routine = kernel.getCurrent() - local w, h = kernel.window.getSize() - kernel.window.reposition(1, 2, w, h - 1) + if multishell and multishell.openTab then + local w, h = kernel.window.getSize() + kernel.window.reposition(1, 2, w, h - 1) - routine.terminal = kernel.window - routine.window = kernel.window - term.redirect(kernel.window) + routine.terminal = kernel.window + routine.window = kernel.window + term.redirect(kernel.window) + end kernel.hook('mouse_scroll', function(_, eventData) local dir, y = eventData[1], eventData[3] @@ -50,8 +50,15 @@ local function systemLog() keyboard.removeHotkey('control-d') end -multishell.openTab({ - title = 'System Log', - fn = systemLog, - hidden = true, -}) +if multishell and multishell.openTab then + multishell.openTab({ + title = 'System Log', + fn = systemLog, + hidden = true, + }) +else + kernel.run({ + title = 'Syslog', + fn = systemLog, + }) +end diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua index c94e177..df0b2fd 100644 --- a/sys/autorun/welcome.lua +++ b/sys/autorun/welcome.lua @@ -3,7 +3,7 @@ local Config = require('config') local shell = _ENV.shell local config = Config.load('os') -if not config.welcomed then +if not config.welcomed and shell.openForegroundTab then config.welcomed = true Config.update('os', config) diff --git a/sys/extensions/1.device.lua b/sys/extensions/1.device.lua index 2dbdb91..5c57761 100644 --- a/sys/extensions/1.device.lua +++ b/sys/extensions/1.device.lua @@ -113,11 +113,6 @@ kernel.hook({ 'mouse_click', 'mouse_up', 'mouse_drag' }, function(event, eventDa end end) -kernel.hook('kernel_focus', function() - --Util.clear(keyboard.state) - --Util.clear(mouse.state) -end) - function keyboard.addHotkey(code, fn) keyboard.hotkeys[code] = fn end diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index 9bbfb2c..974afe4 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -1,7 +1,6 @@ _G.requireInjector(_ENV) local Config = require('config') -local Packages = require('packages') local trace = require('trace') local Util = require('util') @@ -12,7 +11,6 @@ local keys = _G.keys local os = _G.os local printError = _G.printError local shell = _ENV.shell -local term = _G.term local window = _G.window local parentTerm = _G.device.terminal @@ -186,23 +184,7 @@ function multishell.getCount() return #kernel.routines end -kernel.hook('kernel_focus', function(_, eventData) - local previous = eventData[2] - if previous then - local routine = kernel.find(previous) - if routine and routine.window then - routine.window.setVisible(false) - if routine.hidden then - kernel.lower(previous) - end - end - end - - local focused = kernel.find(eventData[1]) - if focused and focused.window then - focused.window.setVisible(true) - end - +kernel.hook('kernel_focus', function() redrawMenu() end) @@ -349,59 +331,6 @@ kernel.hook('mouse_scroll', function(_, eventData) eventData[3] = eventData[3] - 1 end) -local function startup() - local success = true - - local function runDir(directory, open) - if not fs.exists(directory) then - return true - end - - local files = fs.list(directory) - table.sort(files) - - for _,file in ipairs(files) do - os.sleep(0) - local result, err = open(directory .. '/' .. file) - - if result then - if term.isColor() then - term.setTextColor(colors.green) - end - term.write('[PASS] ') - term.setTextColor(colors.white) - term.write(fs.combine(directory, file)) - print() - else - if term.isColor() then - term.setTextColor(colors.red) - end - term.write('[FAIL] ') - term.setTextColor(colors.white) - term.write(fs.combine(directory, file)) - if err then - _G.printError('\n' .. err) - end - print() - success = false - end - end - end - - runDir('sys/autorun', shell.run) - for name in pairs(Packages:installed()) do - local packageDir = 'packages/' .. name .. '/autorun' - runDir(packageDir, shell.run) - end - runDir('usr/autorun', shell.run) - - if not success then - multishell.setFocus(multishell.getCurrent()) - printError('\nA startup program has errored') - os.pullEvent('terminate') - end -end - kernel.hook('kernel_ready', function() overviewId = multishell.openTab({ path = 'sys/apps/Overview.lua', @@ -411,7 +340,8 @@ kernel.hook('kernel_ready', function() }) multishell.openTab({ - fn = startup, + path = 'sys/apps/shell.lua', + args = { 'sys/apps/autorun.lua' }, title = 'Autorun', }) end) diff --git a/sys/kernel.lua b/sys/kernel.lua index b81fd9e..2f53ddf 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -14,6 +14,7 @@ local kernel = _G.kernel local os = _G.os local shell = _ENV.shell local term = _G.term +local window = _G.window local w, h = term.getSize() kernel.terminal = term.current() @@ -69,6 +70,23 @@ end local Routine = { } +local function switch(routine, previous) + if routine then + if previous and previous.window then + previous.window.setVisible(false) + if previous.hidden then + kernel.lower(previous.uid) + end + end + + if routine and routine.window then + routine.window.setVisible(true) + end + + os.queueEvent('kernel_focus', routine.uid, previous and previous.uid) + end +end + function Routine:resume(event, ...) if not self.co or coroutine.status(self.co) == 'dead' then return @@ -97,7 +115,7 @@ function Routine:resume(event, ...) if coroutine.status(self.co) == 'dead' then Util.removeByValue(kernel.routines, self) if #kernel.routines > 0 then - os.queueEvent('kernel_focus', kernel.routines[1].uid) + switch(kernel.routines[1]) end if self.haltOnExit then kernel.halt() @@ -174,7 +192,10 @@ function kernel.raise(uid) Util.removeByValue(kernel.routines, routine) table.insert(kernel.routines, 1, routine) end - os.queueEvent('kernel_focus', routine.uid, previous and previous.uid) + + switch(routine, previous) +-- local previous = eventData[2] +-- local routine = kernel.find(previous) return true end return false @@ -276,13 +297,19 @@ local function init(...) if args[1] then kernel.hook('kernel_ready', function() + + term.redirect(kernel.window) + shell.run('sys/apps/autorun.lua') + + local shellWindow = window.create(kernel.terminal, 1, 1, w, h, false) local s, m = kernel.run({ title = args[1], path = 'sys/apps/shell.lua', args = args, haltOnExit = true, haltOnError = true, - terminal = kernel.terminal, + terminal = shellWindow, + window = shellWindow, }) if s then kernel.raise(s.uid) From b71ca0d545a8b89a17ff7e853e8f831dfc5f0f45 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 28 Mar 2019 07:29:01 -0400 Subject: [PATCH 116/231] autorun overhaul + shell input readline commands + launcher option + shell colors --- sys/apis/entry.lua | 304 +++++++++++++++++++++----------- sys/apis/terminal.lua | 44 ++--- sys/apps/Overview.lua | 2 - sys/apps/shell.lua | 38 ++-- sys/apps/system/cloud.lua | 14 +- sys/apps/system/colors.lua | 136 ++++++++++++++ sys/apps/system/launcher.lua | 81 +++++++++ sys/apps/system/path.lua | 2 +- sys/apps/system/requires.lua | 2 +- sys/etc/apps.db | 2 +- sys/extensions/1.device.lua | 2 +- sys/extensions/4.user.lua | 2 +- sys/extensions/7.multishell.lua | 6 +- 13 files changed, 480 insertions(+), 155 deletions(-) create mode 100644 sys/apps/system/colors.lua create mode 100644 sys/apps/system/launcher.lua diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index fd77af9..7379a09 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -30,6 +30,19 @@ local function nextWord(line, cx) end end +local function prevWord(line, cx) + local nOffset = 1 + while nOffset <= #line do + local nNext = line:find("%W%w", nOffset) + if nNext and nNext < cx then + nOffset = nNext + 1 + else + break + end + end + return nOffset - 1 < cx and nOffset - 1 +end + function Entry:updateScroll() if self.pos - self.scroll > self.width then self.scroll = self.pos - (self.width) @@ -38,109 +51,198 @@ function Entry:updateScroll() end end +local function moveLeft(entry) + if entry.pos > 0 then + entry.pos = math.max(entry.pos - 1, 0) + return true + end +end + +local function moveRight(entry) + local input = tostring(entry.value) + if entry.pos < #input then + entry.pos = math.min(entry.pos + 1, #input) + return true + end +end + +local function moveStart(entry) + if entry.pos ~= 0 then + entry.pos = 0 + return true + end +end + +local function moveEnd(entry) + if entry.pos ~= #tostring(entry.value) then + entry.pos = #tostring(entry.value) + return true + end +end + +local function backspace(entry) + if entry.pos > 0 then + local input = tostring(entry.value) + entry.value = input:sub(1, entry.pos - 1) .. input:sub(entry.pos + 1) + entry.pos = entry.pos - 1 + return true + end +end + +local function moveWordRight(entry) + local nx = nextWord(entry.value, entry.pos + 1) + if nx then + entry.pos = math.min(nx - 1, #entry.value) + elseif entry.pos < #entry.value then + entry.pos = #entry.value + end + return true +end + +local function moveWordLeft(entry) + if entry.pos ~= 0 then + local lx = 1 + while true do + local nx = nextWord(entry.value, lx) + if not nx or nx >= entry.pos then + break + end + lx = nx + end + if not lx then + entry.pos = 0 + else + entry.pos = lx - 1 + end + return true + end +end + +local function delete(entry) + local input = tostring(entry.value) + if entry.pos < #input then + entry.value = input:sub(1, entry.pos) .. input:sub(entry.pos + 2) + entry.update = true + return true + end +end + +-- credit for cut functions to: https://github.com/SquidDev-CC/mbs/blob/master/lib/readline.lua +local function cutFromStart(entry) + if entry.pos > 0 then + local input = tostring(entry.value) + os.queueEvent('clipboard_copy', input:sub(1, entry.pos)) + entry.value = input:sub(entry.pos + 1) + entry.pos = 0 + return true + end +end + +local function cutToEnd(entry) + local input = tostring(entry.value) + if entry.pos < #input then + os.queueEvent('clipboard_copy', input:sub(entry.pos + 1)) + entry.value = input:sub(1, entry.pos) + return true + end +end + +local function cutNextWord(entry) + local input = tostring(entry.value) + if entry.pos < #input then + local ex = nextWord(entry.value, entry.pos) + if ex then + os.queueEvent('clipboard_copy', input:sub(entry.pos + 1, ex)) + entry.value = input:sub(1, entry.pos) .. input:sub(ex + 1) + return true + end + end +end + +local function cutPrevWord(entry) + if entry.pos > 0 then + local sx = prevWord(entry.value, entry.pos) + if sx then + local input = tostring(entry.value) + os.queueEvent('clipboard_copy', input:sub(sx + 1, entry.pos)) + entry.value = input:sub(1, sx) .. input:sub(entry.pos + 1) + entry.pos = sx + return true + end + end +end + +local function insertChar(entry, ie) + local input = tostring(entry.value) + if #input < entry.limit then + entry.value = input:sub(1, entry.pos) .. ie.ch .. input:sub(entry.pos + 1) + entry.pos = entry.pos + 1 + entry.update = true + return true + end +end + +local function copy(entry) + os.queueEvent('clipboard_copy', entry.value) +end + +local function paste(entry, ie) + local input = tostring(entry.value) + if #input + #ie.text > entry.limit then + ie.text = ie.text:sub(1, entry.limit-#input) + end + entry.value = input:sub(1, entry.pos) .. ie.text .. input:sub(entry.pos + 1) + entry.pos = entry.pos + #ie.text + return true +end + +local function moveCursor(entry, ie) + -- need starting x passed in instead of hardcoding 3 + entry.pos = math.max(0, math.min(ie.x - 3 + entry.scroll, #entry.value)) + return true +end + +local function clearLine(entry) + local input = tostring(entry.value) + if #input > 0 then + entry:reset() + return true + end +end + +local mappings = { + [ 'left' ] = moveLeft, + [ 'control-b' ] = moveLeft, + [ 'right' ] = moveRight, + [ 'control-f' ] = moveRight, + [ 'home' ] = moveStart, + [ 'control-a' ] = moveStart, + [ 'end' ] = moveEnd, + [ 'control-e' ] = moveEnd, + [ 'backspace' ] = backspace, + [ 'control-right' ] = moveWordRight, + [ 'alt-f' ] = moveWordRight, + [ 'control-left' ] = moveWordLeft, + [ 'alt-b' ] = moveWordLeft, + [ 'delete' ] = delete, + [ 'control-u' ] = cutFromStart, + [ 'control-k' ] = cutToEnd, + [ 'control-d' ] = cutNextWord, + [ 'control-w' ] = cutPrevWord, + [ 'char' ] = insertChar, + [ 'copy' ] = copy, + [ 'paste' ] = paste, + [ 'control-y' ] = paste, + [ 'mouse_click' ] = moveCursor, + [ 'mouse_rightclick' ] = clearLine, +} + function Entry:process(ie) - local updated = false + local action = mappings[ie.code] + local updated - if ie.code == 'left' then - if self.pos > 0 then - self.pos = math.max(self.pos - 1, 0) - updated = true - end - - elseif ie.code == 'right' then - local input = tostring(self.value) - if self.pos < #input then - self.pos = math.min(self.pos + 1, #input) - updated = true - end - - elseif ie.code == 'home' then - if self.pos ~= 0 then - self.pos = 0 - updated = true - end - - elseif ie.code == 'end' then - if self.pos ~= #tostring(self.value) then - self.pos = #tostring(self.value) - updated = true - end - - elseif ie.code == 'backspace' then - if self.pos > 0 then - local input = tostring(self.value) - self.value = input:sub(1, self.pos - 1) .. input:sub(self.pos + 1) - self.pos = self.pos - 1 - updated = true - end - - elseif ie.code == 'control-right' then - local nx = nextWord(self.value, self.pos + 1) - if nx then - self.pos = math.min(nx - 1, #self.value) - elseif self.pos < #self.value then - self.pos = #self.value - end - updated = true - - elseif ie.code == 'control-left' then - if self.pos ~= 0 then - local lx = 1 - while true do - local nx = nextWord(self.value, lx) - if not nx or nx >= self.pos then - break - end - lx = nx - end - if not lx then - self.pos = 0 - else - self.pos = lx - 1 - end - updated = true - end - - elseif ie.code == 'delete' then - local input = tostring(self.value) - if self.pos < #input then - self.value = input:sub(1, self.pos) .. input:sub(self.pos + 2) - self.update = true - updated = true - end - - elseif ie.code == 'char' then - local input = tostring(self.value) - if #input < self.limit then - self.value = input:sub(1, self.pos) .. ie.ch .. input:sub(self.pos + 1) - self.pos = self.pos + 1 - self.update = true - updated = true - end - - elseif ie.code == 'copy' then - os.queueEvent('clipboard_copy', self.value) - - elseif ie.code == 'paste' then - local input = tostring(self.value) - if #input + #ie.text > self.limit then - ie.text = ie.text:sub(1, self.limit-#input) - end - self.value = input:sub(1, self.pos) .. ie.text .. input:sub(self.pos + 1) - self.pos = self.pos + #ie.text - updated = true - - elseif ie.code == 'mouse_click' then - -- need starting x passed in instead of hardcoding 3 - self.pos = math.max(0, math.min(ie.x - 3 + self.scroll, #self.value)) - updated = true - - elseif ie.code == 'mouse_rightclick' then - local input = tostring(self.value) - if #input > 0 then - self:reset() - updated = true - end + if action then + updated = action(self, ie) end self:updateScroll() diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 950741e..dc10311 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -6,6 +6,25 @@ local _gsub = string.gsub local Terminal = { } +local mapColorToGray = { + [ colors.white ] = colors.white, + [ colors.orange ] = colors.lightGray, + [ colors.magenta ] = colors.lightGray, + [ colors.lightBlue ] = colors.lightGray, + [ colors.yellow ] = colors.lightGray, + [ colors.lime ] = colors.lightGray, + [ colors.pink ] = colors.lightGray, + [ colors.gray ] = colors.gray, + [ colors.lightGray ] = colors.lightGray, + [ colors.cyan ] = colors.lightGray, + [ colors.purple ] = colors.gray, + [ colors.blue ] = colors.gray, + [ colors.brown ] = colors.gray, + [ colors.green ] = colors.lightGray, + [ colors.red ] = colors.gray, + [ colors.black ] = colors.black, +} + -- Replacement for window api with scrolling and buffering function Terminal.window(parent, sx, sy, w, h, isVisible) isVisible = isVisible ~= false @@ -243,32 +262,17 @@ function Terminal.getContents(win, parent) return lines end -function Terminal.toGrayscale(ct) - local scolors = { - [ colors.white ] = colors.white, - [ colors.orange ] = colors.lightGray, - [ colors.magenta ] = colors.lightGray, - [ colors.lightBlue ] = colors.lightGray, - [ colors.yellow ] = colors.lightGray, - [ colors.lime ] = colors.lightGray, - [ colors.pink ] = colors.lightGray, - [ colors.gray ] = colors.gray, - [ colors.lightGray ] = colors.lightGray, - [ colors.cyan ] = colors.lightGray, - [ colors.purple ] = colors.gray, - [ colors.blue ] = colors.gray, - [ colors.brown ] = colors.gray, - [ colors.green ] = colors.lightGray, - [ colors.red ] = colors.gray, - [ colors.black ] = colors.black, - } +function Terminal.colorToGrayscale(c) + return mapColorToGray[c] +end +function Terminal.toGrayscale(ct) local methods = { 'setBackgroundColor', 'setBackgroundColour', 'setTextColor', 'setTextColour' } for _,v in pairs(methods) do local fn = ct[v] ct[v] = function(c) - fn(scolors[c]) + fn(mapColorToGray[c]) end end diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 58c65b8..eba0bfd 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -1,5 +1,3 @@ -_G.requireInjector(_ENV) - local class = require('class') local Config = require('config') local Event = require('event') diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index 8946e0a..05978a7 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -362,6 +362,7 @@ local Config = require('config') local Entry = require('entry') local History = require('history') local Input = require('input') +local Terminal = require('terminal') local colors = _G.colors local os = _G.os @@ -372,22 +373,12 @@ local oldTerm local terminal = term.current() if not terminal.scrollUp then - local Terminal = require('terminal') terminal = Terminal.window(term.current()) terminal.setMaxScroll(200) oldTerm = term.redirect(terminal) end local config = { - standard = { - textColor = colors.white, - commandTextColor = colors.lightGray, - directoryTextColor = colors.gray, - directoryBackgroundColor = colors.black, - promptTextColor = colors.gray, - promptBackgroundColor = colors.black, - directoryColor = colors.gray, - }, color = { textColor = colors.white, commandTextColor = colors.yellow, @@ -396,15 +387,20 @@ local config = { promptTextColor = colors.blue, promptBackgroundColor = colors.black, directoryColor = colors.green, + fileColor = colors.white, + backgroundColor = colors.black, }, displayDirectory = true, } Config.load('shellprompt', config) -local _colors = config.standard -if term.isColor() then - _colors = config.color +local _colors = config.color +if not term.isColor() then + _colors = { } + for k, v in pairs(config.color) do + _colors[k] = Terminal.colorToGrayscale(v) + end end local function autocompleteArgument(program, words) @@ -536,9 +532,9 @@ local function autocomplete(line) end if #tDirs > 0 then - textutils.tabulate(_colors.directoryColor, tDirs, colors.white, tFiles) + textutils.tabulate(_colors.directoryColor, tDirs, _colors.fileColor, tFiles) else - textutils.tabulate(colors.white, tFiles) + textutils.tabulate(_colors.fileColor, tFiles) end term.setTextColour(_colors.promptTextColor) @@ -546,7 +542,7 @@ local function autocomplete(line) term.write("$ " ) term.setTextColour(_colors.commandTextColor) - term.setBackgroundColor(colors.black) + term.setBackgroundColor(_colors.backgroundColor) return line end end @@ -593,8 +589,9 @@ local function shellRead(history) elseif ie.code == 'enter' then break - elseif ie.code == 'up' or ie.code == 'down' then - if ie.code == 'up' then + elseif ie.code == 'up' or ie.code == 'control-p' or + ie.code == 'down' or ie.code == 'control-n' then + if ie.code == 'up' or ie.code == 'control-p' then entry.value = history:back() or '' else entry.value = history:forward() or '' @@ -634,6 +631,9 @@ end local history = History.load('usr/.shell_history', 25) +term.setBackgroundColor(_colors.backgroundColor) +term.clear() + while not bExit do if config.displayDirectory then term.setTextColour(_colors.directoryTextColor) @@ -644,7 +644,7 @@ while not bExit do term.setBackgroundColor(_colors.promptBackgroundColor) term.write("$ " ) term.setTextColour(_colors.commandTextColor) - term.setBackgroundColor(colors.black) + term.setBackgroundColor(_colors.backgroundColor) local sLine = shellRead(history) if bExit then -- terminated break diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua index d766f4d..434a16c 100644 --- a/sys/apps/system/cloud.lua +++ b/sys/apps/system/cloud.lua @@ -27,16 +27,16 @@ if _G.http.websocket then event = 'update_key', }, labelText = UI.TextArea { - x = 2, ex = -2, y = 6, + x = 3, ex = -3, y = 6, textColor = colors.yellow, - marginRight = 0, + marginLeft = 0, marginRight = 0, value = string.format( - [[Use a non-changing cloud key. Note that only a single computer can use this session at one time. - To obtain a key, visit: - %shttps://cloud-catcher.squiddev.cc%s then bookmark: - %shttps://cloud-catcher.squiddev.cc/?id=%sKEY +[[Use a non-changing cloud key. Note that only a single computer can use this session at one time. +To obtain a key, visit: +%shttps://cloud-catcher.squiddev.cc%s then bookmark: +%shttps://cloud-catcher.squiddev.cc/?id=KEY ]], - Ansi.white, Ansi.reset, Ansi.white, Ansi.white), + Ansi.white, Ansi.reset, Ansi.white), }, } diff --git a/sys/apps/system/colors.lua b/sys/apps/system/colors.lua new file mode 100644 index 0000000..3bdefda --- /dev/null +++ b/sys/apps/system/colors.lua @@ -0,0 +1,136 @@ +local Config = require('config') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors +local os = _G.os + +local config = Config.load('shellprompt') + +local allColors = { } +for k,v in pairs(colors) do + if type(v) == 'number' then + table.insert(allColors, { name = k, value = v }) + end +end + +local defaults = { + textColor = colors.white, + commandTextColor = colors.yellow, + directoryTextColor = colors.orange, + directoryBackgroundColor = colors.black, + promptTextColor = colors.blue, + promptBackgroundColor = colors.black, + directoryColor = colors.green, + fileColor = colors.white, + backgroundColor = colors.black, +} +local _colors = config.color or Util.shallowCopy(defaults) + +local allSettings = { } +for k, v in pairs(defaults) do + table.insert(allSettings, { name = k }) +end + +local tab = UI.Tab { + tabTitle = 'Shell', + description = 'Shell option', + grid1 = UI.ScrollingGrid { + y = 2, ey = -10, x = 3, ex = -16, + disableHeader = true, + columns = { { key = 'name' } }, + values = allSettings, + sortColumn = 'name', + }, + grid2 = UI.ScrollingGrid { + y = 2, ey = -10, x = -14, ex = -3, + disableHeader = true, + columns = { { key = 'name' } }, + values = allColors, + sortColumn = 'name', + }, + directoryLabel = UI.Text { + x = 2, y = -2, + value = 'Display directory', + }, + directory = UI.Checkbox { + x = 20, y = -2, + value = config.displayDirectory + }, + reset = UI.Button { + x = -18, y = -2, + text = 'Reset', + event = 'reset', + }, + button = UI.Button { + x = -9, y = -2, + text = 'Update', + event = 'update', + }, + display = UI.Window { + x = 3, ex = -3, y = -8, height = 5, + }, +} + +function tab.grid2:getRowTextColor(row) + local selected = tab.grid1:getSelected() + if _colors[selected.name] == row.value then + return colors.yellow + end + return UI.Grid.getRowTextColor(self, row) +end + +function tab.display:draw() + self:clear(_colors.backgroundColor) + local offset = 0 + if config.displayDirectory then + self:write(1, 1, + '==' .. os.getComputerLabel() .. ':/dir/etc', + _colors.directoryBackgroundColor, _colors.directoryTextColor) + offset = 1 + end + + self:write(1, 1 + offset, '$ ', + _colors.promptBackgroundColor, _colors.promptTextColor) + + self:write(3, 1 + offset, 'ls /', + _colors.backgroundColor, _colors.commandTextColor) + + self:write(1, 2 + offset, 'sys usr', + _colors.backgroundColor, _colors.directoryColor) + + self:write(1, 3 + offset, 'startup', + _colors.backgroundColor, _colors.fileColor) +end + +function tab:eventHandler(event) + if event.type =='checkbox_change' then + config.displayDirectory = not not event.checked + self.display:draw() + + elseif event.type == 'grid_focus_row' and event.element == self.grid1 then + self.grid2:draw() + + elseif event.type == 'grid_select' and event.element == self.grid2 then + _colors[tab.grid1:getSelected().name] = event.selected.value + self.display:draw() + self.grid2:draw() + + elseif event.type == 'reset' then + config.color = defaults + config.displayDirectory = true + self.directory.value = true + _colors = Util.shallowCopy(defaults) + + Config.update('shellprompt', config) + self:draw() + + elseif event.type == 'update' then + config.color = _colors + Config.update('shellprompt', config) + + end + return UI.Tab.eventHandler(self, event) +end + +return tab diff --git a/sys/apps/system/launcher.lua b/sys/apps/system/launcher.lua new file mode 100644 index 0000000..25e5db6 --- /dev/null +++ b/sys/apps/system/launcher.lua @@ -0,0 +1,81 @@ +local Config = require('config') +local UI = require('ui') + +local colors = _G.colors +local fs = _G.fs + +local config = Config.load('multishell') + +local tab = UI.Tab { + tabTitle = 'Launcher', + description = 'Set the application launcher', + launcherLabel = UI.Text { + x = 3, y = 2, + value = 'Launcher', + }, + launcher = UI.Chooser { + x = 13, y = 2, width = 12, + choices = { + { name = 'Overview', value = 'sys/apps/Overview.lua' }, + { name = 'Shell', value = 'sys/apps/shell.lua' }, + { name = 'Custom', value = 'custom' }, + }, + }, + custom = UI.TextEntry { + x = 13, ex = -3, y = 3, + limit = 128, + shadowText = 'File name', + }, + button = UI.Button { + x = 3, y = 5, + text = 'Update', + event = 'update', + }, + labelText = UI.TextArea { + x = 3, ex = -3, y = 7, + textColor = colors.yellow, + value = 'Choose an application launcher', + }, +} + +function tab:enable() + local launcher = config.launcher and 'custom' or 'sys/apps/Overview.lua' + + for _, v in pairs(self.launcher.choices) do + if v.value == config.launcher then + launcher = v.value + break + end + end + + UI.Tab.enable(self) + + self.launcher.value = launcher + self.custom.enabled = launcher == 'custom' +end + +function tab:eventHandler(event) + if event.type == 'choice_change' then + self.custom.enabled = event.value == 'custom' + self:draw() + + elseif event.type == 'update' then + local launcher + + if self.launcher.value ~= 'custom' then + launcher = self.launcher.value + elseif fs.exists(self.custom.value) and not fs.isDir(self.custom.value) then + launcher = self.custom.value + end + + if launcher then + config.launcher = launcher + Config.update('multishell', config) + self:emit({ type = 'success_message', message = 'Updated' }) + else + self:emit({ type = 'error_message', message = 'Invalid file' }) + end + end +end + +return tab diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index 7e3abff..504c7e1 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -20,7 +20,7 @@ local tab = UI.Tab { disableHeader = true, columns = { { key = 'value' } }, autospace = true, - sort = 'index', + sortColumn = 'index', help = 'double-click to remove, shift-arrow to move', accelerators = { delete = 'remove', diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua index dfa7a02..2bd97cf 100644 --- a/sys/apps/system/requires.lua +++ b/sys/apps/system/requires.lua @@ -20,7 +20,7 @@ local tab = UI.Tab { disableHeader = true, columns = { { key = 'value' } }, autospace = true, - sort = 'index', + sortColumn = 'index', help = 'double-click to remove, shift-arrow to move', accelerators = { delete = 'remove', diff --git a/sys/etc/apps.db b/sys/etc/apps.db index edd19bd..d7ea0dd 100644 --- a/sys/etc/apps.db +++ b/sys/etc/apps.db @@ -46,7 +46,7 @@ iconExt = "\031f\128\0313\152\131\131\132\031f\128\ \0313\139\159\129\0303\031f\159\129\139\ \031f\128\0313\136\0303\031f\143\143\030f\0313\134\031f\128", - run = "update", + run = "update update", }, c47ae15370cfe1ed2781eedc1dc2547d12d9e972 = { title = "Help", diff --git a/sys/extensions/1.device.lua b/sys/extensions/1.device.lua index 5c57761..3d25083 100644 --- a/sys/extensions/1.device.lua +++ b/sys/extensions/1.device.lua @@ -75,7 +75,7 @@ end) local modifiers = Util.transpose { keys.leftCtrl, keys.rightCtrl, keys.leftShift, keys.rightShift, - --keys.leftAlt, keys.rightAlt, + keys.leftAlt, keys.rightAlt, } kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData) diff --git a/sys/extensions/4.user.lua b/sys/extensions/4.user.lua index 169155d..e795997 100644 --- a/sys/extensions/4.user.lua +++ b/sys/extensions/4.user.lua @@ -44,6 +44,6 @@ end shell.setPath(table.concat(path, ':')) _G.LUA_PATH = config.lua_path -_G.settings.set('require.path', config.lua_path) +_G.settings.set('mbs.shell.require_path', config.lua_path) fs.loadTab('usr/config/fstab') diff --git a/sys/extensions/7.multishell.lua b/sys/extensions/7.multishell.lua index 974afe4..9d48ce0 100644 --- a/sys/extensions/7.multishell.lua +++ b/sys/extensions/7.multishell.lua @@ -332,11 +332,15 @@ kernel.hook('mouse_scroll', function(_, eventData) end) kernel.hook('kernel_ready', function() + local env = Util.shallowCopy(shell.getEnv()) + _G.requireInjector(env) + overviewId = multishell.openTab({ - path = 'sys/apps/Overview.lua', + path = config.launcher or 'sys/apps/Overview.lua', isOverview = true, focused = true, title = '+', + env = env, }) multishell.openTab({ From 517376db28ac03934a3faa21770f7f9dc571d1fc Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 28 Mar 2019 07:39:34 -0400 Subject: [PATCH 117/231] update issues --- sys/apps/shell.lua | 6 ++++++ sys/apps/system/colors.lua | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index 05978a7..a138fe6 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -396,6 +396,12 @@ local config = { Config.load('shellprompt', config) local _colors = config.color +-- temp +if not _colors.backgroundColor then + _colors.backgroundColor = colors.black + _colors.fileColor = colors.white +end + if not term.isColor() then _colors = { } for k, v in pairs(config.color) do diff --git a/sys/apps/system/colors.lua b/sys/apps/system/colors.lua index 3bdefda..cce9559 100644 --- a/sys/apps/system/colors.lua +++ b/sys/apps/system/colors.lua @@ -32,6 +32,12 @@ for k, v in pairs(defaults) do table.insert(allSettings, { name = k }) end +-- temp +if not _colors.backgroundColor then + _colors.backgroundColor = colors.black + _colors.fileColor = colors.white +end + local tab = UI.Tab { tabTitle = 'Shell', description = 'Shell option', From 30bad694173a24fed15459d99a16ee3ec91fa7b9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 28 Mar 2019 08:53:14 -0400 Subject: [PATCH 118/231] tweaks --- sys/apps/system/{colors.lua => shell.lua} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename sys/apps/system/{colors.lua => shell.lua} (99%) diff --git a/sys/apps/system/colors.lua b/sys/apps/system/shell.lua similarity index 99% rename from sys/apps/system/colors.lua rename to sys/apps/system/shell.lua index cce9559..ee413f5 100644 --- a/sys/apps/system/colors.lua +++ b/sys/apps/system/shell.lua @@ -40,7 +40,7 @@ end local tab = UI.Tab { tabTitle = 'Shell', - description = 'Shell option', + description = 'Shell options', grid1 = UI.ScrollingGrid { y = 2, ey = -10, x = 3, ex = -16, disableHeader = true, From c9ef150605082b28288f3d781eb7097779620216 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 29 Mar 2019 09:56:56 -0400 Subject: [PATCH 119/231] better text entry --- sys/apis/entry.lua | 477 +++++++++++++++++---------- sys/apis/input.lua | 6 + sys/apis/ui.lua | 11 +- sys/apis/ui/components/TextEntry.lua | 144 +++----- sys/apps/Lua.lua | 11 +- sys/apps/shell.lua | 49 ++- sys/apps/system/launcher.lua | 3 + 7 files changed, 405 insertions(+), 296 deletions(-) diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index 7379a09..e19f55c 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -8,246 +8,379 @@ function Entry:init(args) self.pos = 0 self.scroll = 0 self.value = '' - self.width = args.width - self.limit = 1024 + self.width = args.width or 256 + self.limit = args.limit or 1024 + self.mark = { } + self.offset = args.offset or 1 end function Entry:reset() self.pos = 0 self.scroll = 0 self.value = '' + self.mark = { } end -local function nextWord(line, cx) - local result = { line:find("(%w+)", cx) } - if #result > 1 and result[2] > cx then - return result[2] + 1 - elseif #result > 0 and result[1] == cx then - result = { line:find("(%w+)", result[2] + 1) } - if #result > 0 then - return result[1] - end - end +function Entry:nextWord() + return select(2, self.value:find("[%s%p]?%w[%s%p]", self.pos + 1)) or #self.value end -local function prevWord(line, cx) - local nOffset = 1 - while nOffset <= #line do - local nNext = line:find("%W%w", nOffset) - if nNext and nNext < cx then - nOffset = nNext + 1 - else - break - end - end - return nOffset - 1 < cx and nOffset - 1 +function Entry:prevWord() + local x = #self.value - (self.pos - 1) + local _, n = self.value:reverse():find("[%s%p]?%w[%s%p]", x) + return n and #self.value - n + 1 or 0 end function Entry:updateScroll() + local ps = self.scroll + if self.pos > #self.value then + self.pos = #self.value + self.scroll = 0 -- ?? + end if self.pos - self.scroll > self.width then - self.scroll = self.pos - (self.width) + self.scroll = self.pos - self.width elseif self.pos < self.scroll then self.scroll = self.pos end + if ps ~= self.scroll then + self.textChanged = true + end end -local function moveLeft(entry) - if entry.pos > 0 then - entry.pos = math.max(entry.pos - 1, 0) +function Entry:copyText(cx, ex) + return self.value:sub(cx + 1, ex) +end + +function Entry:insertText(x, text) + if #self.value + #text > self.limit then + text = text:sub(1, self.limit-#self.value) + end + self.value = self.value:sub(1, x) .. text .. self.value:sub(x + 1) + self.pos = self.pos + #text +end + +function Entry:deleteText(sx, ex) + local front = self.value:sub(1, sx) + local back = self.value:sub(ex + 1, #self.value) + self.value = front .. back + self.pos = sx +end + +function Entry:moveLeft() + if self.pos > 0 then + self.pos = self.pos - 1 return true end end -local function moveRight(entry) - local input = tostring(entry.value) - if entry.pos < #input then - entry.pos = math.min(entry.pos + 1, #input) +function Entry:moveRight() + if self.pos < #self.value then + self.pos = self.pos + 1 return true end end -local function moveStart(entry) - if entry.pos ~= 0 then - entry.pos = 0 +function Entry:moveHome() + if self.pos ~= 0 then + self.pos = 0 return true end end -local function moveEnd(entry) - if entry.pos ~= #tostring(entry.value) then - entry.pos = #tostring(entry.value) +function Entry:moveEnd() + if self.pos ~= #self.value then + self.pos = #self.value return true end end -local function backspace(entry) - if entry.pos > 0 then - local input = tostring(entry.value) - entry.value = input:sub(1, entry.pos - 1) .. input:sub(entry.pos + 1) - entry.pos = entry.pos - 1 +function Entry:moveTo(ie) + self.pos = math.max(0, math.min(ie.x + self.scroll - self.offset, #self.value)) +end + +function Entry:backspace() + if self.mark.active then + self:delete() + elseif self:moveLeft() then + self:delete() + end +end + +function Entry:moveWordRight() + if self.pos < #self.value then + self.pos = self:nextWord(self.value, self.pos + 1) return true end end -local function moveWordRight(entry) - local nx = nextWord(entry.value, entry.pos + 1) - if nx then - entry.pos = math.min(nx - 1, #entry.value) - elseif entry.pos < #entry.value then - entry.pos = #entry.value +function Entry:moveWordLeft() + if self.pos > 0 then + self.pos = self:prevWord(self.value, self.pos - 1) or 0 + return true end - return true end -local function moveWordLeft(entry) - if entry.pos ~= 0 then - local lx = 1 - while true do - local nx = nextWord(entry.value, lx) - if not nx or nx >= entry.pos then - break - end - lx = nx - end - if not lx then - entry.pos = 0 +function Entry:delete() + if self.mark.active then + self:deleteText(self.mark.x, self.mark.ex) + elseif self.pos < #self.value then + self:deleteText(self.pos, self.pos + 1) + end +end + +function Entry:cutFromStart() + if self.pos > 0 then + local text = self:copyText(1, self.pos) + self:deleteText(1, self.pos) + os.queueEvent('clipboard_copy', text) + end +end + +function Entry:cutToEnd() + if self.pos < #self.value then + local text = self:copyText(self.pos, #self.value) + self:deleteText(self.pos, #self.value) + os.queueEvent('clipboard_copy', text) + end +end + +function Entry:cutNextWord() + if self.pos < #self.value then + local ex = self:nextWord(self.value, self.pos) + local text = self:copyText(self.pos, ex) + self:deleteText(self.pos, ex) + os.queueEvent('clipboard_copy', text) + end +end + +function Entry:cutPrevWord() + if self.pos > 0 then + local sx = self:prevWord(self.value, self.pos) + local text = self:copyText(sx, self.pos) + self:deleteText(sx, self.pos) + os.queueEvent('clipboard_copy', text) + end +end + +function Entry:insertChar(ie) + if self.mark.active then + self:delete() + end + self:insertText(self.pos, ie.ch) +end + +function Entry:copy() + if #self.value > 0 then + self.mark.continue = true + if self.mark.active then + self:copyMarked() else - entry.pos = lx - 1 - end - return true - end -end - -local function delete(entry) - local input = tostring(entry.value) - if entry.pos < #input then - entry.value = input:sub(1, entry.pos) .. input:sub(entry.pos + 2) - entry.update = true - return true - end -end - --- credit for cut functions to: https://github.com/SquidDev-CC/mbs/blob/master/lib/readline.lua -local function cutFromStart(entry) - if entry.pos > 0 then - local input = tostring(entry.value) - os.queueEvent('clipboard_copy', input:sub(1, entry.pos)) - entry.value = input:sub(entry.pos + 1) - entry.pos = 0 - return true - end -end - -local function cutToEnd(entry) - local input = tostring(entry.value) - if entry.pos < #input then - os.queueEvent('clipboard_copy', input:sub(entry.pos + 1)) - entry.value = input:sub(1, entry.pos) - return true - end -end - -local function cutNextWord(entry) - local input = tostring(entry.value) - if entry.pos < #input then - local ex = nextWord(entry.value, entry.pos) - if ex then - os.queueEvent('clipboard_copy', input:sub(entry.pos + 1, ex)) - entry.value = input:sub(1, entry.pos) .. input:sub(ex + 1) - return true + os.queueEvent('clipboard_copy', self.value) end end end -local function cutPrevWord(entry) - if entry.pos > 0 then - local sx = prevWord(entry.value, entry.pos) - if sx then - local input = tostring(entry.value) - os.queueEvent('clipboard_copy', input:sub(sx + 1, entry.pos)) - entry.value = input:sub(1, sx) .. input:sub(entry.pos + 1) - entry.pos = sx - return true +function Entry:cut() + if self.mark.active then + self:copyMarked() + self:delete() + end +end + +function Entry:copyMarked() + local text = self:copyText(self.mark.x, self.mark.ex) + os.queueEvent('clipboard_copy', text) +end + +function Entry:paste(ie) + if #ie.text > 0 then + if self.mark.active then + self:delete() end + self:insertText(self.pos, ie.text) end end -local function insertChar(entry, ie) - local input = tostring(entry.value) - if #input < entry.limit then - entry.value = input:sub(1, entry.pos) .. ie.ch .. input:sub(entry.pos + 1) - entry.pos = entry.pos + 1 - entry.update = true - return true +function Entry:clearLine() + if #self.value > 0 then + self:reset() end end -local function copy(entry) - os.queueEvent('clipboard_copy', entry.value) -end - -local function paste(entry, ie) - local input = tostring(entry.value) - if #input + #ie.text > entry.limit then - ie.text = ie.text:sub(1, entry.limit-#input) +function Entry:markBegin() + if not self.mark.active then + self.mark.active = true + self.mark.anchor = { x = self.pos } end - entry.value = input:sub(1, entry.pos) .. ie.text .. input:sub(entry.pos + 1) - entry.pos = entry.pos + #ie.text - return true end -local function moveCursor(entry, ie) - -- need starting x passed in instead of hardcoding 3 - entry.pos = math.max(0, math.min(ie.x - 3 + entry.scroll, #entry.value)) - return true -end - -local function clearLine(entry) - local input = tostring(entry.value) - if #input > 0 then - entry:reset() - return true +function Entry:markFinish() + if self.pos == self.mark.anchor.x then + self.mark.active = false + else + self.mark.x = math.min(self.mark.anchor.x, self.pos) + self.mark.ex = math.max(self.mark.anchor.x, self.pos) end + self.textChanged = true + self.mark.continue = self.mark.active +end + +function Entry:unmark() + if self.mark.active then + self.textChanged = true + self.mark.active = false + end +end + +function Entry:markAnchor(ie) + self:unmark() + self:moveTo(ie) + self:markBegin() + self:markFinish() +end + +function Entry:markLeft() + self:markBegin() + if self:moveLeft() then + self:markFinish() + end +end + +function Entry:markRight() + self:markBegin() + if self:moveRight() then + self:markFinish() + end +end + +function Entry:markWord(ie) + local index = 1 + self:moveTo(ie) + while true do + local s, e = self.value:find('%w+', index) + if not s or s - 1 > self.pos then + break + end + if self.pos >= s - 1 and self.pos < e then + self.pos = s - 1 + self:markBegin() + self.pos = e + self:markFinish() + self:moveTo(ie) + break + end + index = e + 1 + end +end + +function Entry:markNextWord() + self:markBegin() + if self:moveWordRight() then + self:markFinish() + end +end + +function Entry:markPrevWord() + self:markBegin() + if self:moveWordLeft() then + self:markFinish() + end +end + +function Entry:markAll() + if #self.value > 0 then + self.mark.anchor = { x = 1 } + self.mark.active = true + self.mark.continue = true + self.mark.x = 0 + self.mark.ex = #self.value + self.textChanged = true + end +end + +function Entry:markHome() + self:markBegin() + if self:moveHome() then + self:markFinish() + end +end + +function Entry:markEnd() + self:markBegin() + if self:moveEnd() then + self:markFinish() + end +end + +function Entry:markTo(ie) + self:markBegin() + self:moveTo(ie) + self:markFinish() end local mappings = { - [ 'left' ] = moveLeft, - [ 'control-b' ] = moveLeft, - [ 'right' ] = moveRight, - [ 'control-f' ] = moveRight, - [ 'home' ] = moveStart, - [ 'control-a' ] = moveStart, - [ 'end' ] = moveEnd, - [ 'control-e' ] = moveEnd, - [ 'backspace' ] = backspace, - [ 'control-right' ] = moveWordRight, - [ 'alt-f' ] = moveWordRight, - [ 'control-left' ] = moveWordLeft, - [ 'alt-b' ] = moveWordLeft, - [ 'delete' ] = delete, - [ 'control-u' ] = cutFromStart, - [ 'control-k' ] = cutToEnd, - [ 'control-d' ] = cutNextWord, - [ 'control-w' ] = cutPrevWord, - [ 'char' ] = insertChar, - [ 'copy' ] = copy, - [ 'paste' ] = paste, - [ 'control-y' ] = paste, - [ 'mouse_click' ] = moveCursor, - [ 'mouse_rightclick' ] = clearLine, + [ 'left' ] = Entry.moveLeft, + [ 'control-b' ] = Entry.moveLeft, + [ 'right' ] = Entry.moveRight, + [ 'control-f' ] = Entry.moveRight, + [ 'home' ] = Entry.moveHome, + [ 'end' ] = Entry.moveEnd, + [ 'control-e' ] = Entry.moveEnd, + [ 'mouse_click' ] = Entry.moveTo, + [ 'backspace' ] = Entry.backspace, + [ 'control-right' ] = Entry.moveWordRight, + [ 'alt-f' ] = Entry.moveWordRight, + [ 'control-left' ] = Entry.moveWordLeft, + [ 'alt-b' ] = Entry.moveWordLeft, + [ 'mouse_doubleclick' ] = Entry.markWord, + [ 'delete' ] = Entry.delete, + [ 'control-u' ] = Entry.cutFromStart, + [ 'control-k' ] = Entry.cutToEnd, + --[ 'control-d' ] = Entry.cutNextWord, + [ 'control-w' ] = Entry.cutPrevWord, + [ 'char' ] = Entry.insertChar, + [ 'control-c' ] = Entry.copy, + [ 'control-x' ] = Entry.cut, + [ 'paste' ] = Entry.paste, + [ 'control-y' ] = Entry.paste, + [ 'mouse_rightclick' ] = Entry.clearLine, + + [ 'shift-left' ] = Entry.markLeft, + [ 'shift-right' ] = Entry.markRight, + [ 'mouse_down' ] = Entry.markAnchor, + [ 'mouse_drag' ] = Entry.markTo, + [ 'shift-mouse_click' ] = Entry.markTo, + [ 'control-a' ] = Entry.markAll, + [ 'control-shift-right' ] = Entry.markNextWord, + [ 'control-shift-left' ] = Entry.markPrevWord, + [ 'shift-end' ] = Entry.markEnd, + [ 'shift-home' ] = Entry.markHome, } function Entry:process(ie) local action = mappings[ie.code] - local updated + + self.textChanged = false if action then - updated = action(self, ie) + local pos = self.pos + local line = self.value + + local wasMarking = self.mark.continue + self.mark.continue = false + + action(self, ie) + + self.textChanged = self.textChanged or self.value ~= line + self.posChanged = pos ~= self.pos + self:updateScroll() + + if not self.mark.continue and wasMarking then + self:unmark() + end + + return true end - - self:updateScroll() - - return updated end return Entry diff --git a/sys/apis/input.lua b/sys/apis/input.lua index a47213a..a1e91a6 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -119,6 +119,12 @@ function input:translate(event, code, p1, p2) local buttons = { 'mouse_click', 'mouse_rightclick' } self.mch = buttons[code] self.mfired = nil + return { + code = input:toCode('mouse_down', 255), + button = code, + x = p1, + y = p2, + } elseif event == 'mouse_drag' then self.mfired = true diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 5a3b257..e4a373a 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -45,7 +45,7 @@ function Manager:init() if ie and currentPage then local target = currentPage.focused or currentPage self:inputEvent(target, - { type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target }) + { type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target, ie = ie }) currentPage:sync() end end @@ -97,7 +97,7 @@ function Manager:init() end, mouse_click = function(_, button, x, y) - Input:translate('mouse_click', button, x, y) + local ie = Input:translate('mouse_click', button, x, y) local currentPage = self:getActivePage() if currentPage then @@ -107,6 +107,7 @@ function Manager:init() currentPage:setFocus(event.element) currentPage:sync() end + self:click(currentPage, ie.code, button, x, y) end end end, @@ -136,14 +137,15 @@ function Manager:init() if ie and currentPage then local event = currentPage:pointToChild(x, y) event.type = ie.code + event.ie = ie self:inputEvent(event.element, event) currentPage:sync() end end, paste = function(_, text) - Input:translate('paste') - self:emitEvent({ type = 'paste', text = text }) + local ie = Input:translate('paste', text) + self:emitEvent({ type = 'paste', text = text, ie = ie }) self:getActivePage():sync() end, } @@ -259,6 +261,7 @@ function Manager:click(target, code, button, x, y) clickEvent.button = button clickEvent.type = code clickEvent.key = code + clickEvent.ie = { code = code, x = x, y = y } if clickEvent.element.focus then target:setFocus(clickEvent.element) diff --git a/sys/apis/ui/components/TextEntry.lua b/sys/apis/ui/components/TextEntry.lua index 384c098..e8df5d2 100644 --- a/sys/apis/ui/components/TextEntry.lua +++ b/sys/apis/ui/components/TextEntry.lua @@ -1,9 +1,9 @@ local class = require('class') +local entry = require('entry') local UI = require('ui') local Util = require('util') local colors = _G.colors -local os = _G.os local _rep = string.rep UI.TextEntry = class(UI.Window) @@ -18,41 +18,31 @@ UI.TextEntry.defaults = { backgroundFocusColor = colors.black, --lightGray, height = 1, limit = 6, - pos = 0, accelerators = { [ 'control-c' ] = 'copy', } } function UI.TextEntry:postInit() self.value = tostring(self.value) + self.entry = entry({ limit = self.limit, offset = 2 }) +end + +function UI.TextEntry:layout() + UI.Window.layout(self) + self.entry.width = self.width - 2 end function UI.TextEntry:setValue(value) self.value = value + self.entry:unmark() + self.entry.value = value + self.entry:updateScroll() end function UI.TextEntry:setPosition(pos) - self.pos = pos -end - -function UI.TextEntry:updateScroll() - if not self.scroll then - self.scroll = 0 - end - - if not self.pos then - self.pos = #tostring(self.value) - self.scroll = 0 - elseif self.pos > #tostring(self.value) then - self.pos = #tostring(self.value) - self.scroll = 0 - end - - if self.pos - self.scroll > self.width - 2 then - self.scroll = self.pos - (self.width - 2) - elseif self.pos < self.scroll then - self.scroll = self.pos - end + self.entry.pos = pos + self.entry.value = self.value + self.entry:updateScroll() end function UI.TextEntry:draw() @@ -62,11 +52,10 @@ function UI.TextEntry:draw() bg = self.backgroundFocusColor end - self:updateScroll() local text = tostring(self.value) if #text > 0 then - if self.scroll and self.scroll > 0 then - text = text:sub(1 + self.scroll) + if self.entry.scroll > 0 then + text = text:sub(1 + self.entry.scroll) end if self.mask then text = _rep('*', #text) @@ -77,21 +66,32 @@ function UI.TextEntry:draw() end self:write(1, 1, ' ' .. Util.widthify(text, self.width - 2) .. ' ', bg, tc) + + if self.entry.mark.active then + local tx = math.max(self.entry.mark.x - self.entry.scroll, 0) + local tex = self.entry.mark.ex - self.entry.scroll + + if tex > self.width - 2 then -- unsure about this + tex = self.width - 2 - tx + end + + if tx ~= tex then + self:write(tx + 2, 1, text:sub(tx + 1, tex), colors.gray, tc) + end + end if self.focused then - self:setCursorPos(self.pos-self.scroll+2, 1) + self:setCursorPos(self.entry.pos - self.entry.scroll + 2, 1) end end function UI.TextEntry:reset() - self.pos = 0 - self.value = '' + self.entry:reset() self:draw() self:updateCursor() end function UI.TextEntry:updateCursor() - self:updateScroll() - self:setCursorPos(self.pos-self.scroll+2, 1) + self:setCursorPos(self.entry.pos - self.entry.scroll + 2, 1) end function UI.TextEntry:focus() @@ -103,86 +103,20 @@ function UI.TextEntry:focus() end end ---[[ - A few lines below from theoriginalbit - http://www.computercraft.info/forums2/index.php?/topic/16070-read-and-limit-length-of-the-input-field/ ---]] function UI.TextEntry:eventHandler(event) - if event.type == 'key' then - local ch = event.key - if ch == 'left' then - if self.pos > 0 then - self.pos = math.max(self.pos-1, 0) - self:draw() - end - elseif ch == 'right' then - local input = tostring(self.value) - if self.pos < #input then - self.pos = math.min(self.pos+1, #input) - self:draw() - end - elseif ch == 'home' then - self.pos = 0 + local text = self.value + self.entry.value = text + if event.ie and self.entry:process(event.ie) then + if self.entry.textChanged then + self.value = self.entry.value self:draw() - elseif ch == 'end' then - self.pos = #tostring(self.value) - self:draw() - elseif ch == 'backspace' then - if self.pos > 0 then - local input = tostring(self.value) - self.value = input:sub(1, self.pos-1) .. input:sub(self.pos+1) - self.pos = self.pos - 1 - self:draw() + if text ~= self.value then self:emit({ type = 'text_change', text = self.value, element = self }) end - elseif ch == 'delete' then - local input = tostring(self.value) - if self.pos < #input then - self.value = input:sub(1, self.pos) .. input:sub(self.pos+2) - self:draw() - self:emit({ type = 'text_change', text = self.value, element = self }) - end - elseif #ch == 1 then - local input = tostring(self.value) - if #input < self.limit then - self.value = input:sub(1, self.pos) .. ch .. input:sub(self.pos+1) - self.pos = self.pos + 1 - self:draw() - self:emit({ type = 'text_change', text = self.value, element = self }) - end - else - return false - end - return true - - elseif event.type == 'copy' then - os.queueEvent('clipboard_copy', self.value) - - elseif event.type == 'paste' then - local input = tostring(self.value) - local text = event.text - if #input + #text > self.limit then - text = text:sub(1, self.limit-#input) - end - self.value = input:sub(1, self.pos) .. text .. input:sub(self.pos+1) - self.pos = self.pos + #text - self:draw() - self:updateCursor() - self:emit({ type = 'text_change', text = self.value, element = self }) - return true - - elseif event.type == 'mouse_click' then - if self.focused and event.x > 1 then - self.pos = event.x + self.scroll - 2 + elseif self.entry.posChanged then self:updateCursor() - return true - end - elseif event.type == 'mouse_rightclick' then - local input = tostring(self.value) - if #input > 0 then - self:reset() - self:emit({ type = 'text_change', text = self.value, element = self }) end + return true end return false diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index 12bc072..5627d6c 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -34,7 +34,7 @@ local page = UI.Page { prompt = UI.TextEntry { y = 2, shadowText = 'enter command', - limit = 256, + limit = 1024, accelerators = { enter = 'command_enter', up = 'history_back', @@ -72,12 +72,11 @@ page.output = page.tabs[2].output function page:setPrompt(value, focus) self.prompt:setValue(value) - self.prompt.scroll = 0 - self.prompt:setPosition(#value) - self.prompt:updateScroll() if value:sub(-1) == ')' then self.prompt:setPosition(#value - 1) + else + self.prompt:setPosition(#value) end self.prompt:draw() @@ -155,8 +154,8 @@ function page:eventHandler(event) elseif event.type == 'autocomplete' then local sz = #self.prompt.value - local pos = self.prompt.pos - self:setPrompt(autocomplete(sandboxEnv, self.prompt.value, self.prompt.pos)) + local pos = self.prompt.entry.pos + self:setPrompt(autocomplete(sandboxEnv, self.prompt.value, self.prompt.entry.pos)) self.prompt:setPosition(pos + #self.prompt.value - sz) self.prompt:updateCursor() diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index a138fe6..5c9ecea 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -370,7 +370,9 @@ local term = _G.term local textutils = _G.textutils local oldTerm -local terminal = term.current() +local terminal = term.current() +local _rep = string.rep +local _sub = string.sub if not terminal.scrollUp then terminal = Terminal.window(term.current()) @@ -402,11 +404,19 @@ if not _colors.backgroundColor then _colors.fileColor = colors.white end +local palette = { } +for n = 1, 16 do + palette[2 ^ (n - 1)] = _sub("0123456789abcdef", n, n) +end + if not term.isColor() then _colors = { } for k, v in pairs(config.color) do _colors[k] = Terminal.colorToGrayscale(v) end + for n = 1, 16 do + palette[2 ^ (n - 1)] = _sub("088888878877787f", n, n) + end end local function autocompleteArgument(program, words) @@ -556,12 +566,17 @@ end local function shellRead(history) local lastLen = 0 local entry = Entry({ - width = term.getSize() - 3 + width = term.getSize() - 3, + offset = 3, }) history:reset() term.setCursorBlink(true) + local function updateCursor() + term.setCursorPos(3 + entry.pos - entry.scroll, select(2, term.getCursorPos())) + end + local function redraw() if terminal.scrollBottom then terminal.scrollBottom() @@ -571,9 +586,18 @@ local function shellRead(history) local filler = #entry.value < lastLen and string.rep(' ', lastLen - #entry.value) or '' - local str = string.sub(entry.value, entry.scroll + 1) - term.write(string.sub(str, 1, entry.width) .. filler) - term.setCursorPos(3 + entry.pos - entry.scroll, cy) + local str = string.sub(entry.value, entry.scroll + 1, entry.width + entry.scroll) .. filler + local fg = _rep(palette[_colors.commandTextColor], #str) + local bg = _rep(palette[_colors.backgroundColor], #str) + if entry.mark.active then + local sx = entry.mark.x - entry.scroll + 1 + local ex = entry.mark.ex - entry.scroll + 1 + bg = string.rep('f', sx - 1) .. + string.rep('7', ex - sx) .. + string.rep('f', #str - ex + 1) + end + term.blit(str, fg, bg) + updateCursor() lastLen = #entry.value end @@ -597,13 +621,13 @@ local function shellRead(history) elseif ie.code == 'up' or ie.code == 'control-p' or ie.code == 'down' or ie.code == 'control-n' then + entry:reset() if ie.code == 'up' or ie.code == 'control-p' then entry.value = history:back() or '' else entry.value = history:forward() or '' end - entry.pos = string.len(entry.value) - entry.scroll = 0 + entry.pos = #entry.value entry:updateScroll() redraw() @@ -613,17 +637,24 @@ local function shellRead(history) if cline then entry.value = cline entry.pos = #entry.value + entry:unmark() entry:updateScroll() redraw() end end - elseif entry:process(ie) then - redraw() + else + entry:process(ie) + if entry.textChanged then + redraw() + elseif entry.posChanged then + updateCursor() + end end elseif event == "term_resize" then entry.width = term.getSize() - 3 + entry:updateScroll() redraw() end end diff --git a/sys/apps/system/launcher.lua b/sys/apps/system/launcher.lua index 25e5db6..a2fb843 100644 --- a/sys/apps/system/launcher.lua +++ b/sys/apps/system/launcher.lua @@ -57,6 +57,9 @@ end function tab:eventHandler(event) if event.type == 'choice_change' then self.custom.enabled = event.value == 'custom' + if self.custom.enabled then + self.custom.value = config.launcher + end self:draw() elseif event.type == 'update' then From 78402e89cde0bd630145ed114e3953c079755134 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 29 Mar 2019 10:44:21 -0400 Subject: [PATCH 120/231] better text entry --- sys/apis/entry.lua | 2 +- sys/apis/input.lua | 14 ++++++++++---- sys/apps/shell.lua | 3 +++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index e19f55c..8126960 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -361,7 +361,7 @@ function Entry:process(ie) local action = mappings[ie.code] self.textChanged = false - +_debug(ie) if action then local pos = self.pos local line = self.value diff --git a/sys/apis/input.lua b/sys/apis/input.lua index a1e91a6..94d9c91 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -76,11 +76,18 @@ function input:translate(event, code, p1, p2) if p1 then -- key is held down if not modifiers[code] then self.fired = true - return { code = input:toCode(keys.getName(code), code) } + local ch = input:toCode(keys.getName(code), code) + if #ch == 1 then + return { + code = 'char', + ch = ch, + } + end + return { code = ch } end else self.state[code] = true - if self:modifierPressed() and not modifiers[code] or code == 57 then + if self:modifierPressed() and not modifiers[code] then --or code == 57 then self.fired = true return { code = input:toCode(keys.getName(code), code) } else @@ -89,8 +96,7 @@ function input:translate(event, code, p1, p2) end elseif event == 'char' then - if not keyboard.state[keys.leftAlt] and - not keyboard.state[keys.rightAlt] then + if not self.fired then self.fired = true return { code = event, ch = code } -- return { code = event, ch = input:toCode(code) } diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index 5c9ecea..d415c11 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -362,6 +362,7 @@ local Config = require('config') local Entry = require('entry') local History = require('history') local Input = require('input') +local Sound = require('sound') local Terminal = require('terminal') local colors = _G.colors @@ -640,6 +641,8 @@ local function shellRead(history) entry:unmark() entry:updateScroll() redraw() + else + Sound.play('entity.villager.no') end end From c1baf107c1f61766f2ca9a73c45804e3e9495db0 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 29 Mar 2019 10:45:43 -0400 Subject: [PATCH 121/231] better text entry -- oops --- sys/apis/entry.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index 8126960..e19f55c 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -361,7 +361,7 @@ function Entry:process(ie) local action = mappings[ie.code] self.textChanged = false -_debug(ie) + if action then local pos = self.pos local line = self.value From 19159730a4f8b4cdc898876f34d4a2e49ba2d4d0 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 29 Mar 2019 15:47:01 -0400 Subject: [PATCH 122/231] better text entry - bugfixes --- sys/apis/entry.lua | 14 ++++++++------ sys/apis/ui.lua | 2 +- sys/apis/ui/components/TextEntry.lua | 7 ++++--- sys/apps/shell.lua | 2 -- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index e19f55c..b31f247 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -327,24 +327,26 @@ local mappings = { [ 'end' ] = Entry.moveEnd, [ 'control-e' ] = Entry.moveEnd, [ 'mouse_click' ] = Entry.moveTo, - [ 'backspace' ] = Entry.backspace, [ 'control-right' ] = Entry.moveWordRight, [ 'alt-f' ] = Entry.moveWordRight, [ 'control-left' ] = Entry.moveWordLeft, [ 'alt-b' ] = Entry.moveWordLeft, - [ 'mouse_doubleclick' ] = Entry.markWord, + + [ 'backspace' ] = Entry.backspace, [ 'delete' ] = Entry.delete, + [ 'char' ] = Entry.insertChar, + [ 'mouse_rightclick' ] = Entry.clearLine, + + [ 'control-c' ] = Entry.copy, [ 'control-u' ] = Entry.cutFromStart, [ 'control-k' ] = Entry.cutToEnd, - --[ 'control-d' ] = Entry.cutNextWord, [ 'control-w' ] = Entry.cutPrevWord, - [ 'char' ] = Entry.insertChar, - [ 'control-c' ] = Entry.copy, + --[ 'control-d' ] = Entry.cutNextWord, [ 'control-x' ] = Entry.cut, [ 'paste' ] = Entry.paste, [ 'control-y' ] = Entry.paste, - [ 'mouse_rightclick' ] = Entry.clearLine, + [ 'mouse_doubleclick' ] = Entry.markWord, [ 'shift-left' ] = Entry.markLeft, [ 'shift-right' ] = Entry.markRight, [ 'mouse_down' ] = Entry.markAnchor, diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index e4a373a..41c7242 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -261,7 +261,7 @@ function Manager:click(target, code, button, x, y) clickEvent.button = button clickEvent.type = code clickEvent.key = code - clickEvent.ie = { code = code, x = x, y = y } + clickEvent.ie = { code = code, x = clickEvent.x, y = clickEvent.y } if clickEvent.element.focus then target:setFocus(clickEvent.element) diff --git a/sys/apis/ui/components/TextEntry.lua b/sys/apis/ui/components/TextEntry.lua index e8df5d2..69566c6 100644 --- a/sys/apis/ui/components/TextEntry.lua +++ b/sys/apis/ui/components/TextEntry.lua @@ -35,13 +35,13 @@ end function UI.TextEntry:setValue(value) self.value = value self.entry:unmark() - self.entry.value = value + self.entry.value = tostring(value) self.entry:updateScroll() end function UI.TextEntry:setPosition(pos) self.entry.pos = pos - self.entry.value = self.value + self.entry.value = tostring(self.value) self.entry:updateScroll() end @@ -86,6 +86,7 @@ end function UI.TextEntry:reset() self.entry:reset() + self.value = '' self:draw() self:updateCursor() end @@ -105,7 +106,7 @@ end function UI.TextEntry:eventHandler(event) local text = self.value - self.entry.value = text + self.entry.value = tostring(text) if event.ie and self.entry:process(event.ie) then if self.entry.textChanged then self.value = self.entry.value diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index d415c11..a32676a 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -662,8 +662,6 @@ local function shellRead(history) end end - --local _, cy = term.getCursorPos() - --term.setCursorPos( w + 1, cy ) print() term.setCursorBlink( false ) return entry.value From 737ac095de21a9238f45fcc26b0504c699055d26 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 31 Mar 2019 15:16:45 -0400 Subject: [PATCH 123/231] fix menu separators + sys dir restructure --- sys/apis/ui/components/DropMenu.lua | 1 + sys/apis/ui/components/MenuBar.lua | 4 +--- sys/apps/Files.lua | 8 +++++--- sys/apps/Network.lua | 4 ++-- sys/apps/netdaemon.lua | 4 ++-- sys/{ => apps}/network/proxy.lua | 0 sys/{ => apps}/network/redserver.lua | 0 sys/{ => apps}/network/samba.lua | 0 sys/{ => apps}/network/snmp.lua | 0 sys/{ => apps}/network/telnet.lua | 0 sys/{ => apps}/network/transport.lua | 0 sys/{ => apps}/network/trust.lua | 0 sys/{ => apps}/network/vnc.lua | 0 sys/autorun/upgraded.lua | 4 +++- sys/boot/opus.boot | 2 +- sys/{extensions => init}/1.device.lua | 0 sys/{extensions => init}/2.vfs.lua | 0 sys/{extensions => init}/3.modules.lua | 0 sys/{extensions => init}/4.label.lua | 0 sys/{extensions => init}/4.user.lua | 0 sys/{extensions => init}/5.network.lua | 0 sys/{extensions => init}/6.packages.lua | 0 sys/{extensions => init}/6.tl3.lua | 0 sys/{extensions => init}/7.multishell.lua | 0 sys/kernel.lua | 2 +- 25 files changed, 16 insertions(+), 13 deletions(-) rename sys/{ => apps}/network/proxy.lua (100%) rename sys/{ => apps}/network/redserver.lua (100%) rename sys/{ => apps}/network/samba.lua (100%) rename sys/{ => apps}/network/snmp.lua (100%) rename sys/{ => apps}/network/telnet.lua (100%) rename sys/{ => apps}/network/transport.lua (100%) rename sys/{ => apps}/network/trust.lua (100%) rename sys/{ => apps}/network/vnc.lua (100%) rename sys/{extensions => init}/1.device.lua (100%) rename sys/{extensions => init}/2.vfs.lua (100%) rename sys/{extensions => init}/3.modules.lua (100%) rename sys/{extensions => init}/4.label.lua (100%) rename sys/{extensions => init}/4.user.lua (100%) rename sys/{extensions => init}/5.network.lua (100%) rename sys/{extensions => init}/6.packages.lua (100%) rename sys/{extensions => init}/6.tl3.lua (100%) rename sys/{extensions => init}/7.multishell.lua (100%) diff --git a/sys/apis/ui/components/DropMenu.lua b/sys/apis/ui/components/DropMenu.lua index 98f92be..79f1a8a 100644 --- a/sys/apis/ui/components/DropMenu.lua +++ b/sys/apis/ui/components/DropMenu.lua @@ -24,6 +24,7 @@ function UI.DropMenu:setParent() for _,child in ipairs(self.children) do child.width = maxWidth + 2 if child.spacer then + child.inactive = true child.text = string.rep('-', child.width - 2) end end diff --git a/sys/apis/ui/components/MenuBar.lua b/sys/apis/ui/components/MenuBar.lua index 34ee7b9..4c239c0 100644 --- a/sys/apis/ui/components/MenuBar.lua +++ b/sys/apis/ui/components/MenuBar.lua @@ -25,8 +25,6 @@ UI.MenuBar.defaults = { showBackButton = false, buttonClass = 'MenuItem', } -UI.MenuBar.spacer = { spacer = true, text = 'spacer', inactive = true } - function UI.MenuBar:postInit() self:addButtons(self.buttons) end @@ -42,7 +40,7 @@ function UI.MenuBar:addButtons(buttons) else local buttonProperties = { x = self.lastx, - width = #button.text + self.spacing, + width = #(button.text or 'button') + self.spacing, centered = false, } self.lastx = self.lastx + buttonProperties.width diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 3c1dd4f..855aaa1 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -7,6 +7,7 @@ local colors = _G.colors local fs = _G.fs local multishell = _ENV.multishell local os = _G.os +local pastebin = _G.pastebin local shell = _ENV.shell local FILE = 1 @@ -45,7 +46,7 @@ local Browser = UI.Page { { text = 'Cloud edit c', event = 'cedit', flags = FILE }, { text = 'Pastebin put p', event = 'cedit', flags = FILE }, { text = 'Shell s', event = 'shell' }, - UI.MenuBar.spacer, + { spacer = true }, { text = 'Quit q', event = 'quit' }, } }, { text = 'Edit', dropdown = { @@ -53,10 +54,10 @@ local Browser = UI.Page { { text = 'Copy ^c', event = 'copy' }, { text = 'Copy path ', event = 'copy_path' }, { text = 'Paste ^v', event = 'paste' }, - UI.MenuBar.spacer, + { spacer = true }, { text = 'Mark m', event = 'mark' }, { text = 'Unmark all u', event = 'unmark' }, - UI.MenuBar.spacer, + { spacer = true }, { text = 'Delete del', event = 'delete' }, } }, { text = 'View', dropdown = { @@ -365,6 +366,7 @@ function Browser:eventHandler(event) if file and not file.isDir then local s, m = pastebin.put(file.fullName) if s then + os.queueEvent('clipboard_copy', s) self.notification:success(string.format('Uploaded as %s', m), 0) else self.notification:error(m) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index eeb00bf..8b7b7b2 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -33,7 +33,7 @@ local page = UI.Page { { text = 'Connect', dropdown = { { text = 'Telnet t', event = 'telnet' }, { text = 'VNC v', event = 'vnc' }, - UI.MenuBar.spacer, + { spacer = true }, { text = 'Reboot r', event = 'reboot' }, } }, { text = 'Trust', dropdown = { @@ -44,7 +44,7 @@ local page = UI.Page { x = -3, dropdown = { { text = 'Port Status', event = 'ports', modem = true }, - UI.MenuBar.spacer, + { spacer = true }, { text = 'Help', event = 'help', noCheck = true }, }, }, diff --git a/sys/apps/netdaemon.lua b/sys/apps/netdaemon.lua index ae51a19..cc14a7b 100644 --- a/sys/apps/netdaemon.lua +++ b/sys/apps/netdaemon.lua @@ -15,8 +15,8 @@ end print('Net daemon starting') -for _,file in pairs(fs.list('sys/network')) do - local fn, msg = Util.run(_ENV, 'sys/network/' .. file) +for _,file in pairs(fs.list('sys/apps/network')) do + local fn, msg = Util.run(_ENV, 'sys/apps/network/' .. file) if not fn then printError(msg) end diff --git a/sys/network/proxy.lua b/sys/apps/network/proxy.lua similarity index 100% rename from sys/network/proxy.lua rename to sys/apps/network/proxy.lua diff --git a/sys/network/redserver.lua b/sys/apps/network/redserver.lua similarity index 100% rename from sys/network/redserver.lua rename to sys/apps/network/redserver.lua diff --git a/sys/network/samba.lua b/sys/apps/network/samba.lua similarity index 100% rename from sys/network/samba.lua rename to sys/apps/network/samba.lua diff --git a/sys/network/snmp.lua b/sys/apps/network/snmp.lua similarity index 100% rename from sys/network/snmp.lua rename to sys/apps/network/snmp.lua diff --git a/sys/network/telnet.lua b/sys/apps/network/telnet.lua similarity index 100% rename from sys/network/telnet.lua rename to sys/apps/network/telnet.lua diff --git a/sys/network/transport.lua b/sys/apps/network/transport.lua similarity index 100% rename from sys/network/transport.lua rename to sys/apps/network/transport.lua diff --git a/sys/network/trust.lua b/sys/apps/network/trust.lua similarity index 100% rename from sys/network/trust.lua rename to sys/apps/network/trust.lua diff --git a/sys/network/vnc.lua b/sys/apps/network/vnc.lua similarity index 100% rename from sys/network/vnc.lua rename to sys/apps/network/vnc.lua diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index c23d1e9..7b30a1f 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -1,4 +1,6 @@ if fs.exists('sys/apps/shell') and fs.exists('sys/apps/shell.lua') then fs.delete('sys/apps/shell') end -if fs.exists('sys/etc/app.db') then fs.delete('sys/etc/app.db') end \ No newline at end of file +if fs.exists('sys/etc/app.db') then fs.delete('sys/etc/app.db') end +if fs.exists('sys/extensions') then fs.delete('sys/extensions') end +if fs.exists('sys/network') then fs.delete('sys/network') end diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index 69b90d3..7ba7a1d 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -58,7 +58,7 @@ else _G.requireInjector = runUrl('sys/apis/injector.lua') - runUrl('sys/extensions/2.vfs.lua') + runUrl('sys/init/2.vfs.lua') -- install file system fs.mount('', 'gitfs', GIT_REPO) diff --git a/sys/extensions/1.device.lua b/sys/init/1.device.lua similarity index 100% rename from sys/extensions/1.device.lua rename to sys/init/1.device.lua diff --git a/sys/extensions/2.vfs.lua b/sys/init/2.vfs.lua similarity index 100% rename from sys/extensions/2.vfs.lua rename to sys/init/2.vfs.lua diff --git a/sys/extensions/3.modules.lua b/sys/init/3.modules.lua similarity index 100% rename from sys/extensions/3.modules.lua rename to sys/init/3.modules.lua diff --git a/sys/extensions/4.label.lua b/sys/init/4.label.lua similarity index 100% rename from sys/extensions/4.label.lua rename to sys/init/4.label.lua diff --git a/sys/extensions/4.user.lua b/sys/init/4.user.lua similarity index 100% rename from sys/extensions/4.user.lua rename to sys/init/4.user.lua diff --git a/sys/extensions/5.network.lua b/sys/init/5.network.lua similarity index 100% rename from sys/extensions/5.network.lua rename to sys/init/5.network.lua diff --git a/sys/extensions/6.packages.lua b/sys/init/6.packages.lua similarity index 100% rename from sys/extensions/6.packages.lua rename to sys/init/6.packages.lua diff --git a/sys/extensions/6.tl3.lua b/sys/init/6.tl3.lua similarity index 100% rename from sys/extensions/6.tl3.lua rename to sys/init/6.tl3.lua diff --git a/sys/extensions/7.multishell.lua b/sys/init/7.multishell.lua similarity index 100% rename from sys/extensions/7.multishell.lua rename to sys/init/7.multishell.lua diff --git a/sys/kernel.lua b/sys/kernel.lua index 2f53ddf..ba092a2 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -279,7 +279,7 @@ local function init(...) local runLevel = #args > 0 and 6 or 7 print('Starting Opus OS') - local dir = 'sys/extensions' + local dir = 'sys/init' local files = fs.list(dir) table.sort(files) for _,file in ipairs(files) do From 4f9bd8eb0f0f56f223af8aef4860a6a5910cec1b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 7 Apr 2019 10:09:47 -0400 Subject: [PATCH 124/231] support open os command line programs --- sys/apis/fs/linkfs.lua | 2 + sys/apis/peripheral.lua | 88 ++++++++++++++++++++----------------- sys/apis/util.lua | 31 +++++++++++++ sys/apps/Help.lua | 26 ++++++----- sys/apps/autorun.lua | 2 +- sys/apps/system/aliases.lua | 18 +++++--- sys/init/2.vfs.lua | 1 + sys/init/3.relay.lua | 27 ++++++++++++ sys/init/7.multishell.lua | 16 ++++--- 9 files changed, 146 insertions(+), 65 deletions(-) create mode 100644 sys/init/3.relay.lua diff --git a/sys/apis/fs/linkfs.lua b/sys/apis/fs/linkfs.lua index e46342c..38cceac 100644 --- a/sys/apis/fs/linkfs.lua +++ b/sys/apis/fs/linkfs.lua @@ -2,6 +2,8 @@ local fs = _G.fs local linkfs = { } +-- TODO: implement broken links + local methods = { 'exists', 'getFreeSpace', 'getSize', 'isDir', 'isReadOnly', 'list', 'listEx', 'makeDir', 'open', 'getDrive' } diff --git a/sys/apis/peripheral.lua b/sys/apis/peripheral.lua index a176268..6e73a0e 100644 --- a/sys/apis/peripheral.lua +++ b/sys/apis/peripheral.lua @@ -17,53 +17,59 @@ end function Peripheral.addDevice(deviceList, side) local name = side - local ptype = Peripheral.getType(side) + pcall(function() + local ptype = Peripheral.getType(side) + local dev = Peripheral.wrap(side) - if not ptype then - return - end - - if ptype == 'modem' then - if not Peripheral.call(name, 'isWireless') then --- ptype = 'wireless_modem' --- else - ptype = 'wired_modem' + if not ptype or not dev then + return end - end - local sides = { - front = true, - back = true, - top = true, - bottom = true, - left = true, - right = true - } - - if sides[name] then - local i = 1 - local uniqueName = ptype - while deviceList[uniqueName] do - uniqueName = ptype .. '_' .. i - i = i + 1 + if ptype == 'modem' then + if not Peripheral.call(name, 'isWireless') then + -- ptype = 'wireless_modem' + -- else + ptype = 'wired_modem' + if dev.getMetadata then + -- avoid open computer relays being registered + -- as 'wired_modem' + ptype = dev.getMetadata().name or 'wired_modem' + end + end end - name = uniqueName - end - -- this can randomly fail - if not deviceList[name] then - pcall(function() - deviceList[name] = Peripheral.wrap(side) - end) + local sides = { + front = true, + back = true, + top = true, + bottom = true, + left = true, + right = true + } - if deviceList[name] then - Util.merge(deviceList[name], { - name = name, - type = ptype, - side = side, - }) + if sides[name] then + local i = 1 + local uniqueName = ptype + while deviceList[uniqueName] do + uniqueName = ptype .. '_' .. i + i = i + 1 + end + name = uniqueName end - end + + -- this can randomly fail + if not deviceList[name] then + deviceList[name] = dev + + if deviceList[name] then + Util.merge(deviceList[name], { + name = name, + type = ptype, + side = side, + }) + end + end + end) return deviceList[name] end @@ -117,4 +123,4 @@ function Peripheral.get(args) end end -return Peripheral +return Peripheral \ No newline at end of file diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 2a3fb64..a15e1e2 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -659,6 +659,37 @@ function Util.wordWrap(str, limit) return lines end +-- https://github.com/MightyPirates/OpenComputers +function Util.parse(...) + local params = table.pack(...) + local args = {} + local options = {} + local doneWithOptions = false + for i = 1, params.n do + local param = params[i] + if not doneWithOptions and type(param) == "string" then + if param == "--" then + doneWithOptions = true -- stop processing options at `--` + elseif param:sub(1, 2) == "--" then + local key, value = param:match("%-%-(.-)=(.*)") + if not key then + key, value = param:sub(3), true + end + options[key] = value + elseif param:sub(1, 1) == "-" and param ~= "-" then + for j = 2, string.len(param) do + options[string.sub(param, j, j)] = true + end + else + table.insert(args, param) + end + else + table.insert(args, param) + end + end + return args, options +end + function Util.args(arg) local options, args = { }, { } diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index cdb5de7..b43d23a 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -1,8 +1,8 @@ local UI = require('ui') local Util = require('util') -local colors = _G.colors -local help = _G.help +local colors = _G.colors +local help = _G.help UI:configure('Help', ...) @@ -40,7 +40,7 @@ local topicPage = UI.Page { backgroundColor = colors.black, titleBar = UI.TitleBar { title = 'text', - previousPage = true, + event = 'back', }, helpText = UI.TextArea { backgroundColor = colors.black, @@ -52,9 +52,18 @@ local topicPage = UI.Page { }, } +function topicPage:enable(name) + local f = help.lookup(name) + + self.titleBar.title = name + self.helpText:setText(f and Util.readFile(f) or 'No help available for ' .. name) + + return UI.Page.enable(self) +end + function topicPage:eventHandler(event) if event.type == 'back' then - UI:setPreviousPage() + UI:setPage(page) end return UI.Page.eventHandler(self, event) end @@ -66,12 +75,8 @@ function page:eventHandler(event) elseif event.type == 'grid_select' then if self.grid:getSelected() then local name = self.grid:getSelected().name - local f = help.lookup(name) - topicPage.titleBar.title = name - topicPage.helpText:setText(Util.readFile(f)) - - UI:setPage(topicPage) + UI:setPage(topicPage, name) end elseif event.type == 'text_change' then @@ -93,5 +98,6 @@ function page:eventHandler(event) end end -UI:setPage(page) +local args = { ... } +UI:setPage(#args[1] and topicPage or page, args[1]) UI:pullEvents() diff --git a/sys/apps/autorun.lua b/sys/apps/autorun.lua index e7febc1..40e0e74 100644 --- a/sys/apps/autorun.lua +++ b/sys/apps/autorun.lua @@ -55,7 +55,7 @@ runDir('usr/autorun') if not success then if multishell then - --multishell.setFocus(multishell.getCurrent()) + multishell.setFocus(multishell.getCurrent()) end _G.printError('A startup program has errored') print('Press enter to continue') diff --git a/sys/apps/system/aliases.lua b/sys/apps/system/aliases.lua index 0523f27..3a98bc6 100644 --- a/sys/apps/system/aliases.lua +++ b/sys/apps/system/aliases.lua @@ -1,6 +1,8 @@ local Config = require('config') local UI = require('ui') +local kernel = _G.kernel + local aliasTab = UI.Tab { tabTitle = 'Aliases', description = 'Shell aliases', @@ -33,8 +35,12 @@ local aliasTab = UI.Tab { function aliasTab.grid:draw() self.values = { } local env = Config.load('shell') + for k in pairs(kernel.getShell().aliases()) do + kernel.getShell().clearAlias(k) + end for k,v in pairs(env.aliases) do table.insert(self.values, { alias = k, path = v }) + kernel.getShell().setAlias(k, v) end self:update() UI.Grid.draw(self) @@ -42,23 +48,23 @@ end function aliasTab:eventHandler(event) if event.type == 'delete_alias' then - local env = Config.load('shell') + local env = Config.load('shell', { aliases = { } }) env.aliases[self.grid:getSelected().alias] = nil + Config.update('shell', env) self.grid:setIndex(self.grid:getIndex()) self.grid:draw() - Config.update('shell', env) - self:emit({ type = 'success_message', message = 'reboot to take effect' }) + self:emit({ type = 'success_message', message = 'Aliases updated' }) return true elseif event.type == 'new_alias' then - local env = Config.load('shell') + local env = Config.load('shell', { aliases = { } }) env.aliases[self.alias.value] = self.path.value + Config.update('shell', env) self.alias:reset() self.path:reset() self:draw() self:setFocus(self.alias) - Config.update('shell', env) - self:emit({ type = 'success_message', message = 'reboot to take effect' }) + self:emit({ type = 'success_message', message = 'Aliases updated' }) return true end end diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index d80474c..a42e59e 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -287,6 +287,7 @@ function fs.mount(path, fstype, ...) tp.nodes[targetName] = node end end +_debug(node) return node end diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua new file mode 100644 index 0000000..8a65f36 --- /dev/null +++ b/sys/init/3.relay.lua @@ -0,0 +1,27 @@ +local device = _G.device +local kernel = _G.kernel + +local function register(v) + if v and v.isWireless and v.getMetadata and v.getNamesRemote then + v.children = { } + for _, name in pairs(v.getNamesRemote()) do + local dev = v.getMethodsRemote(name) + if dev then + dev.name = name + dev.side = name + dev.type = v.getTypeRemote(name) + device[name] = dev + table.insert(v._children, dev) + end + end + end +end + +for _,v in pairs(device) do + register(v) +end + +-- register oc devices as peripherals +kernel.hook('device_attach', function(_, eventData) + register(device[eventData[2]]) +end) diff --git a/sys/init/7.multishell.lua b/sys/init/7.multishell.lua index 9d48ce0..d9a2536 100644 --- a/sys/init/7.multishell.lua +++ b/sys/init/7.multishell.lua @@ -123,23 +123,25 @@ function multishell.openTab(tab) local routine = kernel.newRoutine(tab) routine.co = coroutine.create(function() - local result, err, stacktrace + local result, err if tab.fn then result, err = Util.runFunction(routine.env, tab.fn, table.unpack(tab.args or { } )) elseif tab.path then - result, err, stacktrace = xprun(routine.env, tab.path, table.unpack(tab.args or { } )) + result, err = xprun(routine.env, tab.path, table.unpack(tab.args or { } )) else err = 'multishell: invalid tab' end - if not result and err and err ~= 'Terminated' then - if err then + if not result and err and err ~= 'Terminated' or (err and err ~= 0) then + tab.terminal.setBackgroundColor(colors.black) + if tonumber(err) then + tab.terminal.setTextColor(colors.orange) + print('Process exited with error code: ' .. err) + elseif err then printError(tostring(err)) - if stacktrace then -- alternatively log stack to _debug - --print('\n' .. stacktrace) - end end + tab.terminal.setTextColor(colors.white) print('\nPress enter to close') routine.isDead = true routine.hidden = false From 9413785248ff7b954c043e514c3692b457a52a4b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 7 Apr 2019 11:18:54 -0400 Subject: [PATCH 125/231] oops --- sys/init/2.vfs.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index a42e59e..d80474c 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -287,7 +287,6 @@ function fs.mount(path, fstype, ...) tp.nodes[targetName] = node end end -_debug(node) return node end From 70733ab4f2d6171925ad2a9725dab09160966072 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 8 Apr 2019 09:30:47 -0400 Subject: [PATCH 126/231] network group wip + virtual dirs + better trust --- sys/apis/security.lua | 16 ++++++---------- sys/apis/socket.lua | 35 ++++++++++++++++++++++++----------- sys/apps/Welcome.lua | 24 +++++++++++++++++++----- sys/apps/network/snmp.lua | 1 + sys/apps/telnet.lua | 17 ++++++++++++++--- sys/apps/vnc.lua | 11 ++++++++++- sys/init/2.vfs.lua | 9 +++++++++ sys/init/5.network.lua | 10 +++++++++- 8 files changed, 92 insertions(+), 31 deletions(-) diff --git a/sys/apis/security.lua b/sys/apis/security.lua index 24d24d4..ab0fea8 100644 --- a/sys/apis/security.lua +++ b/sys/apis/security.lua @@ -1,20 +1,18 @@ local Config = require('config') -local config = { } - local Security = { } function Security.verifyPassword(password) - Config.load('os', config) - return config.password and password == config.password + local current = Security.getPassword() + return current and password == current end function Security.hasPassword() - return not not config.password + return not not Security.getPassword() end function Security.getSecretKey() - Config.load('os', config) + local config = Config.load('os') if not config.secretKey then config.secretKey = math.random(100000, 999999) Config.update('os', config) @@ -23,7 +21,6 @@ function Security.getSecretKey() end function Security.getPublicKey() - local exchange = { base = 11, primeMod = 625210769 @@ -47,14 +44,13 @@ function Security.getPublicKey() end function Security.updatePassword(password) - Config.load('os', config) + local config = Config.load('os') config.password = password Config.update('os', config) end function Security.getPassword() - Config.load('os', config) - return config.password + return Config.load('os').password end return Security diff --git a/sys/apis/socket.lua b/sys/apis/socket.lua index 75ae3a3..fd73abd 100644 --- a/sys/apis/socket.lua +++ b/sys/apis/socket.lua @@ -105,7 +105,7 @@ end function Socket.connect(host, port) if not device.wireless_modem then - return false, 'Wireless modem not found' + return false, 'Wireless modem not found', 'NOMODEM' end local socket = newSocket(host == os.getComputerID()) @@ -138,15 +138,19 @@ function Socket.connect(host, port) _G.transport.open(socket) return socket + elseif msg.type == 'NOPASS' then + socket:close() + return false, 'Password not set on target', 'NOPASS' + elseif msg.type == 'REJE' then socket:close() - return false, 'Password not set on target or not trusted' + return false, 'Trust not established', 'NOTRUST' end end until e == 'timer' and id == timerId socket:close() - return false, 'Connection timed out' + return false, 'Connection timed out', 'TIMEOUT' end local function trusted(msg, port) @@ -190,7 +194,15 @@ function Socket.server(port) socket.wseq = msg.wseq socket.rseq = msg.rseq - if trusted(msg, port) then + if not Security.hasPassword() then + socket.transmit(socket.dport, socket.sport, { + type = 'NOPASS', + dhost = socket.dhost, + shost = socket.shost, + }) + socket:close() + + elseif trusted(msg, port) then socket.connected = true socket.transmit(socket.dport, socket.sport, { type = 'CONN', @@ -201,14 +213,15 @@ function Socket.server(port) _G.transport.open(socket) return socket - end - socket.transmit(socket.dport, socket.sport, { - type = 'REJE', - dhost = socket.dhost, - shost = socket.shost, - }) - socket:close() + else + socket.transmit(socket.dport, socket.sport, { + type = 'REJE', + dhost = socket.dhost, + shost = socket.shost, + }) + socket:close() + end end end end diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 0d190b9..c5d5e41 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -1,4 +1,5 @@ local Ansi = require('ansi') +local Config = require('config') local Security = require('security') local SHA1 = require('sha1') local UI = require('ui') @@ -53,7 +54,7 @@ local page = UI.Page { }, password = UI.WizardPage { index = 3, - labelText = UI.Text { + passwordLabel = UI.Text { x = 3, y = 2, value = 'Password' }, @@ -62,14 +63,22 @@ local page = UI.Page { limit = 32, mask = true, shadowText = 'password', - accelerators = { - enter = 'new_password', - }, }, +--[[ + groupLabel = UI.Text { + x = 3, y = 3, + value = 'Group' + }, + group = UI.TextEntry { + x = 12, ex = -3, y = 3, + limit = 32, + shadowText = 'network group', + }, +]] intro = UI.TextArea { textColor = colors.yellow, inactive = true, - x = 3, ex = -3, y = 4, ey = -3, + x = 3, ex = -3, y = 5, ey = -3, value = string.format(passwordIntro, Ansi.white), }, }, @@ -101,6 +110,11 @@ function page.wizard.pages.password:validate() if #self.newPass.value > 0 then Security.updatePassword(SHA1.sha1(self.newPass.value)) end + if #self.group.value > 0 then + local config = Config.load('os') + config.group = self.group.value + Config.update('os', config) + end return true end diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index 07ccc0a..aa25151 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -141,6 +141,7 @@ local function sendInfo() infoTimer = os.clock() info.label = os.getComputerLabel() info.uptime = math.floor(os.clock()) + info.group = network.getGroup() if turtle then info.fuel = turtle.getFuelLevel() info.status = turtle.getStatus() diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 8a736a3..3f5dd84 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -24,10 +24,21 @@ if multishell then multishell.setTitle(multishell.getCurrent(), 'Telnet ' .. remoteId) end -local socket, msg = Socket.connect(remoteId, 23) +local socket, msg, reason -if not socket then - error(msg) +while true do + socket, msg, reason = Socket.connect(remoteId, 23) + + if socket then + break + elseif reason ~= 'NOTRUST' then + error(msg) + end + + local s, m = shell.run('trust ' .. remoteId) + if not s then + error(m) + end end local ct = Util.shallowCopy(term.current()) diff --git a/sys/apps/vnc.lua b/sys/apps/vnc.lua index 0540125..b57df3b 100644 --- a/sys/apps/vnc.lua +++ b/sys/apps/vnc.lua @@ -6,6 +6,7 @@ local Util = require('util') local colors = _G.colors local multishell = _ENV.multishell local os = _G.os +local shell = _ENV.shell local term = _G.term local remoteId @@ -26,7 +27,15 @@ if multishell then end local function connect() - local socket, msg = Socket.connect(remoteId, 5900) + local socket, msg, reason = Socket.connect(remoteId, 5900) + + if reason == 'NOTRUST' then + local s, m = shell.run('trust ' .. remoteId) + if not s then + return s, m + end + socket, msg = Socket.connect(remoteId, 5900) + end if not socket then return false, msg diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index d80474c..b32f6b4 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -5,6 +5,8 @@ end _G.requireInjector(_ENV) local Util = require('util') +-- TODO: support getDrive for virtual nodes + local fs = _G.fs fs.native = Util.shallowCopy(fs) @@ -88,6 +90,13 @@ function nativefs.exists(node, dir) return fs.native.exists(dir) end +function nativefs.getDrive(node, dir) + if node.mountPoint == dir then + return fs.native.getDrive(dir) or 'virt' + end + return fs.native.getDrive(dir) +end + function nativefs.delete(node, dir) if node.mountPoint == dir then fs.unmount(dir) diff --git a/sys/init/5.network.lua b/sys/init/5.network.lua index 417126e..bd97122 100644 --- a/sys/init/5.network.lua +++ b/sys/init/5.network.lua @@ -6,7 +6,15 @@ local device = _G.device local kernel = _G.kernel local os = _G.os -_G.network = { } +do + local config = Config.load('os') + _G.network = setmetatable({ }, { __index = { + getGroup = function() return config.group end, + setGroup = function(name) + config.group = name + end + }}) +end local function startNetwork() kernel.run({ From c633e935f81ad4042917778ada0b102e3a1182d0 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 8 Apr 2019 10:23:04 -0400 Subject: [PATCH 127/231] network group wip --- sys/apps/Welcome.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index c5d5e41..e735840 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -110,11 +110,13 @@ function page.wizard.pages.password:validate() if #self.newPass.value > 0 then Security.updatePassword(SHA1.sha1(self.newPass.value)) end + --[[ if #self.group.value > 0 then local config = Config.load('os') config.group = self.group.value Config.update('os', config) end + ]] return true end From f011e7b14f60b66f5610a3eb5444dd320db861e4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 11 Apr 2019 08:41:23 -0400 Subject: [PATCH 128/231] pastebin rewrite --- sys/apis/http/pastebin.lua | 150 +++++++++++++++++++++++++++++++++++++ sys/apis/pastebin.lua | 146 ------------------------------------ sys/apps/Files.lua | 12 +-- sys/apps/pastebin.lua | 34 ++++++--- sys/apps/telnet.lua | 1 + sys/autorun/apps.lua | 3 - 6 files changed, 179 insertions(+), 167 deletions(-) create mode 100644 sys/apis/http/pastebin.lua delete mode 100644 sys/apis/pastebin.lua diff --git a/sys/apis/http/pastebin.lua b/sys/apis/http/pastebin.lua new file mode 100644 index 0000000..54f5b24 --- /dev/null +++ b/sys/apis/http/pastebin.lua @@ -0,0 +1,150 @@ + +--- Attempts to guess the pastebin ID from the given code or URL +local function extractId(paste) + local patterns = { + "^([%a%d]+)$", + "^https?://pastebin.com/([%a%d]+)$", + "^pastebin.com/([%a%d]+)$", + "^https?://pastebin.com/raw/([%a%d]+)$", + "^pastebin.com/raw/([%a%d]+)$", + } + + for i = 1, #patterns do + local code = paste:match( patterns[i] ) + if code then return code end + end + + return nil +end + +function download(url) + if type( url ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( url ) .. ")", 2 ) + end + + if not http then + return false, "Pastebin requires http API" + end + + local paste = extractId( url ) + if not paste then + return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." + end + + -- Add a cache buster so that spam protection is re-checked + local cacheBuster = ("%x"):format(math.random(0, 2^30)) + local response, err = http.get( + "https://pastebin.com/raw/"..textutils.urlEncode( paste ).."?cb="..cacheBuster + ) + + if not response then + return response, err + end + + -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html + local headers = response.getResponseHeaders() + if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then + return false, "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) + end + + local sResponse = response.readAll() + response.close() + return sResponse +end + +local function put(sPath) + if type( sPath ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) + end + + if not http then + return false, "Pastebin requires http API" + end + + -- Upload a file to pastebin.com + -- Determine file to upload + if not fs.exists( sPath ) or fs.isDir( sPath ) then + return false, "No such file" + end + + -- Read in the file + local sName = fs.getName( sPath ) + local file = fs.open( sPath, "r" ) + local sText = file.readAll() + file.close() + + -- POST the contents to pastebin + local key = "0ec2eb25b6166c0c27a394ae118ad829" + local response = http.post( + "https://pastebin.com/api/api_post.php", + "api_option=paste&".. + "api_dev_key="..key.."&".. + "api_paste_format=lua&".. + "api_paste_name="..textutils.urlEncode(sName).."&".. + "api_paste_code="..textutils.urlEncode(sText) + ) + + if response then + local sResponse = response.readAll() + response.close() + + return string.match( sResponse, "[^/]+$" ) + end + return false, "Failed." +end + +local function get(sCode, sPath) + if type( sCode ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) + end + + if type( sPath ) ~= "string" then + error( "bad argument #2 (expected string, got " .. type( sPath ) .. ")", 2 ) + end + + if not http then + return false, "Pastebin requires http API" + end + + if fs.exists( sPath ) then + return false, "File already exists" + end + + -- GET the contents from pastebin + local res, msg = download(sCode) + if not res then + return res, msg + end + + local file = fs.open( sPath, "w" ) + file.write( res ) + file.close() + + return sPath +end + +local function run(sCode, ...) + if not http then + return false, "Pastebin requires http API" + end + + if type( sCode ) ~= "string" then + error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) + end + + local res, msg = download(sCode) + if not res then + return res, msg + end + local func, err = load(res, sCode, "t", _ENV) + if not func then + return func, err + end + return pcall(func, ...) +end + +return { + get = get, + put = put, + run = run, +} \ No newline at end of file diff --git a/sys/apis/pastebin.lua b/sys/apis/pastebin.lua deleted file mode 100644 index d78c10c..0000000 --- a/sys/apis/pastebin.lua +++ /dev/null @@ -1,146 +0,0 @@ - ---- Attempts to guess the pastebin ID from the given code or URL -local function extractId(paste) - local patterns = { - "^([%a%d]+)$", - "^https?://pastebin.com/([%a%d]+)$", - "^pastebin.com/([%a%d]+)$", - "^https?://pastebin.com/raw/([%a%d]+)$", - "^pastebin.com/raw/([%a%d]+)$", - } - - for i = 1, #patterns do - local code = paste:match( patterns[i] ) - if code then return code end - end - - return nil -end - -function download(url) - if not http then - return false, "Pastebin requires http API" - end - - if type( url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( url ) .. ")", 2 ) - end - - local paste = extractId( url ) - if not paste then - return false, "Invalid pastebin code." - end - - -- Add a cache buster so that spam protection is re-checked - local cacheBuster = ("%x"):format(math.random(0, 2^30)) - local response, err = http.get( - "https://pastebin.com/raw/"..textutils.urlEncode( paste ).."?cb="..cacheBuster - ) - - if response then - -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html - local headers = response.getResponseHeaders() - if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then - return false, "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) - end - - local sResponse = response.readAll() - response.close() - return true, sResponse - end - - return false, err -end - -function put(sPath) - if not http then - return false, "Pastebin requires http API" - end - - if type( sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end - - -- Upload a file to pastebin.com - -- Determine file to upload - if not fs.exists( sPath ) or fs.isDir( sPath ) then - return false, "No such file" - end - - -- Read in the file - local sName = fs.getName( sPath ) - local file = fs.open( sPath, "r" ) - local sText = file.readAll() - file.close() - - -- POST the contents to pastebin - local key = "0ec2eb25b6166c0c27a394ae118ad829" - local response = http.post( - "https://pastebin.com/api/api_post.php", - "api_option=paste&".. - "api_dev_key="..key.."&".. - "api_paste_format=lua&".. - "api_paste_name="..textutils.urlEncode(sName).."&".. - "api_paste_code="..textutils.urlEncode(sText) - ) - - if response then - local sResponse = response.readAll() - response.close() - - local sCode = string.match( sResponse, "[^/]+$" ) - - return true, sCode - end - return false, "Failed." -end - -function get(sCode, sPath) - if not http then - return false, "Pastebin requires http API" - end - - if type( sCode ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) - end - - if type( sPath ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sPath ) .. ")", 2 ) - end - - if fs.exists( sPath ) then - return false, "File already exists" - end - - -- GET the contents from pastebin - local res, msg = download(sCode) - if not res then - return res, msg - end - - local file = fs.open( sPath, "w" ) - file.write( msg ) - file.close() - - return true -end - -function run(sCode, ...) - if not http then - return false, "Pastebin requires http API" - end - - if type( sCode ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) - end - - local res, msg = download(sCode) - if not res then - return res, msg - end - local func, err = load(msg, sCode, "t", _ENV) - if not func then - return func, err - end - return pcall(func, ...) -end diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 855aaa1..0e40ec5 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -1,5 +1,6 @@ local Config = require('config') local Event = require('event') +local pastebin = require('http.pastebin') local UI = require('ui') local Util = require('util') @@ -7,7 +8,6 @@ local colors = _G.colors local fs = _G.fs local multishell = _ENV.multishell local os = _G.os -local pastebin = _G.pastebin local shell = _ENV.shell local FILE = 1 @@ -41,10 +41,10 @@ local Browser = UI.Page { buttons = { { text = '^-', event = 'updir' }, { text = 'File', dropdown = { - { text = 'Run', event = 'run', flags = FILE }, - { text = 'Edit e', event = 'edit', flags = FILE }, - { text = 'Cloud edit c', event = 'cedit', flags = FILE }, - { text = 'Pastebin put p', event = 'cedit', flags = FILE }, + { text = 'Run', event = 'run', flags = FILE }, + { text = 'Edit e', event = 'edit', flags = FILE }, + { text = 'Cloud edit c', event = 'cedit', flags = FILE }, + { text = 'Pastebin put p', event = 'pastebin', flags = FILE }, { text = 'Shell s', event = 'shell' }, { spacer = true }, { text = 'Quit q', event = 'quit' }, @@ -367,7 +367,7 @@ function Browser:eventHandler(event) local s, m = pastebin.put(file.fullName) if s then os.queueEvent('clipboard_copy', s) - self.notification:success(string.format('Uploaded as %s', m), 0) + self.notification:success(string.format('Uploaded as %s', s), 0) else self.notification:error(m) end diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua index 66057ca..6c4df9e 100644 --- a/sys/apps/pastebin.lua +++ b/sys/apps/pastebin.lua @@ -18,6 +18,8 @@ if not http then return end +local pastebin = require('http.pastebin') + local sCommand = tArgs[1] if sCommand == "put" then -- Upload a file to pastebin.com @@ -29,14 +31,16 @@ if sCommand == "put" then return end - local success, msg = pastebin.put(sFile) + print( "Connecting to pastebin.com... " ) - if success then + local resp, msg = pastebin.put(sFile) + + if resp then print( "Uploaded as "..msg ) - print( "Run \"pastebin get "..msg.."\" to download anywhere" ) + print( "Run \"pastebin get "..resp.."\" to download anywhere" ) else - print( msg ) + printError( msg ) end elseif sCommand == "get" then @@ -46,30 +50,36 @@ elseif sCommand == "get" then return end + print( "Connecting to pastebin.com... " ) + -- Determine file to download local sCode = tArgs[2] local sFile = tArgs[3] local sPath = shell.resolve( sFile ) if fs.exists( sPath ) then - print( "File already exists" ) + printError( "File already exists" ) return end - local success, msg = pastebin.get(sCode, sPath) + local resp, msg = pastebin.get(sCode, sPath) - if success then - print( "Downloaded as "..sFile ) + if resp then + print( "Downloaded as "..resp ) else - print(msg) + printError( msg ) end + elseif sCommand == "run" then local sCode = tArgs[2] - local success, msg = pastebin.run(sCode, table.unpack(tArgs, 3)) - if not success then - print(msg) + print( "Connecting to pastebin.com... " ) + + local resp, msg = pastebin.run(sCode, table.unpack(tArgs, 3)) + if not resp then + printError( msg ) end else + printUsage() return end diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 3f5dd84..40a1134 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -6,6 +6,7 @@ local Util = require('util') local multishell = _ENV.multishell local os = _G.os local read = _G.read +local shell = _ENV.shell local term = _G.term local args = { ... } diff --git a/sys/autorun/apps.lua b/sys/autorun/apps.lua index 97bec3e..c66656b 100644 --- a/sys/autorun/apps.lua +++ b/sys/autorun/apps.lua @@ -2,6 +2,3 @@ fs.mount('sys/apps/pain.lua', 'urlfs', 'http://pastebin.com/raw/wJQ7jav0') fs.mount('sys/apps/update.lua', 'urlfs', 'http://pastebin.com/raw/UzGHLbNC') fs.mount('sys/apps/Enchat.lua', 'urlfs', 'https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua') fs.mount('sys/apps/cloud.lua', 'urlfs', 'https://cloud-catcher.squiddev.cc/cloud.lua') - --- baking this in before a PR to cc:tweaked -os.loadAPI('sys/apis/pastebin.lua') \ No newline at end of file From a77d55e33f3bd6c5564c7472ad4809f8d4233866 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 12 Apr 2019 08:33:41 -0400 Subject: [PATCH 129/231] pastebin rework round 3 --- sys/apis/http/pastebin.lua | 222 +++++++++++++++++-------------------- sys/apps/pastebin.lua | 55 ++++++--- sys/help/pastebin | 15 +++ 3 files changed, 157 insertions(+), 135 deletions(-) create mode 100644 sys/help/pastebin diff --git a/sys/apis/http/pastebin.lua b/sys/apis/http/pastebin.lua index 54f5b24..343a7db 100644 --- a/sys/apis/http/pastebin.lua +++ b/sys/apis/http/pastebin.lua @@ -1,150 +1,128 @@ +--- Parse the pastebin code from the given code or URL +local function parseCode(paste) + local patterns = { + "^([%a%d]+)$", + "^https?://pastebin.com/([%a%d]+)$", + "^pastebin.com/([%a%d]+)$", + "^https?://pastebin.com/raw/([%a%d]+)$", + "^pastebin.com/raw/([%a%d]+)$", + } ---- Attempts to guess the pastebin ID from the given code or URL -local function extractId(paste) - local patterns = { - "^([%a%d]+)$", - "^https?://pastebin.com/([%a%d]+)$", - "^pastebin.com/([%a%d]+)$", - "^https?://pastebin.com/raw/([%a%d]+)$", - "^pastebin.com/raw/([%a%d]+)$", - } + for i = 1, #patterns do + local code = paste:match(patterns[i]) + if code then + return code + end + end - for i = 1, #patterns do - local code = paste:match( patterns[i] ) - if code then return code end - end - - return nil + return nil end -function download(url) - if type( url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( url ) .. ")", 2 ) - end +-- Download the contents of a paste +local function download(url) + if type(url) ~= "string" then + error("bad argument #1 (expected string, got " .. type(url) .. ")", 2) + end - if not http then - return false, "Pastebin requires http API" - end + if not http then + return false, "Pastebin requires http API" + end - local paste = extractId( url ) - if not paste then - return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." - end + -- Add a cache buster so that spam protection is re-checked + local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30)) + local response, err = http.get( + "https://pastebin.com/raw/" .. textutils.urlEncode(paste) .. "?cb=" .. cacheBuster + ) - -- Add a cache buster so that spam protection is re-checked - local cacheBuster = ("%x"):format(math.random(0, 2^30)) - local response, err = http.get( - "https://pastebin.com/raw/"..textutils.urlEncode( paste ).."?cb="..cacheBuster - ) + if not response then + return response, err + end - if not response then - return response, err - end + -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html + local headers = response.getResponseHeaders() + if not headers["Content-Type"] or not headers["Content-Type"]:find("^text/plain") then + return false, "Pastebin blocked due to spam protection" + end - -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html - local headers = response.getResponseHeaders() - if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then - return false, "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) - end - - local sResponse = response.readAll() - response.close() - return sResponse + local contents = response.readAll() + response.close() + return contents end -local function put(sPath) - if type( sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end +-- Upload text to pastebin +local function upload(name, text) + if not http then + return false, "Pastebin requires http API" + end - if not http then - return false, "Pastebin requires http API" - end + -- POST the contents to pastebin + local key = "0ec2eb25b6166c0c27a394ae118ad829" + local response = http.post( + "https://pastebin.com/api/api_post.php", + "api_option=paste&" .. + "api_dev_key=" .. key .. "&" .. + "api_paste_format=lua&" .. + "api_paste_name=" .. textutils.urlEncode(name) .. "&" .. + "api_paste_code=" .. textutils.urlEncode(text) + ) - -- Upload a file to pastebin.com - -- Determine file to upload - if not fs.exists( sPath ) or fs.isDir( sPath ) then - return false, "No such file" - end + if not response then + return false, "Failed." + end - -- Read in the file - local sName = fs.getName( sPath ) - local file = fs.open( sPath, "r" ) - local sText = file.readAll() - file.close() + local contents = response.readAll() + response.close() - -- POST the contents to pastebin - local key = "0ec2eb25b6166c0c27a394ae118ad829" - local response = http.post( - "https://pastebin.com/api/api_post.php", - "api_option=paste&".. - "api_dev_key="..key.."&".. - "api_paste_format=lua&".. - "api_paste_name="..textutils.urlEncode(sName).."&".. - "api_paste_code="..textutils.urlEncode(sText) - ) - - if response then - local sResponse = response.readAll() - response.close() - - return string.match( sResponse, "[^/]+$" ) - end - return false, "Failed." + return string.match(contents, "[^/]+$") end -local function get(sCode, sPath) - if type( sCode ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) - end +-- Download the contents to a file from pastebin +local function get(code, path) + if type(code) ~= "string" then + error( "bad argument #1 (expected string, got " .. type(code) .. ")", 2) + end - if type( sPath ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sPath ) .. ")", 2 ) - end + if type(path) ~= "string" then + error("bad argument #2 (expected string, got " .. type(path) .. ")", 2) + end - if not http then - return false, "Pastebin requires http API" - end + local res, msg = download(code) + if not res then + return res, msg + end - if fs.exists( sPath ) then - return false, "File already exists" - end + local file = fs.open(path, "w") + file.write(res) + file.close() - -- GET the contents from pastebin - local res, msg = download(sCode) - if not res then - return res, msg - end - - local file = fs.open( sPath, "w" ) - file.write( res ) - file.close() - - return sPath + return true end -local function run(sCode, ...) - if not http then - return false, "Pastebin requires http API" - end +-- Upload a file to pastebin.com +local function put(path) + if type(path) ~= "string" then + error("bad argument #1 (expected string, got " .. type(path) .. ")", 2) + end - if type( sCode ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) - end + -- Determine file to upload + if not fs.exists(path) or fs.isDir(path) then + return false, "No such file" + end - local res, msg = download(sCode) - if not res then - return res, msg - end - local func, err = load(res, sCode, "t", _ENV) - if not func then - return func, err - end - return pcall(func, ...) + -- Read in the file + local name = fs.getName(path) + local file = fs.open(path, "r") + local text = file.readAll() + file.close() + + return upload(name, text) end return { - get = get, - put = put, - run = run, -} \ No newline at end of file + download = download, + upload = upload, + get = get, + put = put, + parseCode = parseCode, +} + diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua index 6c4df9e..d2ee048 100644 --- a/sys/apps/pastebin.lua +++ b/sys/apps/pastebin.lua @@ -1,4 +1,3 @@ - local function printUsage() print( "Usages:" ) print( "pastebin put " ) @@ -6,12 +5,6 @@ local function printUsage() print( "pastebin run " ) end -local tArgs = { ... } -if #tArgs < 2 then - printUsage() - return -end - if not http then printError( "Pastebin requires http API" ) printError( "Set http_enable to true in ComputerCraft.cfg" ) @@ -20,9 +13,17 @@ end local pastebin = require('http.pastebin') +local tArgs = { ... } local sCommand = tArgs[1] + if sCommand == "put" then -- Upload a file to pastebin.com + + if #tArgs < 2 then + printUsage() + return + end + -- Determine file to upload local sFile = tArgs[2] local sPath = shell.resolve( sFile ) @@ -45,15 +46,18 @@ if sCommand == "put" then elseif sCommand == "get" then -- Download a file from pastebin.com + if #tArgs < 3 then printUsage() return end - print( "Connecting to pastebin.com... " ) + local sCode = pastebin.parseCode(tArgs[2]) + if not sCode then + return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." + end -- Determine file to download - local sCode = tArgs[2] local sFile = tArgs[3] local sPath = shell.resolve( sFile ) if fs.exists( sPath ) then @@ -61,21 +65,45 @@ elseif sCommand == "get" then return end + print( "Connecting to pastebin.com... " ) + local resp, msg = pastebin.get(sCode, sPath) if resp then - print( "Downloaded as "..resp ) + print( "Downloaded as " .. sPath ) else printError( msg ) end elseif sCommand == "run" then - local sCode = tArgs[2] + -- Download and run a file from pastebin.com + + if #tArgs < 2 then + printUsage() + return + end + + local sCode = pastebin.parseCode(tArgs[2]) + if not sCode then + return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." + end print( "Connecting to pastebin.com... " ) - local resp, msg = pastebin.run(sCode, table.unpack(tArgs, 3)) - if not resp then + local res, msg = pastebin.download(sCode) + if not res then + printError( msg ) + return res, msg + end + + res, msg = load(res, sCode, "t", _ENV) + if not res then + printError( msg ) + return res, msg + end + + res, msg = pcall(res, table.unpack(tArgs, 3)) + if not res then printError( msg ) end else @@ -83,3 +111,4 @@ else printUsage() return end + diff --git a/sys/help/pastebin b/sys/help/pastebin new file mode 100644 index 0000000..57e4d0a --- /dev/null +++ b/sys/help/pastebin @@ -0,0 +1,15 @@ +pastebin is a program for uploading files to and downloading files from pastebin.com. This is useful for sharing programs with other players. +The HTTP API must be enabled in ComputerCraft.cfg to use this program. + +ex: +"pastebin put foo" will upload the file "foo" to pastebin.com, and print the URL. +"pastebin get xq5gc7LB foo" will download the file from the URL http://pastebin.com/xq5gc7LB, and save it as "foo". +"pastebin run CxaWmPrX" will download the file from the URL http://pastebin.com/CxaWmPrX, and immediately run it. + +Functions in the pastebin API: +pastebin.get( code, filepath ) +pastebin.put( filepath ) +pastebin.download( code ) +pastebin.upload( pastename, text ) +pastebin.parseCode( code ) + From 8220ed106679cd69d49e3d736b7bf0d031db009f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 12 Apr 2019 08:55:38 -0400 Subject: [PATCH 130/231] pastebin oops --- sys/apis/http/pastebin.lua | 6 +++--- sys/apps/pastebin.lua | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sys/apis/http/pastebin.lua b/sys/apis/http/pastebin.lua index 343a7db..89676ba 100644 --- a/sys/apis/http/pastebin.lua +++ b/sys/apis/http/pastebin.lua @@ -19,9 +19,9 @@ local function parseCode(paste) end -- Download the contents of a paste -local function download(url) +local function download(code) if type(url) ~= "string" then - error("bad argument #1 (expected string, got " .. type(url) .. ")", 2) + error("bad argument #1 (expected string, got " .. type(code) .. ")", 2) end if not http then @@ -31,7 +31,7 @@ local function download(url) -- Add a cache buster so that spam protection is re-checked local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30)) local response, err = http.get( - "https://pastebin.com/raw/" .. textutils.urlEncode(paste) .. "?cb=" .. cacheBuster + "https://pastebin.com/raw/" .. textutils.urlEncode(code) .. "?cb=" .. cacheBuster ) if not response then diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua index d2ee048..cff33db 100644 --- a/sys/apps/pastebin.lua +++ b/sys/apps/pastebin.lua @@ -34,10 +34,10 @@ if sCommand == "put" then print( "Connecting to pastebin.com... " ) - local resp, msg = pastebin.put(sFile) + local resp, msg = pastebin.put(sPath) if resp then - print( "Uploaded as "..msg ) + print( "Uploaded as " .. resp ) print( "Run \"pastebin get "..resp.."\" to download anywhere" ) else From 263a32094c393913e5bee149c38d65089983c5d7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 12 Apr 2019 09:31:28 -0400 Subject: [PATCH 131/231] pastebin oops --- sys/apis/http/pastebin.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apis/http/pastebin.lua b/sys/apis/http/pastebin.lua index 89676ba..a6cf60b 100644 --- a/sys/apis/http/pastebin.lua +++ b/sys/apis/http/pastebin.lua @@ -20,7 +20,7 @@ end -- Download the contents of a paste local function download(code) - if type(url) ~= "string" then + if type(code) ~= "string" then error("bad argument #1 (expected string, got " .. type(code) .. ")", 2) end From e1fd4be3a53137d347c2f819bd53231c1ff71b7d Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 14 Apr 2019 10:04:22 -0400 Subject: [PATCH 132/231] icon update --- sys/apps/Overview.lua | 6 +- sys/apps/pastebin.lua | 130 +++++++++++++++++++++--------------------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index eba0bfd..1c0fe01 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -22,9 +22,9 @@ if not _ENV.multishell then end local REGISTRY_DIR = 'usr/.registry' -local DEFAULT_ICON = NFT.parse("\03180\031711\03180\ -\031800\03171\03180\ -\03171\031800\03171") +local DEFAULT_ICON = NFT.parse("\0308\0317\153\153\153\153\153\ +\0307\0318\153\153\153\153\153\ +\0308\0317\153\153\153\153\153") UI:configure('Overview', ...) diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua index cff33db..4cdc80b 100644 --- a/sys/apps/pastebin.lua +++ b/sys/apps/pastebin.lua @@ -1,14 +1,14 @@ local function printUsage() - print( "Usages:" ) - print( "pastebin put " ) - print( "pastebin get " ) - print( "pastebin run " ) + print( "Usages:" ) + print( "pastebin put " ) + print( "pastebin get " ) + print( "pastebin run " ) end if not http then - printError( "Pastebin requires http API" ) - printError( "Set http_enable to true in ComputerCraft.cfg" ) - return + printError( "Pastebin requires http API" ) + printError( "Set http_enable to true in ComputerCraft.cfg" ) + return end local pastebin = require('http.pastebin') @@ -17,98 +17,98 @@ local tArgs = { ... } local sCommand = tArgs[1] if sCommand == "put" then - -- Upload a file to pastebin.com + -- Upload a file to pastebin.com - if #tArgs < 2 then - printUsage() - return - end + if #tArgs < 2 then + printUsage() + return + end - -- Determine file to upload - local sFile = tArgs[2] - local sPath = shell.resolve( sFile ) - if not fs.exists( sPath ) or fs.isDir( sPath ) then - print( "No such file" ) - return - end + -- Determine file to upload + local sFile = tArgs[2] + local sPath = shell.resolve( sFile ) + if not fs.exists( sPath ) or fs.isDir( sPath ) then + print( "No such file" ) + return + end - print( "Connecting to pastebin.com... " ) + print( "Connecting to pastebin.com... " ) - local resp, msg = pastebin.put(sPath) + local resp, msg = pastebin.put(sPath) - if resp then - print( "Uploaded as " .. resp ) - print( "Run \"pastebin get "..resp.."\" to download anywhere" ) + if resp then + print( "Uploaded as " .. resp ) + print( "Run \"pastebin get "..resp.."\" to download anywhere" ) - else - printError( msg ) - end + else + printError( msg ) + end elseif sCommand == "get" then - -- Download a file from pastebin.com + -- Download a file from pastebin.com - if #tArgs < 3 then - printUsage() - return - end + if #tArgs < 3 then + printUsage() + return + end - local sCode = pastebin.parseCode(tArgs[2]) + local sCode = pastebin.parseCode(tArgs[2]) if not sCode then return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." - end + end - -- Determine file to download - local sFile = tArgs[3] - local sPath = shell.resolve( sFile ) - if fs.exists( sPath ) then - printError( "File already exists" ) - return - end + -- Determine file to download + local sFile = tArgs[3] + local sPath = shell.resolve( sFile ) + if fs.exists( sPath ) then + printError( "File already exists" ) + return + end - print( "Connecting to pastebin.com... " ) + print( "Connecting to pastebin.com... " ) - local resp, msg = pastebin.get(sCode, sPath) + local resp, msg = pastebin.get(sCode, sPath) - if resp then - print( "Downloaded as " .. sPath ) - else - printError( msg ) - end + if resp then + print( "Downloaded as " .. sPath ) + else + printError( msg ) + end elseif sCommand == "run" then - -- Download and run a file from pastebin.com + -- Download and run a file from pastebin.com - if #tArgs < 2 then - printUsage() - return - end + if #tArgs < 2 then + printUsage() + return + end - local sCode = pastebin.parseCode(tArgs[2]) + local sCode = pastebin.parseCode(tArgs[2]) if not sCode then return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." - end + end - print( "Connecting to pastebin.com... " ) + print( "Connecting to pastebin.com... " ) local res, msg = pastebin.download(sCode) if not res then - printError( msg ) + printError( msg ) return res, msg end - res, msg = load(res, sCode, "t", _ENV) + res, msg = load(res, sCode, "t", _ENV) if not res then - printError( msg ) + printError( msg ) return res, msg end - res, msg = pcall(res, table.unpack(tArgs, 3)) - if not res then - printError( msg ) - end + res, msg = pcall(res, table.unpack(tArgs, 3)) + if not res then + printError( msg ) + end else - printUsage() - return + printUsage() + return end From e6d1e58ce223671b7a8e0e780f5fbc84306b5f84 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 14 Apr 2019 17:44:29 -0400 Subject: [PATCH 133/231] drop dowm menus resize fix --- sys/apis/ui/components/DropMenu.lua | 11 +++++++---- sys/apps/network/proxy.lua | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sys/apis/ui/components/DropMenu.lua b/sys/apis/ui/components/DropMenu.lua index 79f1a8a..10ad096 100644 --- a/sys/apis/ui/components/DropMenu.lua +++ b/sys/apis/ui/components/DropMenu.lua @@ -10,8 +10,8 @@ UI.DropMenu.defaults = { backgroundColor = colors.white, buttonClass = 'DropMenuItem', } -function UI.DropMenu:setParent() - UI.MenuBar.setParent(self) +function UI.DropMenu:layout() + UI.MenuBar.layout(self) local maxWidth = 1 for y,child in ipairs(self.children) do @@ -31,9 +31,12 @@ function UI.DropMenu:setParent() self.height = #self.children + 1 self.width = maxWidth + 2 - self.ow = self.width - self.canvas = self:addLayer() + if not self.canvas then + self.canvas = self:addLayer() + else + self.canvas:resize(self.width, self.height) + end end function UI.DropMenu:enable() diff --git a/sys/apps/network/proxy.lua b/sys/apps/network/proxy.lua index 7e0f284..5105103 100644 --- a/sys/apps/network/proxy.lua +++ b/sys/apps/network/proxy.lua @@ -15,8 +15,8 @@ local function getProxy(path) end Event.addRoutine(function() + print('proxy: listening on port 188') while true do - print('proxy: listening on port 188') local socket = Socket.server(188) print('proxy: connection from ' .. socket.dhost) From 54660c60894af3183d1ad28fc583b056d567f8a1 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 18 Apr 2019 11:13:28 -0400 Subject: [PATCH 134/231] api change for modems --- sys/apis/peripheral.lua | 2 +- sys/init/3.relay.lua | 2 +- sys/kernel.lua | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/apis/peripheral.lua b/sys/apis/peripheral.lua index 6e73a0e..1d84c8a 100644 --- a/sys/apis/peripheral.lua +++ b/sys/apis/peripheral.lua @@ -30,7 +30,7 @@ function Peripheral.addDevice(deviceList, side) -- ptype = 'wireless_modem' -- else ptype = 'wired_modem' - if dev.getMetadata then + if dev.isAccessPoint then -- avoid open computer relays being registered -- as 'wired_modem' ptype = dev.getMetadata().name or 'wired_modem' diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua index 8a65f36..cc197cf 100644 --- a/sys/init/3.relay.lua +++ b/sys/init/3.relay.lua @@ -2,7 +2,7 @@ local device = _G.device local kernel = _G.kernel local function register(v) - if v and v.isWireless and v.getMetadata and v.getNamesRemote then + if v and v.isWireless and v.isAccessPoint and v.getNamesRemote then v.children = { } for _, name in pairs(v.getNamesRemote()) do local dev = v.getMethodsRemote(name) diff --git a/sys/kernel.lua b/sys/kernel.lua index ba092a2..a787513 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -145,6 +145,7 @@ function kernel.newRoutine(args) timestamp = os.clock(), terminal = kernel.window, window = kernel.window, + title = 'untitled', }, { __index = Routine }) Util.merge(routine, args) From 3beae64ad8556edcc881826dd22bee68bd1ccc6e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 19 Apr 2019 19:03:34 -0400 Subject: [PATCH 135/231] http binary mode --- sys/apis/util.lua | 4 ++-- sys/apps/Help.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index a15e1e2..f1f5a8d 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -484,8 +484,8 @@ function Util.loadTable(fname) end --[[ loading and running functions ]] -- -function Util.httpGet(url, headers) - local h, msg = http.get(url, headers) +function Util.httpGet(url, headers, isBinary) + local h, msg = http.get(url, headers, isBinary) if h then local contents = h.readAll() h.close() diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index b43d23a..d00c80b 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -99,5 +99,5 @@ function page:eventHandler(event) end local args = { ... } -UI:setPage(#args[1] and topicPage or page, args[1]) +UI:setPage(args[1] and topicPage or page, args[1]) UI:pullEvents() From 62a3bc1360f01d65762d1f35c0413a0f028f9d4b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 20 Apr 2019 12:34:45 -0400 Subject: [PATCH 136/231] sanitize network info a bit --- sys/apps/network/snmp.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index aa25151..ac2e8bf 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -124,6 +124,10 @@ Event.on('modem_message', function(_, _, sport, id, info, distance) network[id].distance = distance network[id].timestamp = os.clock() + if not network[id].label then + network[id].label = 'unknown' + end + if not network[id].active then network[id].active = true os.queueEvent('network_attach', network[id]) From 7749e14cadabe6a8e8d2e3db63714262d68ba2f8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 20 Apr 2019 13:48:13 -0400 Subject: [PATCH 137/231] protected network services --- sys/apps/network/proxy.lua | 68 ++++++++++++++++++++----------------- sys/apps/network/samba.lua | 7 +++- sys/apps/network/snmp.lua | 6 +++- sys/apps/network/telnet.lua | 6 +++- sys/apps/network/trust.lua | 44 ++++++++++++++---------- sys/apps/network/vnc.lua | 6 +++- 6 files changed, 83 insertions(+), 54 deletions(-) diff --git a/sys/apps/network/proxy.lua b/sys/apps/network/proxy.lua index 5105103..a90dcef 100644 --- a/sys/apps/network/proxy.lua +++ b/sys/apps/network/proxy.lua @@ -14,6 +14,36 @@ local function getProxy(path) return proxy end +local function proxyConnection(socket) + local path = socket:read(2) + if path then + local api = getProxy(path) + + if not api then + print('proxy: invalid API') + socket:close() + return + end + + local methods = { } + for k,v in pairs(api) do + if type(v) == 'function' then + table.insert(methods, k) + end + end + socket:write(methods) + + while true do + local data = socket:read() + if not data then + print('proxy: lost connection from ' .. socket.dhost) + break + end + socket:write({ api[data[1]](table.unpack(data, 2)) }) + end + end +end + Event.addRoutine(function() print('proxy: listening on port 188') while true do @@ -22,39 +52,13 @@ Event.addRoutine(function() print('proxy: connection from ' .. socket.dhost) Event.addRoutine(function() - local path = socket:read(2) - if path then - local api = getProxy(path) - - if not api then - print('proxy: invalid API') - socket:close() - return - end - - local methods = { } - for k,v in pairs(api) do - if type(v) == 'function' then - table.insert(methods, k) - end - end - socket:write(methods) - - local s, m = pcall(function() - while true do - local data = socket:read() - if not data then - print('proxy: lost connection from ' .. socket.dhost) - break - end - socket:write({ api[data[1]](table.unpack(data, 2)) }) - end - end) - if not s and m then - _G.printError(m) - end - end + local s, m = pcall(proxyConnection, socket) + print('proxy: closing connection to ' .. socket.dhost) socket:close() + if not s and m then + print('Proxy error') + _G.printError(m) + end end) end end) diff --git a/sys/apps/network/samba.lua b/sys/apps/network/samba.lua index c87c1c0..a1d5227 100644 --- a/sys/apps/network/samba.lua +++ b/sys/apps/network/samba.lua @@ -67,8 +67,13 @@ Event.addRoutine(function() Event.addRoutine(function() print('samba: connection from ' .. socket.dhost) - sambaConnection(socket) + local s, m = pcall(sambaConnection, socket) print('samba: closing connection to ' .. socket.dhost) + socket:close() + if not s and m then + print('Samba error') + _G.printError(m) + end end) end end) diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index ac2e8bf..dcc7bff 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -106,8 +106,12 @@ Event.addRoutine(function() Event.addRoutine(function() print('snmp: connection from ' .. socket.dhost) - snmpConnection(socket) + local s, m = pcall(snmpConnection, socket) print('snmp: closing connection to ' .. socket.dhost) + if not s and m then + print('snmp error') + _G.printError(m) + end end) end end) diff --git a/sys/apps/network/telnet.lua b/sys/apps/network/telnet.lua index e840a6e..a396570 100644 --- a/sys/apps/network/telnet.lua +++ b/sys/apps/network/telnet.lua @@ -76,7 +76,11 @@ Event.addRoutine(function() print('telnet: connection from ' .. socket.dhost) Event.addRoutine(function() - telnetHost(socket) + local s, m = pcall(telnetHost, socket) + if not s and m then + print('Telnet error') + _G.printError(m) + end end) end end) diff --git a/sys/apps/network/trust.lua b/sys/apps/network/trust.lua index 03ed4e8..9d12c3a 100644 --- a/sys/apps/network/trust.lua +++ b/sys/apps/network/trust.lua @@ -4,6 +4,27 @@ local Security = require('security') local Socket = require('socket') local Util = require('util') +local function trustConnection(socket) + local data = socket:read(2) + if data then + local password = Security.getPassword() + if not password then + socket:write({ msg = 'No password has been set' }) + else + data = Crypto.decrypt(data, password) + if data and data.pk and data.dh == socket.dhost then + local trustList = Util.readTable('usr/.known_hosts') or { } + trustList[data.dh] = data.pk + Util.writeTable('usr/.known_hosts', trustList) + + socket:write({ success = true, msg = 'Trust accepted' }) + else + socket:write({ msg = 'Invalid password' }) + end + end + end +end + Event.addRoutine(function() print('trust: listening on port 19') @@ -12,24 +33,11 @@ Event.addRoutine(function() print('trust: connection from ' .. socket.dhost) - local data = socket:read(2) - if data then - local password = Security.getPassword() - if not password then - socket:write({ msg = 'No password has been set' }) - else - data = Crypto.decrypt(data, password) - if data and data.pk and data.dh == socket.dhost then - local trustList = Util.readTable('usr/.known_hosts') or { } - trustList[data.dh] = data.pk - Util.writeTable('usr/.known_hosts', trustList) - - socket:write({ success = true, msg = 'Trust accepted' }) - else - socket:write({ msg = 'Invalid password' }) - end - end - end + local s, m = pcall(trustConnection, socket) socket:close() + if not s and m then + print('Trust error') + _G.printError(m) + end end end) diff --git a/sys/apps/network/vnc.lua b/sys/apps/network/vnc.lua index 7c4febc..779a75d 100644 --- a/sys/apps/network/vnc.lua +++ b/sys/apps/network/vnc.lua @@ -63,7 +63,11 @@ Event.addRoutine(function() -- no new process - only 1 connection allowed -- due to term size issues - vncHost(socket) + local s, m = pcall(vncHost, socket) socket:close() + if not s and m then + print('vnc error') + _G.printError(m) + end end end) From 43a6019b9f32eb4810ea4871ad35ef849c97e14d Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 20 Apr 2019 14:07:21 -0400 Subject: [PATCH 138/231] oc relay oops --- sys/init/3.relay.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua index cc197cf..ca75dc2 100644 --- a/sys/init/3.relay.lua +++ b/sys/init/3.relay.lua @@ -3,7 +3,7 @@ local kernel = _G.kernel local function register(v) if v and v.isWireless and v.isAccessPoint and v.getNamesRemote then - v.children = { } + v._children = { } for _, name in pairs(v.getNamesRemote()) do local dev = v.getMethodsRemote(name) if dev then From d32030bec48b267fc68aad45efabc4472e52dbbc Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 21 Apr 2019 23:41:17 -0400 Subject: [PATCH 139/231] foreign keyboards --- sys/apis/entry.lua | 2 +- sys/apis/input.lua | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sys/apis/entry.lua b/sys/apis/entry.lua index b31f247..5956762 100644 --- a/sys/apis/entry.lua +++ b/sys/apis/entry.lua @@ -344,7 +344,7 @@ local mappings = { --[ 'control-d' ] = Entry.cutNextWord, [ 'control-x' ] = Entry.cut, [ 'paste' ] = Entry.paste, - [ 'control-y' ] = Entry.paste, +-- [ 'control-y' ] = Entry.paste, -- well this won't work... [ 'mouse_doubleclick' ] = Entry.markWord, [ 'shift-left' ] = Entry.markLeft, diff --git a/sys/apis/input.lua b/sys/apis/input.lua index 94d9c91..a8871e9 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -88,8 +88,9 @@ function input:translate(event, code, p1, p2) else self.state[code] = true if self:modifierPressed() and not modifiers[code] then --or code == 57 then - self.fired = true - return { code = input:toCode(keys.getName(code), code) } + -- why was i firing here ?? + --self.fired = true + --return { code = input:toCode(keys.getName(code), code) } else self.fired = false end From 8a030cbc5041582d51770d80721871a1d2adf1c1 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 22 Apr 2019 02:07:34 -0400 Subject: [PATCH 140/231] altgr combos --- sys/apis/input.lua | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sys/apis/input.lua b/sys/apis/input.lua index a8871e9..661ad70 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -71,6 +71,12 @@ function input:reset() self.mfired = nil end +local function isCombo() + -- allow control-alt combinations for certain keyboards + return (keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt]) and + (keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl]) +end + function input:translate(event, code, p1, p2) if event == 'key' then if p1 then -- key is held down @@ -87,19 +93,16 @@ function input:translate(event, code, p1, p2) end else self.state[code] = true - if self:modifierPressed() and not modifiers[code] then --or code == 57 then - -- why was i firing here ?? - --self.fired = true - --return { code = input:toCode(keys.getName(code), code) } - else - self.fired = false - end + self.fired = false end elseif event == 'char' then + local combo = isCombo() if not self.fired then - self.fired = true - return { code = event, ch = code } + if combo or not (keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl]) then + self.fired = not combo + return { code = event, ch = code } + end -- return { code = event, ch = input:toCode(code) } end From 9e4eb1207e3338c5b502befc0f173f61fa12ab6f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 23 Apr 2019 14:48:39 -0400 Subject: [PATCH 141/231] better shell launcher --- sys/apps/ShellLauncher.lua | 27 +++++++++++++++++++++++++++ sys/apps/system/launcher.lua | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 sys/apps/ShellLauncher.lua diff --git a/sys/apps/ShellLauncher.lua b/sys/apps/ShellLauncher.lua new file mode 100644 index 0000000..9407e46 --- /dev/null +++ b/sys/apps/ShellLauncher.lua @@ -0,0 +1,27 @@ +local kernel = _G.kernel +local os = _G.os +local shell = _ENV.shell + +local launcherTab = kernel.getCurrent() + +kernel.hook('kernel_focus', function(_, eventData) + local focusTab = eventData and eventData[1] + if focusTab == launcherTab.uid then + local previousTab = eventData[2] + local nextTab = launcherTab + if not previousTab then + for _, v in pairs(kernel.routines) do + if not v.hidden and v.uid > nextTab.uid then + nextTab = v + end + end + end + if nextTab == launcherTab then + shell.switchTab(shell.openTab('sys/apps/shell.lua')) + else + shell.switchTab(nextTab.uid) + end + end +end) + +while os.pullEventRaw() do end \ No newline at end of file diff --git a/sys/apps/system/launcher.lua b/sys/apps/system/launcher.lua index a2fb843..5108ad0 100644 --- a/sys/apps/system/launcher.lua +++ b/sys/apps/system/launcher.lua @@ -17,7 +17,7 @@ local tab = UI.Tab { x = 13, y = 2, width = 12, choices = { { name = 'Overview', value = 'sys/apps/Overview.lua' }, - { name = 'Shell', value = 'sys/apps/shell.lua' }, + { name = 'Shell', value = 'sys/apps/ShellLauncher.lua' }, { name = 'Custom', value = 'custom' }, }, }, From 0c811ef892fbfd416265088096946d27795aa868 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Wed, 24 Apr 2019 00:42:23 -0700 Subject: [PATCH 142/231] improve startup option screen - Replaced the old startup alternate menu with a cleaner crisper interface - Up and down arrows as well as the mouse scroll wheel will move the cursor up or down. Enter will proceed to boot. - OR if the option desired is between 1 and 9, pressing the corresponding key will select and boot that option. - Appended .lua to the startup file --- startup => startup.lua | 75 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 13 deletions(-) rename startup => startup.lua (53%) diff --git a/startup b/startup.lua similarity index 53% rename from startup rename to startup.lua index 47678d3..082bdc9 100644 --- a/startup +++ b/startup.lua @@ -12,25 +12,74 @@ local bootOptions = { local bootOption = 2 if settings then settings.load('.settings') - bootOption = tonumber(settings.get('opus.boot_option') or 2) or 2 + bootOption = tonumber(settings.get('opus.boot_option')) or bootOption end local function startupMenu() - while true do + local x, y = term.getSize() + local align, selected = 0, 1 + local function redraw() + local title = "Boot Options:" term.clear() - term.setCursorPos(1, 1) - print('Select startup mode') - print() - for k,option in pairs(bootOptions) do - print(k .. ' : ' .. option.prompt) - end - print('') - term.write('> ') - local ch = tonumber(_G.read()) - if ch and bootOptions[ch] then - return ch + term.setTextColor(colors.white) + term.setCursorPos((x/2)-(#title/2), (y/2)-(#bootOptions/2)-1) + term.write(title) + for i = 1, #bootOptions do + local txt = i..". "..bootOptions[i].prompt + term.setCursorPos((x/2)-(align/2), (y/2)-(#bootOptions/2)+i) + term.write(txt) end end + + for i = 1, #bootOptions do + if (bootOptions[i].prompt):len() > align then + align = (bootOptions[i].prompt):len() + end + end + + redraw() + repeat + term.setCursorPos((x/2)-(align/2)-2, (y/2)-(#bootOptions/2)+selected) + if term.isColor() then + term.setTextColor(colors.yellow) + else + term.setTextColor(colors.lightGray) + end + term.write(">") + local k = ({os.pullEvent()}) + if k[1] == "mouse_scroll" then + if k[2] == 1 then + k = keys.down + else + k = keys.up + end + elseif k[1] == "key" then + k = k[2] + else + k = nil + end + if k then + if k == keys.enter or k == keys.right then + return selected + elseif k == keys.down then + if selected == #bootOptions then + selected = 0 + end + selected = selected+1 + elseif k == keys.up then + if selected == 1 then + selected = #bootOptions+1 + end + selected = selected-1 + elseif k >= keys.one and k <= #bootOptions+1 and k < keys.zero then + selected = k-1 + return selected + end + local cx, cy = term.getCursorPos() + term.setCursorPos(cx-1, cy) + term.write(" ") + end + until true == false end local function splash() From 366ab1736b51d2ad370950f0c59a53693c1ad3d8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 24 Apr 2019 20:32:38 -0400 Subject: [PATCH 143/231] remove old startup --- sys/autorun/upgraded.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index 7b30a1f..5c947c5 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -4,3 +4,4 @@ end if fs.exists('sys/etc/app.db') then fs.delete('sys/etc/app.db') end if fs.exists('sys/extensions') then fs.delete('sys/extensions') end if fs.exists('sys/network') then fs.delete('sys/network') end +if fs.exists('startup') then fs.delete('startup') end From 0e3cb15356dd8bea2b76b4ad434c440612a9210e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 24 Apr 2019 22:09:36 -0400 Subject: [PATCH 144/231] blacklist items for turtle digging --- sys/init/6.tl3.lua | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sys/init/6.tl3.lua b/sys/init/6.tl3.lua index ab4d93f..feeb5a0 100644 --- a/sys/init/6.tl3.lua +++ b/sys/init/6.tl3.lua @@ -51,6 +51,7 @@ function turtle.resetState() state.digPolicy = noop state.movePolicy = _defaultMove state.moveCallback = noop + state.blacklist = nil Pathing.reset() return true end @@ -283,6 +284,34 @@ turtle.addPolicy('turtleSafe', function(action) end) end) +local function isBlacklisted(b) + if b and state.blacklist then + for k, v in pairs(state.blacklist) do + if b.name:find(v) then + return true + end + end + end +end + +turtle.addPolicy('blacklist', function(action) + if action.side == 'back' then + return false + end + local s, m = action.inspect() + if not isBlacklisted(s and m) then + return action.dig() + end + if s and m and m.name:find('turtle') then + return Util.tryTimes(math.random(3, 6), function() + os.sleep(.25) + if not action.detect() then + return true + end + end) + end +end) + turtle.addPolicy('digAndDrop', function(action) if action.detect() then local slots = turtle.getInventory() @@ -347,6 +376,9 @@ function turtle.set(args) elseif k == 'status' then turtle.setStatus(v) + elseif k == 'blacklist' then + state.blacklist = v + else error('Invalid turle.set: ' .. tostring(k)) end From f4bcd611160bd5c8894c4959d99ea6c3c4f47d49 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 25 Apr 2019 14:44:36 -0400 Subject: [PATCH 145/231] tweaks --- sys/apis/event.lua | 6 +++++- sys/apis/fs/netfs.lua | 1 + sys/apps/Files.lua | 4 ++-- sys/autorun/apps.lua | 2 +- sys/init/6.tl3.lua | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sys/apis/event.lua b/sys/apis/event.lua index b563f2f..924461e 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -118,12 +118,16 @@ function Event.off(h) end function Event.onInterval(interval, fn) - return Event.addRoutine(function() + local h = Event.addRoutine(function() while true do os.sleep(interval) fn() end end) + function h.updateInterval(i) + interval = i + end + return h end function Event.onTimeout(timeout, fn) diff --git a/sys/apis/fs/netfs.lua b/sys/apis/fs/netfs.lua index d7eb2eb..77ec3b0 100644 --- a/sys/apis/fs/netfs.lua +++ b/sys/apis/fs/netfs.lua @@ -36,6 +36,7 @@ end local methods = { 'delete', 'exists', 'getFreeSpace', 'makeDir', 'list', 'listEx' } local function resolveDir(dir, node) + -- TODO: Wrong ! (does not support names with dashes) dir = dir:gsub(node.mountPoint, '', 1) return fs.combine(node.directory, dir) end diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 0e40ec5..f7564ed 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -146,9 +146,9 @@ local Browser = UI.Page { s = 'shell', p = 'pastebin', r = 'refresh', - space = 'mark', + [ ' ' ] = 'mark', + m = 'mark', backspace = 'updir', - m = 'move', u = 'unmark', d = 'delete', delete = 'delete', diff --git a/sys/autorun/apps.lua b/sys/autorun/apps.lua index c66656b..5322c79 100644 --- a/sys/autorun/apps.lua +++ b/sys/autorun/apps.lua @@ -1,4 +1,4 @@ -fs.mount('sys/apps/pain.lua', 'urlfs', 'http://pastebin.com/raw/wJQ7jav0') +fs.mount('sys/apps/pain.lua', 'urlfs', 'https://github.com/LDDestroier/CC/raw/master/pain.lua') fs.mount('sys/apps/update.lua', 'urlfs', 'http://pastebin.com/raw/UzGHLbNC') fs.mount('sys/apps/Enchat.lua', 'urlfs', 'https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua') fs.mount('sys/apps/cloud.lua', 'urlfs', 'https://cloud-catcher.squiddev.cc/cloud.lua') diff --git a/sys/init/6.tl3.lua b/sys/init/6.tl3.lua index feeb5a0..53519c4 100644 --- a/sys/init/6.tl3.lua +++ b/sys/init/6.tl3.lua @@ -286,7 +286,7 @@ end) local function isBlacklisted(b) if b and state.blacklist then - for k, v in pairs(state.blacklist) do + for _, v in pairs(state.blacklist) do if b.name:find(v) then return true end From 59552d4217c495cc07f8f3b81c1a737d435ca53a Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 27 Apr 2019 19:33:21 -0400 Subject: [PATCH 146/231] canvas update for resizing --- sys/apis/input.lua | 2 +- sys/apis/terminal.lua | 7 +++++-- sys/apis/ui/canvas.lua | 18 ++++++++++++++++-- sys/init/1.device.lua | 8 -------- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/sys/apis/input.lua b/sys/apis/input.lua index 661ad70..4134461 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -91,7 +91,7 @@ function input:translate(event, code, p1, p2) end return { code = ch } end - else + elseif code then self.state[code] = true self.fired = false end diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index dc10311..214e4ec 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -192,8 +192,11 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) end function win.restoreCursor() - win.setCursorPos(cx, cy) - win.setCursorBlink(blink) + if isVisible then + win.setCursorPos(cx, cy) + win.setTextColor(fg) + win.setCursorBlink(blink) + end end function win.getPosition() diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index d980845..c7fbca3 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -63,8 +63,22 @@ function Canvas:resize(w, h) table.remove(self.lines, #self.lines) end - if w ~= self.width then - self:clear() + if w < self.width then + for i = 1, h do + self.lines[i].text = _sub(self.lines[i].text, 1, w) + self.lines[i].fg = _sub(self.lines[i].fg, 1, w) + self.lines[i].bg = _sub(self.lines[i].bg, 1, w) + end + elseif w > self.width then + local d = w - self.width + local text = _rep(' ', d) + local fg = _rep(self.palette[self.fg or colors.white], d) + local bg = _rep(self.palette[self.bg or colors.black], d) + for i = 1, h do + self.lines[i].text = self.lines[i].text .. text + self.lines[i].fg = self.lines[i].fg .. fg + self.lines[i].bg = self.lines[i].bg .. bg + end end self.ex = self.x + w - 1 diff --git a/sys/init/1.device.lua b/sys/init/1.device.lua index 3d25083..803898d 100644 --- a/sys/init/1.device.lua +++ b/sys/init/1.device.lua @@ -121,14 +121,6 @@ function keyboard.removeHotkey(code) keyboard.hotkeys[code] = nil end -kernel.hook('monitor_touch', function(event, eventData) - local monitor = Peripheral.getBySide(eventData[1]) - if monitor and monitor.eventChannel then - monitor.eventChannel(event, table.unpack(eventData)) - return true -- stop propagation - end -end) - local function createDevice(name, devType, method, manipulator) local dev = { name = name, From c44dc765daa127f7036dc0a675ad43f3664ca425 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 3 May 2019 15:30:09 -0400 Subject: [PATCH 147/231] change _debug to _syslog --- sys/apis/terminal.lua | 4 ++-- sys/apis/trace.lua | 2 +- sys/apis/ui/canvas.lua | 16 +++++++++------- sys/apps/network/transport.lua | 16 ++++++++-------- sys/boot/opus.boot | 2 +- sys/kernel.lua | 8 +------- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 214e4ec..e73d822 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -100,9 +100,9 @@ function Terminal.window(parent, sx, sy, w, h, isVisible) end function win.setCursorPos(x, y) - cx, cy = x, y + cx, cy = math.floor(x), math.floor(y) if isVisible then - parent.setCursorPos(x + canvas.x - 1, y + canvas.y - 1) + parent.setCursorPos(cx + canvas.x - 1, cy + canvas.y - 1) end end diff --git a/sys/apis/trace.lua b/sys/apis/trace.lua index ddb023c..4323003 100644 --- a/sys/apis/trace.lua +++ b/sys/apis/trace.lua @@ -85,7 +85,7 @@ return function (fn, ...) end for _, line in pairs(trace) do - _G._debug(line) + _G._syslog(line) end -- If this traceback is more than 15 elements long, keep the first 9, last 5 diff --git a/sys/apis/ui/canvas.lua b/sys/apis/ui/canvas.lua index c7fbca3..b7969b0 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/apis/ui/canvas.lua @@ -199,13 +199,15 @@ function Canvas:blit(x, y, text, bg, fg) end local line = self.lines[y] - line.dirty = true - line.text = replace(line.text, x, text, width) - if fg then - line.fg = replace(line.fg, x, fg, width) - end - if bg then - line.bg = replace(line.bg, x, bg, width) + if line then + line.dirty = true + line.text = replace(line.text, x, text, width) + if fg then + line.fg = replace(line.fg, x, fg, width) + end + if bg then + line.bg = replace(line.bg, x, bg, width) + end end end end diff --git a/sys/apps/network/transport.lua b/sys/apps/network/transport.lua index 2eeb801..eccd9ef 100644 --- a/sys/apps/network/transport.lua +++ b/sys/apps/network/transport.lua @@ -33,7 +33,7 @@ function transport.read(socket) end function transport.write(socket, data) - --_debug('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq })) + --_syslog('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq })) socket.transmit(socket.dport, socket.dhost, data) --local timerId = os.startTimer(3) @@ -45,7 +45,7 @@ function transport.write(socket, data) end function transport.ping(socket) - --_debug('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq })) + --_syslog('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq })) if os.clock() - socket.activityTimer > 10 then socket.activityTimer = os.clock() socket.transmit(socket.dport, socket.dhost, { @@ -78,9 +78,9 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) local socket = transport.sockets[dport] if socket and socket.connected then - --if msg.type then _debug('<< ' .. Util.tostring(msg)) end + --if msg.type then _syslog('<< ' .. Util.tostring(msg)) end if socket.co and coroutine.status(socket.co) == 'dead' then - _G._debug('socket coroutine dead') + _G._syslog('socket coroutine dead') socket:close() elseif msg.type == 'DISC' then @@ -111,9 +111,9 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) socket.activityTimer = os.clock() if msg.seq ~= socket.rseq then print('transport seq error - closing socket ' .. socket.sport) - _debug(msg.data) - _debug('current ' .. socket.rseq) - _debug('expected ' .. msg.seq) + _syslog(msg.data) + _syslog('current ' .. socket.rseq) + _syslog('expected ' .. msg.seq) -- socket:close() -- os.queueEvent('transport_' .. socket.uid) else @@ -125,7 +125,7 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) os.queueEvent('transport_' .. socket.uid) end - --_debug('>> ' .. Util.tostring({ type = 'ACK', seq = msg.seq })) + --_syslog('>> ' .. Util.tostring({ type = 'ACK', seq = msg.seq })) --socket.transmit(socket.dport, socket.dhost, { -- type = 'ACK', -- seq = msg.seq, diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index 7ba7a1d..d139e37 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -11,7 +11,7 @@ for k,v in pairs(_ENV) do sandboxEnv[k] = v end -_G._debug = function() end +_G._syslog = function() end local function makeEnv() local env = setmetatable({ }, { __index = _G }) diff --git a/sys/kernel.lua b/sys/kernel.lua index a787513..799164e 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -28,19 +28,13 @@ local focusedRoutineEvents = Util.transpose { 'paste', 'terminate', } -_G._debug = function(pattern, ...) +_G._syslog = function(pattern, ...) local oldTerm = term.redirect(kernel.window) kernel.window.scrollBottom() Util.print(pattern, ...) term.redirect(oldTerm) end -if not _G.debug then -- don't clobber lua debugger - function _G.debug(...) - _G._debug(...) - end -end - -- any function that runs in a kernel hook does not run in -- a separate coroutine or have a window. an error in a hook -- function will crash the system. From bf870479c4f6a6e74ea72682823e041bd8eb76b4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 4 May 2019 06:11:22 -0400 Subject: [PATCH 148/231] mark with drag fix --- sys/apis/ui.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 41c7242..3b0c26b 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -114,7 +114,6 @@ function Manager:init() mouse_up = function(_, button, x, y) local ie = Input:translate('mouse_up', button, x, y) - local currentPage = self:getActivePage() if ie.code == 'control-shift-mouse_click' then -- hack @@ -134,12 +133,9 @@ function Manager:init() mouse_drag = function(_, button, x, y) local ie = Input:translate('mouse_drag', button, x, y) local currentPage = self:getActivePage() + if ie and currentPage then - local event = currentPage:pointToChild(x, y) - event.type = ie.code - event.ie = ie - self:inputEvent(event.element, event) - currentPage:sync() + self:click(currentPage, ie.code, button, x, y) end end, From 43163053a58193b81d37c52f369f849d6a3125c3 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 12 May 2019 10:02:46 -0400 Subject: [PATCH 149/231] Lua: timing --- sys/apis/map.lua | 2 ++ sys/apis/util.lua | 3 +++ sys/apps/Lua.lua | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sys/apis/map.lua b/sys/apis/map.lua index 9e4ab93..a6b033c 100644 --- a/sys/apis/map.lua +++ b/sys/apis/map.lua @@ -6,6 +6,8 @@ local Map = { } -- TODO: refactor Map.merge = Util.merge Map.shallowCopy = Util.shallowCopy +Map.find = Util.find +Map.filter = Util.filter function Map.removeMatches(t, values) local function matchAll(entry) diff --git a/sys/apis/util.lua b/sys/apis/util.lua index f1f5a8d..e774ed9 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -77,6 +77,9 @@ function Util.tostring(pattern, ...) end if type(pattern) == 'string' then + if select('#', ...) == 0 then + return pattern + end return _sformat(pattern, ...) elseif type(pattern) == 'table' then return serialize(pattern, term.current().getSize()) diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index 5627d6c..4eba8ab 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -294,6 +294,7 @@ end function page:rawExecute(s) local fn, m local wrapped + local t = os.clock() fn = load('return (' ..s.. ')', 'lua', nil, sandboxEnv) @@ -319,7 +320,7 @@ function page:rawExecute(s) local bg, fg = term.getBackgroundColor(), term.getTextColor() term.setTextColor(colors.cyan) term.setBackgroundColor(colors.black) - term.write(string.format('out [%d]: ', counter)) + term.write(string.format('out [%.2f]: ', os.clock() - t)) term.setBackgroundColor(bg) term.setTextColor(fg) Util.print(m or 'nil') From 310879a801ec84a557dfdcd04f1a35dfe7ea498c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 20 May 2019 15:19:39 -0400 Subject: [PATCH 150/231] sanitize discovery messages --- sys/apps/network/snmp.lua | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index dcc7bff..0e69a03 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -121,20 +121,26 @@ print('discovery: listening on port 999') Event.on('modem_message', function(_, _, sport, id, info, distance) if sport == 999 and tonumber(id) and type(info) == 'table' then - if not network[id] then - network[id] = { } - end - Util.merge(network[id], info) - network[id].distance = distance - network[id].timestamp = os.clock() + if info.label and info.id and + type(info.label) == 'string' and type(info.id) == 'number' then - if not network[id].label then - network[id].label = 'unknown' - end + if not network[id] then + network[id] = { } + end + Util.merge(network[id], info) + network[id].distance = type(distance) == 'number' and distance + network[id].timestamp = os.clock() - if not network[id].active then - network[id].active = true - os.queueEvent('network_attach', network[id]) + if not network[id].label then + network[id].label = 'unknown' + end + + if not network[id].active then + network[id].active = true + os.queueEvent('network_attach', network[id]) + end + else + print('discovery: Invalid alive message ' .. id) end end end) From 82ec4db50fc9aa0ac072d81b2d473c6f0e573ee3 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 26 May 2019 11:05:37 -0400 Subject: [PATCH 151/231] input rework - again --- sys/apis/input.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sys/apis/input.lua b/sys/apis/input.lua index 4134461..ee003a0 100644 --- a/sys/apis/input.lua +++ b/sys/apis/input.lua @@ -92,28 +92,32 @@ function input:translate(event, code, p1, p2) return { code = ch } end elseif code then - self.state[code] = true - self.fired = false + --self.fired = true + local ch = input:toCode(keys.getName(code), code) + if #ch ~= 1 then + return { code = ch } + end +-- self.state[code] = true end elseif event == 'char' then local combo = isCombo() - if not self.fired then + --if not self.fired then if combo or not (keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl]) then self.fired = not combo return { code = event, ch = code } - end + --end -- return { code = event, ch = input:toCode(code) } end - elseif event == 'key_up' then + elseif event == 'key_upx' then if not self.fired then - if self.state[code] then + --if self.state[code] then self.fired = true local ch = input:toCode(keys.getName(code), code) self.state[code] = nil return { code = ch } - end + --end end self.state[code] = nil From 3c22a872b0eb408fcbe28010533b9d06cbf5b925 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 18 Jun 2019 15:19:24 -0400 Subject: [PATCH 152/231] spaces->tabs + cleanup + pathing fixes --- sys/apis/bulkget.lua | 42 +- sys/apis/fs/redfs.lua | 61 --- sys/apis/fs/urlfs.lua | 6 +- sys/apis/json.lua | 727 ++++++++++++++++++++------- sys/apis/map.lua | 6 +- sys/apis/pathfind.lua | 25 +- sys/apis/point.lua | 15 +- sys/apis/proxy.lua | 32 -- sys/apis/rttp.lua | 95 ---- sys/apis/sha2.lua | 200 ++++++++ sys/apis/sync.lua | 86 ++-- sys/apis/trace.lua | 158 +++--- sys/apis/ui/components/Grid.lua | 29 +- sys/apis/util.lua | 2 +- sys/apps/Files.lua | 852 ++++++++++++++++---------------- sys/apps/Lua.lua | 19 +- sys/apps/Network.lua | 2 + sys/apps/ShellLauncher.lua | 36 +- sys/apps/Welcome.lua | 170 +++---- sys/apps/autorun.lua | 86 ++-- sys/apps/cedit.lua | 36 +- sys/apps/cshell.lua | 24 +- sys/apps/network/redserver.lua | 115 ----- sys/apps/network/snmp.lua | 2 +- sys/apps/sniff.lua | 69 --- sys/apps/system/cloud.lua | 78 +-- sys/apps/system/kiosk.lua | 14 +- sys/apps/system/launcher.lua | 112 ++--- sys/apps/system/path.lua | 108 ++-- sys/apps/system/requires.lua | 114 ++--- sys/apps/system/shell.lua | 180 +++---- sys/autorun/complete.lua | 36 +- sys/autorun/welcome.lua | 6 +- sys/init/3.modules.lua | 62 +-- sys/init/3.relay.lua | 30 +- sys/init/6.packages.lua | 4 +- sys/init/6.tl3.lua | 12 +- 37 files changed, 1948 insertions(+), 1703 deletions(-) delete mode 100644 sys/apis/fs/redfs.lua delete mode 100644 sys/apis/proxy.lua delete mode 100644 sys/apis/rttp.lua create mode 100644 sys/apis/sha2.lua delete mode 100644 sys/apps/network/redserver.lua delete mode 100644 sys/apps/sniff.lua diff --git a/sys/apis/bulkget.lua b/sys/apis/bulkget.lua index 1135847..a9679ef 100644 --- a/sys/apis/bulkget.lua +++ b/sys/apis/bulkget.lua @@ -5,29 +5,29 @@ local parallel = _G.parallel local BulkGet = { } function BulkGet.download(list, callback) - local t = { } - local failed = false + local t = { } + local failed = false - for _ = 1, 5 do - table.insert(t, function() - while true do - local entry = table.remove(list) - if not entry then - break - end - local s, m = Util.download(entry.url, entry.path) - if not s then - failed = true - end - callback(entry, s, m) - if failed then - break - end - end - end) - end + for _ = 1, 5 do + table.insert(t, function() + while true do + local entry = table.remove(list) + if not entry then + break + end + local s, m = Util.download(entry.url, entry.path) + if not s then + failed = true + end + callback(entry, s, m) + if failed then + break + end + end + end) + end - parallel.waitForAll(table.unpack(t)) + parallel.waitForAll(table.unpack(t)) end return BulkGet diff --git a/sys/apis/fs/redfs.lua b/sys/apis/fs/redfs.lua deleted file mode 100644 index bbd981a..0000000 --- a/sys/apis/fs/redfs.lua +++ /dev/null @@ -1,61 +0,0 @@ ---[[ - Mount a readonly file system from another computer across rednet. The - target computer must be running OpusOS or redserver. Dissimlar to samba - in that a snapshot of the target is taken upon mounting - making this - faster. - - Useful for mounting a non-changing directory tree. - - Syntax: - rttp:///directory/subdir - - Examples: - rttp://12/usr/etc - rttp://8/usr -]]-- - -local rttp = require('rttp') - -local fs = _G.fs - -local redfs = { } - -local function getListing(uri) - local success, response = rttp.get(uri .. '?recursive=true') - - if not success then - error(response) - end - - if response.statusCode ~= 200 then - error('Received response ' .. response.statusCode) - end - - local list = { } - for _,v in pairs(response.data) do - if not v.isDir then - list[v.path] = { - url = uri .. '/' .. v.path, - size = v.size, - } - end - end - - return list -end - -function redfs.mount(dir, uri) - if not uri then - error('redfs syntax: uri') - end - - local list = getListing(uri) - for path, entry in pairs(list) do - if not fs.exists(fs.combine(dir, path)) then - local node = fs.mount(fs.combine(dir, path), 'urlfs', entry.url) - node.size = entry.size - end - end -end - -return redfs diff --git a/sys/apis/fs/urlfs.lua b/sys/apis/fs/urlfs.lua index 6feb4f0..fc3b655 100644 --- a/sys/apis/fs/urlfs.lua +++ b/sys/apis/fs/urlfs.lua @@ -1,4 +1,4 @@ -local rttp = require('rttp') +--local rttp = require('rttp') local Util = require('util') local fs = _G.fs @@ -39,7 +39,6 @@ function urlfs.getDrive() end function urlfs.open(node, fn, fl) - if fl == 'w' or fl == 'wb' then fs.delete(fn) return fs.open(fn, fl) @@ -51,12 +50,15 @@ function urlfs.open(node, fn, fl) local c = node.cache if not c then + --[[ if node.url:match("^(rttps?:)") then local s, response = rttp.get(node.url) c = s and response.statusCode == 200 and response.data else c = Util.httpGet(node.url) end + ]]-- + c = Util.httpGet(node.url) if c then node.cache = c node.size = #c diff --git a/sys/apis/json.lua b/sys/apis/json.lua index 64f8825..04b1cd1 100644 --- a/sys/apis/json.lua +++ b/sys/apis/json.lua @@ -1,215 +1,584 @@ --- credit ElvishJerricco --- http://pastebin.com/raw.php?i=4nRg9CHU +-- Module options: +local register_global_module_table = false +local global_module_name = 'json' -local json = { } +--[==[ +NOTE: Modified to reduce file size. +See https://github.com/LuaDist/dkjson/blob/master/dkjson.lua +for full version. ------------------------------------------------------------------- utils -local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"} +David Kolf's JSON module for Lua 5.1/5.2 +Version 2.5 -local function isArray(t) - local max = 0 - for k,v in pairs(t) do - if type(k) ~= "number" then - return false - elseif k > max then - max = k - end - end - return max == #t +For the documentation see the corresponding readme.txt or visit +. + +You can contact the author by sending an e-mail to 'david' at the +domain 'dkolf.de'. + +Copyright (C) 2010-2014 David Heiko Kolf + +Refer to license located at https://github.com/LuaDist/dkjson/blob/master/dkjson.lua + +--]==] + +-- global dependencies: +local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset = + pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset +local error, require, pcall, select = error, require, pcall, select +local floor, huge = math.floor, math.huge +local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat = + string.rep, string.gsub, string.sub, string.byte, string.char, + string.find, string.len, string.format +local strmatch = string.match +local concat = table.concat + +local json = { version = "dkjson 2.5" } + +if register_global_module_table then + _G[global_module_name] = json end -local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true} -local function removeWhite(str) - while whites[str:sub(1, 1)] do - str = str:sub(2) - end - return str -end +local _ENV = nil -- blocking globals in Lua 5.2 ------------------------------------------------------------------- encoding +pcall (function() + -- Enable access to blocked metatables. + -- Don't worry, this module doesn't change anything in them. + local debmeta = require "debug".getmetatable + if debmeta then getmetatable = debmeta end +end) -local function encodeCommon(val, pretty, tabLevel, tTracking) - local str = "" +json.null = setmetatable ({}, { + __tojson = function () return "null" end +}) - -- Tabbing util - local function tab(s) - str = str .. ("\t"):rep(tabLevel) .. s - end - - local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc) - str = str .. bracket - if pretty then - str = str .. "\n" - tabLevel = tabLevel + 1 - end - for k,v in iterator(val) do - tab("") - loopFunc(k,v) - str = str .. "," - if pretty then str = str .. "\n" end - end - if pretty then - tabLevel = tabLevel - 1 - end - if str:sub(-2) == ",\n" then - str = str:sub(1, -3) .. "\n" - elseif str:sub(-1) == "," then - str = str:sub(1, -2) - end - tab(closeBracket) - end - - -- Table encoding - if type(val) == "table" then - assert(not tTracking[val], "Cannot encode a table holding itself recursively") - tTracking[val] = true - if isArray(val) then - arrEncoding(val, "[", "]", ipairs, function(k,v) - str = str .. encodeCommon(v, pretty, tabLevel, tTracking) - end) +local function isarray (tbl) + local max, n, arraylen = 0, 0, 0 + for k,v in pairs (tbl) do + if k == 'n' and type(v) == 'number' then + arraylen = v + if v > max then + max = v + end else - arrEncoding(val, "{", "}", pairs, function(k,v) - assert(type(k) == "string", "JSON object keys must be strings", 2) - str = str .. encodeCommon(k, pretty, tabLevel, tTracking) - str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking) - end) + if type(k) ~= 'number' or k < 1 or floor(k) ~= k then + return false + end + if k > max then + max = k + end + n = n + 1 end - -- String encoding - elseif type(val) == "string" then - str = '"' .. val:gsub("[%c\"\\]", controls) .. '"' - -- Number encoding - elseif type(val) == "number" or type(val) == "boolean" then - str = tostring(val) + end + if max > 10 and max > arraylen and max > n * 2 then + return false -- don't create an array with too many holes + end + return true, max +end + +local escapecodes = { + ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f", + ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t" +} + +local function escapeutf8 (uchar) + local value = escapecodes[uchar] + if value then + return value + end + local a, b, c, d = strbyte (uchar, 1, 4) + a, b, c, d = a or 0, b or 0, c or 0, d or 0 + if a <= 0x7f then + value = a + elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then + value = (a - 0xc0) * 0x40 + b - 0x80 + elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then + value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80 + elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then + value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80 else - error("JSON only supports arrays, objects, numbers, booleans, and strings", 2) + return "" end - return str -end - -function json.encode(val) - return encodeCommon(val, false, 0, {}) -end - -function json.encodePretty(val) - return encodeCommon(val, true, 0, {}) -end - -function json.encodeToFile(path, val) - local file = io.open(path, "w") - assert(file, "Unable to open file") - file:write(json.encodePretty(val)) - file:close() -end - ------------------------------------------------------------------- decoding - -local decodeControls = {} -for k,v in pairs(controls) do - decodeControls[v] = k -end - -local function parseBoolean(str) - if str:sub(1, 4) == "true" then - return true, removeWhite(str:sub(5)) + if value <= 0xffff then + return strformat ("\\u%.4x", value) + elseif value <= 0x10ffff then + -- encode as UTF-16 surrogate pair + value = value - 0x10000 + local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400) + return strformat ("\\u%.4x\\u%.4x", highsur, lowsur) else - return false, removeWhite(str:sub(6)) + return "" end end -local function parseNull(str) - return nil, removeWhite(str:sub(5)) -end - -local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true} -local function parseNumber(str) - local i = 1 - while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do - i = i + 1 +local function fsub (str, pattern, repl) + -- gsub always builds a new string in a buffer, even when no match + -- exists. First using find should be more efficient when most strings + -- don't contain the pattern. + if strfind (str, pattern) then + return gsub (str, pattern, repl) + else + return str end - local val = tonumber(str:sub(1, i - 1)) - str = removeWhite(str:sub(i)) - return val, str end -local function parseString(str) - str = str:sub(2) - local s = "" - while str:sub(1,1) ~= "\"" do - local next = str:sub(1,1) - str = str:sub(2) - assert(next ~= "\n", "Unclosed string") +local function quotestring (value) + -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js + value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8) + if strfind (value, "[\194\216\220\225\226\239]") then + value = fsub (value, "\194[\128-\159\173]", escapeutf8) + value = fsub (value, "\216[\128-\132]", escapeutf8) + value = fsub (value, "\220\143", escapeutf8) + value = fsub (value, "\225\158[\180\181]", escapeutf8) + value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8) + value = fsub (value, "\226\129[\160-\175]", escapeutf8) + value = fsub (value, "\239\187\191", escapeutf8) + value = fsub (value, "\239\191[\176-\191]", escapeutf8) + end + return "\"" .. value .. "\"" +end +json.quotestring = quotestring - if next == "\\" then - local escape = str:sub(1,1) - str = str:sub(2) +local function replace(str, o, n) + local i, j = strfind (str, o, 1, true) + if i then + return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1) + else + return str + end +end - next = assert(decodeControls[next..escape], "Invalid escape character") +-- locale independent num2str and str2num functions +local decpoint, numfilter + +local function updatedecpoint () + decpoint = strmatch(tostring(0.5), "([^05+])") + -- build a filter that can be used to remove group separators + numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+" +end + +updatedecpoint() + +local function num2str (num) + return replace(fsub(tostring(num), numfilter, ""), decpoint, ".") +end + +local function str2num (str) + local num = tonumber(replace(str, ".", decpoint)) + if not num then + updatedecpoint() + num = tonumber(replace(str, ".", decpoint)) + end + return num +end + +local function addnewline2 (level, buffer, buflen) + buffer[buflen+1] = "\n" + buffer[buflen+2] = strrep (" ", level) + buflen = buflen + 2 + return buflen +end + +function json.addnewline (state) + if state.indent then + state.bufferlen = addnewline2 (state.level or 0, + state.buffer, state.bufferlen or #(state.buffer)) + end +end + +local encode2 -- forward declaration + +local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state) + local kt = type (key) + if kt ~= 'string' and kt ~= 'number' then + return nil, "type '" .. kt .. "' is not supported as a key by JSON." + end + if prev then + buflen = buflen + 1 + buffer[buflen] = "," + end + if indent then + buflen = addnewline2 (level, buffer, buflen) + end + buffer[buflen+1] = quotestring (key) + buffer[buflen+2] = ":" + return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state) +end + +local function appendcustom(res, buffer, state) + local buflen = state.bufferlen + if type (res) == 'string' then + buflen = buflen + 1 + buffer[buflen] = res + end + return buflen +end + +local function exception(reason, value, state, buffer, buflen, defaultmessage) + defaultmessage = defaultmessage or reason + local handler = state.exception + if not handler then + return nil, defaultmessage + else + state.bufferlen = buflen + local ret, msg = handler (reason, value, state, defaultmessage) + if not ret then return nil, msg or defaultmessage end + return appendcustom(ret, buffer, state) + end +end + +function json.encodeexception(reason, value, state, defaultmessage) + return quotestring("<" .. defaultmessage .. ">") +end + +encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state) + local valtype = type (value) + local valmeta = getmetatable (value) + valmeta = type (valmeta) == 'table' and valmeta -- only tables + local valtojson = valmeta and valmeta.__tojson + if valtojson then + if tables[value] then + return exception('reference cycle', value, state, buffer, buflen) end - - s = s .. next + tables[value] = true + state.bufferlen = buflen + local ret, msg = valtojson (value, state) + if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end + tables[value] = nil + buflen = appendcustom(ret, buffer, state) + elseif value == nil then + buflen = buflen + 1 + buffer[buflen] = "null" + elseif valtype == 'number' then + local s + if value ~= value or value >= huge or -value >= huge then + -- This is the behaviour of the original JSON implementation. + s = "null" + else + s = num2str (value) + end + buflen = buflen + 1 + buffer[buflen] = s + elseif valtype == 'boolean' then + buflen = buflen + 1 + buffer[buflen] = value and "true" or "false" + elseif valtype == 'string' then + buflen = buflen + 1 + buffer[buflen] = quotestring (value) + elseif valtype == 'table' then + if tables[value] then + return exception('reference cycle', value, state, buffer, buflen) + end + tables[value] = true + level = level + 1 + local isa, n = isarray (value) + if n == 0 and valmeta and valmeta.__jsontype == 'object' then + isa = false + end + local msg + if isa then -- JSON array + buflen = buflen + 1 + buffer[buflen] = "[" + for i = 1, n do + buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state) + if not buflen then return nil, msg end + if i < n then + buflen = buflen + 1 + buffer[buflen] = "," + end + end + buflen = buflen + 1 + buffer[buflen] = "]" + else -- JSON object + local prev = false + buflen = buflen + 1 + buffer[buflen] = "{" + local order = valmeta and valmeta.__jsonorder or globalorder + if order then + local used = {} + n = #order + for i = 1, n do + local k = order[i] + local v = value[k] + if v then + used[k] = true + buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state) + prev = true -- add a seperator before the next element + end + end + for k,v in pairs (value) do + if not used[k] then + buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state) + if not buflen then return nil, msg end + prev = true -- add a seperator before the next element + end + end + else -- unordered + for k,v in pairs (value) do + buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state) + if not buflen then return nil, msg end + prev = true -- add a seperator before the next element + end + end + if indent then + buflen = addnewline2 (level - 1, buffer, buflen) + end + buflen = buflen + 1 + buffer[buflen] = "}" + end + tables[value] = nil + else + return exception ('unsupported type', value, state, buffer, buflen, + "type '" .. valtype .. "' is not supported by JSON.") end - return s, removeWhite(str:sub(2)) + return buflen end -function json.parseArray(str) - str = removeWhite(str:sub(2)) - - local val = {} - local i = 1 - while str:sub(1, 1) ~= "]" do - local v - v, str = json.parseValue(str) - val[i] = v - i = i + 1 - str = removeWhite(str) - end - str = removeWhite(str:sub(2)) - return val, str -end - -function json.parseValue(str) - local fchar = str:sub(1, 1) - if fchar == "{" then - return json.parseObject(str) - elseif fchar == "[" then - return json.parseArray(str) - elseif tonumber(fchar) ~= nil or numChars[fchar] then - return parseNumber(str) - elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then - return parseBoolean(str) - elseif fchar == "\"" then - return parseString(str) - elseif str:sub(1, 4) == "null" then - return parseNull(str) +function json.encode (value, state) + state = state or {} + local oldbuffer = state.buffer + local buffer = oldbuffer or {} + state.buffer = buffer + updatedecpoint() + local ret, msg = encode2 (value, state.indent, state.level or 0, + buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state) + if not ret then + error (msg, 2) + elseif oldbuffer == buffer then + state.bufferlen = ret + return true + else + state.bufferlen = nil + state.buffer = nil + return concat (buffer) end end -function json.parseMember(str) - local k, val - k, str = json.parseValue(str) - val, str = json.parseValue(str) - return k, val, str -end - -function json.parseObject(str) - str = removeWhite(str:sub(2)) - - local val = {} - while str:sub(1, 1) ~= "}" do - local k, v - k, v, str = json.parseMember(str) - val[k] = v - str = removeWhite(str) +local function loc (str, where) + local line, pos, linepos = 1, 1, 0 + while true do + pos = strfind (str, "\n", pos, true) + if pos and pos < where then + line = line + 1 + linepos = pos + pos = pos + 1 + else + break + end end - str = removeWhite(str:sub(2)) - return val, str + return "line " .. line .. ", column " .. (where - linepos) end -function json.decode(str) - str = removeWhite(str) - return json.parseValue(str) +local function unterminated (str, what, where) + return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where) end +local function scanwhite (str, pos) + while true do + pos = strfind (str, "%S", pos) + if not pos then return nil end + local sub2 = strsub (str, pos, pos + 1) + if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then + -- UTF-8 Byte Order Mark + pos = pos + 3 + elseif sub2 == "//" then + pos = strfind (str, "[\n\r]", pos + 2) + if not pos then return nil end + elseif sub2 == "/*" then + pos = strfind (str, "*/", pos + 2) + if not pos then return nil end + pos = pos + 2 + else + return pos + end + end +end + +local escapechars = { + ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f", + ["n"] = "\n", ["r"] = "\r", ["t"] = "\t" +} + +local function unichar (value) + if value < 0 then + return nil + elseif value <= 0x007f then + return strchar (value) + elseif value <= 0x07ff then + return strchar (0xc0 + floor(value/0x40), + 0x80 + (floor(value) % 0x40)) + elseif value <= 0xffff then + return strchar (0xe0 + floor(value/0x1000), + 0x80 + (floor(value/0x40) % 0x40), + 0x80 + (floor(value) % 0x40)) + elseif value <= 0x10ffff then + return strchar (0xf0 + floor(value/0x40000), + 0x80 + (floor(value/0x1000) % 0x40), + 0x80 + (floor(value/0x40) % 0x40), + 0x80 + (floor(value) % 0x40)) + else + return nil + end +end + +local function scanstring (str, pos) + local lastpos = pos + 1 + local buffer, n = {}, 0 + while true do + local nextpos = strfind (str, "[\"\\]", lastpos) + if not nextpos then + return unterminated (str, "string", pos) + end + if nextpos > lastpos then + n = n + 1 + buffer[n] = strsub (str, lastpos, nextpos - 1) + end + if strsub (str, nextpos, nextpos) == "\"" then + lastpos = nextpos + 1 + break + else + local escchar = strsub (str, nextpos + 1, nextpos + 1) + local value + if escchar == "u" then + value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16) + if value then + local value2 + if 0xD800 <= value and value <= 0xDBff then + -- we have the high surrogate of UTF-16. Check if there is a + -- low surrogate escaped nearby to combine them. + if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then + value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16) + if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then + value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000 + else + value2 = nil -- in case it was out of range for a low surrogate + end + end + end + value = value and unichar (value) + if value then + if value2 then + lastpos = nextpos + 12 + else + lastpos = nextpos + 6 + end + end + end + end + if not value then + value = escapechars[escchar] or escchar + lastpos = nextpos + 2 + end + n = n + 1 + buffer[n] = value + end + end + if n == 1 then + return buffer[1], lastpos + elseif n > 1 then + return concat (buffer), lastpos + else + return "", lastpos + end +end + +local scanvalue -- forward declaration + +local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta) + local len = strlen (str) + local tbl, n = {}, 0 + local pos = startpos + 1 + if what == 'object' then + setmetatable (tbl, objectmeta) + else + setmetatable (tbl, arraymeta) + end + while true do + pos = scanwhite (str, pos) + if not pos then return unterminated (str, what, startpos) end + local char = strsub (str, pos, pos) + if char == closechar then + return tbl, pos + 1 + end + local val1, err + val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta) + if err then return nil, pos, err end + pos = scanwhite (str, pos) + if not pos then return unterminated (str, what, startpos) end + char = strsub (str, pos, pos) + if char == ":" then + if val1 == nil then + return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")" + end + pos = scanwhite (str, pos + 1) + if not pos then return unterminated (str, what, startpos) end + local val2 + val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta) + if err then return nil, pos, err end + tbl[val1] = val2 + pos = scanwhite (str, pos) + if not pos then return unterminated (str, what, startpos) end + char = strsub (str, pos, pos) + else + n = n + 1 + tbl[n] = val1 + end + if char == "," then + pos = pos + 1 + end + end +end + +scanvalue = function (str, pos, nullval, objectmeta, arraymeta) + pos = pos or 1 + pos = scanwhite (str, pos) + if not pos then + return nil, strlen (str) + 1, "no valid JSON value (reached the end)" + end + local char = strsub (str, pos, pos) + if char == "{" then + return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta) + elseif char == "[" then + return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta) + elseif char == "\"" then + return scanstring (str, pos) + else + local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos) + if pstart then + local number = str2num (strsub (str, pstart, pend)) + if number then + return number, pend + 1 + end + end + pstart, pend = strfind (str, "^%a%w*", pos) + if pstart then + local name = strsub (str, pstart, pend) + if name == "true" then + return true, pend + 1 + elseif name == "false" then + return false, pend + 1 + elseif name == "null" then + return nullval, pend + 1 + end + end + return nil, pos, "no valid JSON value at " .. loc (str, pos) + end +end + +local function optionalmetatables(...) + if select("#", ...) > 0 then + return ... + else + return {__jsontype = 'object'}, {__jsontype = 'array'} + end +end + +function json.decode (str, pos, nullval, ...) + local objectmeta, arraymeta = optionalmetatables(...) + return scanvalue (str, pos, nullval, objectmeta, arraymeta) +end + +-- NOTE: added method - not in original source function json.decodeFromFile(path) local file = assert(fs.open(path, "r")) local decoded = json.decode(file.readAll()) diff --git a/sys/apis/map.lua b/sys/apis/map.lua index a6b033c..8380f38 100644 --- a/sys/apis/map.lua +++ b/sys/apis/map.lua @@ -19,9 +19,9 @@ function Map.removeMatches(t, values) return true end - for k,v in pairs(t) do - if matchAll(v) then - t[k] = nil + for _, key in pairs(Util.keys(t)) do + if matchAll(t[key]) then + t[key] = nil end end end diff --git a/sys/apis/pathfind.lua b/sys/apis/pathfind.lua index ffb5d25..f34c6ac 100644 --- a/sys/apis/pathfind.lua +++ b/sys/apis/pathfind.lua @@ -106,6 +106,17 @@ local function selectDestination(pts, box, grid) end end +local function updateCanvas(path) + local t = { } + for node in path:nodes() do + table.insert(t, { x = node.x, y = node.y, z = node.z }) + end + os.queueEvent('canvas', { + type = 'canvas_path', + data = t, + }) +end + local function pathTo(dest, options) local blocks = options.blocks or turtle.getState().blocks or { } local dests = options.dest or { dest } -- support alternative destinations @@ -156,6 +167,8 @@ local function pathTo(dest, options) if not path then Util.removeByValue(dests, dest) else + updateCanvas(path) + path:filter() for node in path:nodes() do @@ -173,11 +186,19 @@ local function pathTo(dest, options) -- use single turn method so the turtle doesn't turn around -- when encountering obstacles - if not turtle.gotoSingleTurn(pt.x, pt.y, pt.z, pt.heading) then - --if not turtle.goto(pt) then + --if not turtle.gotoSingleTurn(pt.x, pt.y, pt.z, pt.heading) then + pt.heading = nil + if not turtle.go(pt) then local bpt = Point.nearestTo(turtle.point, pt) + if turtle.getFuelLevel() == 0 then + return false, 'Out of fuel' + end table.insert(blocks, bpt) + os.queueEvent('canvas', { + type = 'canvas_barrier', + data = { bpt }, + }) -- really need to check if the block we ran into was a turtle. -- if so, this block should be temporary (1-2 secs) diff --git a/sys/apis/point.lua b/sys/apis/point.lua index 690b446..da1d15b 100644 --- a/sys/apis/point.lua +++ b/sys/apis/point.lua @@ -131,8 +131,11 @@ end function Point.calculateMoves(pta, ptb, distance) local heading = pta.heading local moves = distance or Point.turtleDistance(pta, ptb) + local weighted = moves + if (pta.heading % 2) == 0 and pta.z ~= ptb.z then moves = moves + 1 + weighted = weighted + .9 if ptb.heading and (ptb.heading % 2 == 1) then heading = ptb.heading elseif ptb.z > pta.z then @@ -142,6 +145,7 @@ function Point.calculateMoves(pta, ptb, distance) end elseif (pta.heading % 2) == 1 and pta.x ~= ptb.x then moves = moves + 1 + weighted = weighted + .9 if ptb.heading and (ptb.heading % 2 == 0) then heading = ptb.heading elseif ptb.x > pta.x then @@ -152,15 +156,18 @@ function Point.calculateMoves(pta, ptb, distance) end if not ptb.heading then - return moves, heading, moves + return moves, heading, weighted end + -- need to know if we are in digging mode + -- if so, we need to face blocks -- need a no-backwards flag + -- calc turns as slightly less than moves - local weighted = moves + -- local weighted = moves if heading ~= ptb.heading then local turns = Point.calculateTurns(heading, ptb.heading) moves = moves + turns - local wturns = { [0] = 0, [1] = .9, [2] = 1.9 } + local wturns = { [0] = 0, [1] = .9, [2] = 1.8 } weighted = weighted + wturns[turns] heading = ptb.heading end @@ -233,7 +240,7 @@ end function Point.nearestTo(pta, ptb) local heading - if pta.x < ptb.x then + if pta.x < ptb.x then heading = 0 elseif pta.z < ptb.z then heading = 1 diff --git a/sys/apis/proxy.lua b/sys/apis/proxy.lua deleted file mode 100644 index eb3d819..0000000 --- a/sys/apis/proxy.lua +++ /dev/null @@ -1,32 +0,0 @@ -local Socket = require('socket') - -local Proxy = { } - -function Proxy.create(remoteId, uri) - local socket, msg = Socket.connect(remoteId, 188) - - if not socket then - error(msg) - end - - socket.co = coroutine.running() - - socket:write(uri) - local methods = socket:read(2) or error('Timed out') - - local hijack = { } - for _,method in pairs(methods) do - hijack[method] = function(...) - socket:write({ method, ... }) - local resp = socket:read() - if not resp then - error('timed out: ' .. method) - end - return table.unpack(resp) - end - end - - return hijack, socket -end - -return Proxy diff --git a/sys/apis/rttp.lua b/sys/apis/rttp.lua deleted file mode 100644 index 8696e9e..0000000 --- a/sys/apis/rttp.lua +++ /dev/null @@ -1,95 +0,0 @@ -local device = _G.device -local os = _G.os - -local rttp = { } -local computerId = os.getComputerID() - -local function parse(url, default) - -- initialize default parameters - local parsed = {} - local authority - - for i,v in pairs(default or parsed) do parsed[i] = v end - -- remove whitespace - -- url = string.gsub(url, "%s", "") - -- Decode unreserved characters - url = string.gsub(url, "%%(%x%x)", function(hex) - local char = string.char(tonumber(hex, 16)) - if string.match(char, "[a-zA-Z0-9._~-]") then - return char - end - -- Hex encodings that are not unreserved must be preserved. - return nil - end) - -- get fragment - url = string.gsub(url, "#(.*)$", function(f) - parsed.fragment = f - return "" - end) - -- get scheme. Lower-case according to RFC 3986 section 3.1. - url = string.gsub(url, "^(%w[%w.+-]*):", - function(s) parsed.scheme = string.lower(s); return "" end) - -- get authority - url = string.gsub(url, "^//([^/]*)", function(n) - authority = n - return "" - end) - -- get query stringing - url = string.gsub(url, "%?(.*)", function(q) - parsed.query = q - return "" - end) - -- get params - url = string.gsub(url, "%;(.*)", function(p) - parsed.params = p - return "" - end) - - -- path is whatever was left - parsed.path = url - - -- Represents host:port, port = nil if not used. - if authority then - authority = string.gsub(authority, ":(%d+)$", - function(p) parsed.port = tonumber(p); return "" end) - if authority ~= "" then - parsed.host = authority - end - end - return parsed -end - -function rttp.get(url) - local modem = device.wireless_modem or error('Modem not found') - local parsed = parse(url, { port = 80 }) - - parsed.host = tonumber(parsed.host) or error('Invalid url') - - for i = 16384, 32767 do - if not modem.isOpen(i) then - modem.open(i) - local path = parsed.query and parsed.path .. '?' .. parsed.query or parsed.path - - modem.transmit(parsed.port, parsed.host, { - method = 'GET', - replyAddress = computerId, - replyPort = i, - path = path, - }) - local timerId = os.startTimer(3) - repeat - local event, id, dport, dhost, response = os.pullEvent() - if event == 'modem_message' and - dport == i and - dhost == computerId and - type(response) == 'table' then - modem.close(i) - return true, response - end - until event == 'timer' and id == timerId - return false, 'timeout' - end - end -end - -return rttp diff --git a/sys/apis/sha2.lua b/sys/apis/sha2.lua new file mode 100644 index 0000000..f7965bc --- /dev/null +++ b/sys/apis/sha2.lua @@ -0,0 +1,200 @@ +-- SHA-256, HMAC and PBKDF2 functions in ComputerCraft +-- By Anavrins + +local bit = _G.bit + +local mod32 = 2^32 +local band = bit32 and bit32.band or bit.band +local bnot = bit32 and bit32.bnot or bit.bnot +local bxor = bit32 and bit32.bxor or bit.bxor +local blshift = bit32 and bit32.lshift or bit.blshift +local upack = unpack + +local function rrotate(n, b) + local s = n/(2^b) + local f = s%1 + return (s-f) + f*mod32 +end +local function brshift(int, by) + local s = int / (2^by) + return s - s%1 +end + +local H = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, +} + +local K = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +} + +local function counter(incr) + local t1, t2 = 0, 0 + if 0xFFFFFFFF - t1 < incr then + t2 = t2 + 1 + t1 = incr - (0xFFFFFFFF - t1) - 1 + else t1 = t1 + incr + end + return t2, t1 +end + +local function BE_toInt(bs, i) + return blshift((bs[i] or 0), 24) + blshift((bs[i+1] or 0), 16) + blshift((bs[i+2] or 0), 8) + (bs[i+3] or 0) +end + +local function preprocess(data) + local len = #data + local proc = {} + data[#data+1] = 0x80 + while #data%64~=56 do data[#data+1] = 0 end + local blocks = math.ceil(#data/64) + for i = 1, blocks do + proc[i] = {} + for j = 1, 16 do + proc[i][j] = BE_toInt(data, 1+((i-1)*64)+((j-1)*4)) + end + end + proc[blocks][15], proc[blocks][16] = counter(len*8) + return proc +end + +local function digestblock(w, C) + for j = 17, 64 do + --local v = w[j-15] + local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3)) + local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10)) + w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32 + end + local a, b, c, d, e, f, g, h = upack(C) + for j = 1, 64 do + local S1 = bxor(bxor(rrotate(e, 6), rrotate(e, 11)), rrotate(e, 25)) + local ch = bxor(band(e, f), band(bnot(e), g)) + local temp1 = (h + S1 + ch + K[j] + w[j])%mod32 + local S0 = bxor(bxor(rrotate(a, 2), rrotate(a, 13)), rrotate(a, 22)) + local maj = bxor(bxor(band(a, b), band(a, c)), band(b, c)) + local temp2 = (S0 + maj)%mod32 + h, g, f, e, d, c, b, a = g, f, e, (d+temp1)%mod32, c, b, a, (temp1+temp2)%mod32 + end + C[1] = (C[1] + a)%mod32 + C[2] = (C[2] + b)%mod32 + C[3] = (C[3] + c)%mod32 + C[4] = (C[4] + d)%mod32 + C[5] = (C[5] + e)%mod32 + C[6] = (C[6] + f)%mod32 + C[7] = (C[7] + g)%mod32 + C[8] = (C[8] + h)%mod32 + return C +end + +local mt = { + __tostring = function(a) return string.char(unpack(a)) end, + __index = { + toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end, + isEqual = function(self, t) + if type(t) ~= "table" then return false end + if #self ~= #t then return false end + local ret = 0 + for i = 1, #self do + ret = bit32.bor(ret, bxor(self[i], t[i])) + end + return ret == 0 + end + } +} + +local function toBytes(t, n) + local b = {} + for i = 1, n do + b[(i-1)*4+1] = band(brshift(t[i], 24), 0xFF) + b[(i-1)*4+2] = band(brshift(t[i], 16), 0xFF) + b[(i-1)*4+3] = band(brshift(t[i], 8), 0xFF) + b[(i-1)*4+4] = band(t[i], 0xFF) + end + return setmetatable(b, mt) +end + +local function digest(data) + data = data or "" + data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} + + data = preprocess(data) + local C = {upack(H)} + for i = 1, #data do C = digestblock(data[i], C) end + return toBytes(C, 8) +end + +local function hmac(data, key) + data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} + key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)} + + local blocksize = 64 + + key = #key > blocksize and digest(key) or key + + local ipad = {} + local opad = {} + local padded_key = {} + + for i = 1, blocksize do + ipad[i] = bxor(0x36, key[i] or 0) + opad[i] = bxor(0x5C, key[i] or 0) + end + + for i = 1, #data do + ipad[blocksize+i] = data[i] + end + + ipad = digest(ipad) + + for i = 1, blocksize do + padded_key[i] = opad[i] + padded_key[blocksize+i] = ipad[i] + end + + return digest(padded_key) +end + +local function pbkdf2(pass, salt, iter, dklen) + local hashlen = 32 + local block = 1 + local out = {} + + dklen = dklen or 32 + salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} + + while dklen > 0 do + local ikey = {} + local isalt = {upack(salt)} + local clen = dklen > hashlen and hashlen or dklen + + isalt[#isalt+1] = band(brshift(block, 24), 0xFF) + isalt[#isalt+1] = band(brshift(block, 16), 0xFF) + isalt[#isalt+1] = band(brshift(block, 8), 0xFF) + isalt[#isalt+1] = band(block, 0xFF) + + for j = 1, iter do + isalt = hmac(isalt, pass) + for k = 1, clen do ikey[k] = bxor(isalt[k], ikey[k] or 0) end + if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end + end + dklen = dklen - clen + block = block+1 + for k = 1, clen do out[#out+1] = ikey[k] end + end + + return setmetatable(out, mt) +end + +return { + digest = digest, + hmac = hmac, + pbkdf2 = pbkdf2, +} \ No newline at end of file diff --git a/sys/apis/sync.lua b/sys/apis/sync.lua index 7987cb4..fd3402c 100644 --- a/sys/apis/sync.lua +++ b/sys/apis/sync.lua @@ -1,61 +1,61 @@ local Sync = { - syncLocks = { } + syncLocks = { } } local os = _G.os function Sync.sync(obj, fn) - local key = tostring(obj) - if Sync.syncLocks[key] then - local cos = tostring(coroutine.running()) - table.insert(Sync.syncLocks[key], cos) - repeat - local _, co = os.pullEvent('sync_lock') - until co == cos - else - Sync.syncLocks[key] = { } - end - local s, m = pcall(fn) - local co = table.remove(Sync.syncLocks[key], 1) - if co then - os.queueEvent('sync_lock', co) - else - Sync.syncLocks[key] = nil - end - if not s then - error(m) - end + local key = tostring(obj) + if Sync.syncLocks[key] then + local cos = tostring(coroutine.running()) + table.insert(Sync.syncLocks[key], cos) + repeat + local _, co = os.pullEvent('sync_lock') + until co == cos + else + Sync.syncLocks[key] = { } + end + local s, m = pcall(fn) + local co = table.remove(Sync.syncLocks[key], 1) + if co then + os.queueEvent('sync_lock', co) + else + Sync.syncLocks[key] = nil + end + if not s then + error(m) + end end function Sync.lock(obj) - local key = tostring(obj) - if Sync.syncLocks[key] then - local cos = tostring(coroutine.running()) - table.insert(Sync.syncLocks[key], cos) - repeat - local _, co = os.pullEvent('sync_lock') - until co == cos - else - Sync.syncLocks[key] = { } - end + local key = tostring(obj) + if Sync.syncLocks[key] then + local cos = tostring(coroutine.running()) + table.insert(Sync.syncLocks[key], cos) + repeat + local _, co = os.pullEvent('sync_lock') + until co == cos + else + Sync.syncLocks[key] = { } + end end function Sync.release(obj) - local key = tostring(obj) - if not Sync.syncLocks[key] then - error('Sync.release: Lock was not obtained', 2) - end - local co = table.remove(Sync.syncLocks[key], 1) - if co then - os.queueEvent('sync_lock', co) - else - Sync.syncLocks[key] = nil - end + local key = tostring(obj) + if not Sync.syncLocks[key] then + error('Sync.release: Lock was not obtained', 2) + end + local co = table.remove(Sync.syncLocks[key], 1) + if co then + os.queueEvent('sync_lock', co) + else + Sync.syncLocks[key] = nil + end end function Sync.isLocked(obj) - local key = tostring(obj) - return not not Sync.syncLocks[key] + local key = tostring(obj) + return not not Sync.syncLocks[key] end return Sync diff --git a/sys/apis/trace.lua b/sys/apis/trace.lua index 4323003..5673b6d 100644 --- a/sys/apis/trace.lua +++ b/sys/apis/trace.lua @@ -5,106 +5,106 @@ local type = type local debug_traceback = type(debug) == "table" and type(debug.traceback) == "function" and debug.traceback local function traceback(x) - -- Attempt to detect error() and error("xyz", 0). - -- This probably means they're erroring the program intentionally and so we - -- shouldn't display anything. - if x == nil or (type(x) == "string" and not x:find(":%d+:")) then - return x - end + -- Attempt to detect error() and error("xyz", 0). + -- This probably means they're erroring the program intentionally and so we + -- shouldn't display anything. + if x == nil or (type(x) == "string" and not x:find(":%d+:")) then + return x + end - if debug_traceback then - -- The parens are important, as they prevent a tail call occuring, meaning - -- the stack level is preserved. This ensures the code behaves identically - -- on LuaJ and PUC Lua. - return (debug_traceback(tostring(x), 2)) - else - local level = 3 - local out = { tostring(x), "stack traceback:" } - while true do - local _, msg = pcall(error, "", level) - if msg == "" then break end + if debug_traceback then + -- The parens are important, as they prevent a tail call occuring, meaning + -- the stack level is preserved. This ensures the code behaves identically + -- on LuaJ and PUC Lua. + return (debug_traceback(tostring(x), 2)) + else + local level = 3 + local out = { tostring(x), "stack traceback:" } + while true do + local _, msg = pcall(error, "", level) + if msg == "" then break end - out[#out + 1] = " " .. msg - level = level + 1 - end + out[#out + 1] = " " .. msg + level = level + 1 + end - return table.concat(out, "\n") - end + return table.concat(out, "\n") + end end local function trim_traceback(target, marker) - local ttarget, tmarker = {}, {} - for line in target:gmatch("([^\n]*)\n?") do ttarget[#ttarget + 1] = line end - for line in marker:gmatch("([^\n]*)\n?") do tmarker[#tmarker + 1] = line end + local ttarget, tmarker = {}, {} + for line in target:gmatch("([^\n]*)\n?") do ttarget[#ttarget + 1] = line end + for line in marker:gmatch("([^\n]*)\n?") do tmarker[#tmarker + 1] = line end - -- 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 + -- 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 - -- Trim elements from this file and xpcall invocations - while t_len >= 1 and ttarget[t_len]:find("^\tstack_trace%.lua:%d+:") or - ttarget[t_len] == "\t[C]: in function 'xpcall'" or ttarget[t_len] == " xpcall: " do - table.remove(ttarget, t_len) - t_len = t_len - 1 - end + -- Trim elements from this file and xpcall invocations + while t_len >= 1 and ttarget[t_len]:find("^\tstack_trace%.lua:%d+:") or + ttarget[t_len] == "\t[C]: in function 'xpcall'" or ttarget[t_len] == " xpcall: " do + table.remove(ttarget, t_len) + t_len = t_len - 1 + end - ttarget[#ttarget] = nil -- remove 2 calls added by the added xpcall - ttarget[#ttarget] = nil + ttarget[#ttarget] = nil -- remove 2 calls added by the added xpcall + ttarget[#ttarget] = nil - return ttarget + return ttarget end --- Run a function with 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 = { ... } + -- 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 - -- which is not ideal - local res = table.pack(xpcall(function() - return fn(table.unpack(args)) - end, traceback)) + -- xpcall in Lua 5.1 does not accept parameters + -- which is not ideal + local res = table.pack(xpcall(function() + return fn(table.unpack(args)) + end, traceback)) - if not res[1] then - trace = traceback("trace.lua:1:") - end - local ok, err = res[1], res[2] + if not res[1] then + trace = traceback("trace.lua:1:") + end + local ok, err = res[1], res[2] - if not ok and err ~= nil then - trace = trim_traceback(err, trace) + if not ok and err ~= nil then + trace = trim_traceback(err, trace) - -- Find the position where the stack traceback actually starts - local trace_starts - for i = #trace, 1, -1 do - if trace[i] == "stack traceback:" then trace_starts = i; break end - end + -- Find the position where the stack traceback actually starts + local trace_starts + for i = #trace, 1, -1 do + if trace[i] == "stack traceback:" then trace_starts = i; break end + end - for _, line in pairs(trace) do - _G._syslog(line) - end + for _, line in pairs(trace) do + _G._syslog(line) + end - -- If this traceback is more than 15 elements long, keep the first 9, last 5 - -- and put an ellipsis between the rest - local max = 10 - 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 - table.insert(trace, keep_starts, " ...") - end + -- If this traceback is more than 15 elements long, keep the first 9, last 5 + -- and put an ellipsis between the rest + local max = 10 + 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 + table.insert(trace, keep_starts, " ...") + end - for k, line in pairs(trace) do - trace[k] = line:gsub("in function", " in") - end + for k, line in pairs(trace) do + trace[k] = line:gsub("in function", " in") + end - return false, table.remove(trace, 1), table.concat(trace, "\n") - end + return false, table.remove(trace, 1), table.concat(trace, "\n") + end - return table.unpack(res, 1, res.n) + return table.unpack(res, 1, res.n) end diff --git a/sys/apis/ui/components/Grid.lua b/sys/apis/ui/components/Grid.lua index 262faee..21069ee 100644 --- a/sys/apis/ui/components/Grid.lua +++ b/sys/apis/ui/components/Grid.lua @@ -329,23 +329,13 @@ function UI.Grid:drawRows() local rawRow = self.values[key] local row = self:getDisplayValues(rawRow, key) - local ind = ' ' - if self.focused and index == self.index and not self.inactive then - ind = self.focusIndicator - end - local selected = index == self.index and not self.inactive local bg = self:getRowBackgroundColor(rawRow, selected) local fg = self:getRowTextColor(rawRow, selected) + local focused = self.focused and selected + + self:drawRow(sb, row, focused, bg, fg) - for _,col in pairs(self.columns) do - sb:write(ind .. safeValue(row[col.key] or ''), - col.cw + 1, - col.align, - bg, - fg) - ind = ' ' - end sb:finish(bg) end @@ -354,6 +344,19 @@ function UI.Grid:drawRows() end end +function UI.Grid:drawRow(sb, row, focused, bg, fg) + local ind = focused and self.focusIndicator or ' ' + + for _,col in pairs(self.columns) do + sb:write(ind .. safeValue(row[col.key] or ''), + col.cw + 1, + col.align, + bg, + fg) + ind = ' ' + end +end + function UI.Grid:getRowTextColor(row, selected) if selected then if self.focused then diff --git a/sys/apis/util.lua b/sys/apis/util.lua index e774ed9..042ba84 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -560,7 +560,7 @@ function Util.insertString(str, istr, pos) end function Util.split(str, pattern) - if not str then error('Util.split: Invalid parameters', 2) end + if not str or type(str) ~= 'string' then error('Util.split: Invalid parameters', 2) end pattern = pattern or "(.-)\n" local t = {} local function helper(line) table.insert(t, line) return "" end diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index f7564ed..ea3126d 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -15,11 +15,11 @@ local FILE = 1 UI:configure('Files', ...) local config = Config.load('Files', { - showHidden = false, - showDirSizes = false, + showHidden = false, + showDirSizes = false, }) config.associations = config.associations or { - nft = 'pain', + nft = 'pain', } local copied = { } @@ -28,517 +28,517 @@ local directories = { } local cutMode = false local function formatSize(size) - if size >= 1000000 then - return string.format('%dM', math.floor(size/1000000, 2)) - elseif size >= 1000 then - return string.format('%dK', math.floor(size/1000, 2)) - end - return size + if size >= 1000000 then + return string.format('%dM', math.floor(size/1000000, 2)) + elseif size >= 1000 then + return string.format('%dK', math.floor(size/1000, 2)) + end + return size end local Browser = UI.Page { - menuBar = UI.MenuBar { - buttons = { - { text = '^-', event = 'updir' }, - { text = 'File', dropdown = { - { text = 'Run', event = 'run', flags = FILE }, - { text = 'Edit e', event = 'edit', flags = FILE }, - { text = 'Cloud edit c', event = 'cedit', flags = FILE }, - { text = 'Pastebin put p', event = 'pastebin', flags = FILE }, - { text = 'Shell s', event = 'shell' }, - { spacer = true }, - { text = 'Quit q', event = 'quit' }, - } }, - { text = 'Edit', dropdown = { - { text = 'Cut ^x', event = 'cut' }, - { text = 'Copy ^c', event = 'copy' }, - { text = 'Copy path ', event = 'copy_path' }, - { text = 'Paste ^v', event = 'paste' }, - { spacer = true }, - { text = 'Mark m', event = 'mark' }, - { text = 'Unmark all u', event = 'unmark' }, - { spacer = true }, - { text = 'Delete del', event = 'delete' }, - } }, - { text = 'View', dropdown = { - { text = 'Refresh r', event = 'refresh' }, - { text = 'Hidden ^h', event = 'toggle_hidden' }, - { text = 'Dir Size ^s', event = 'toggle_dirSize' }, - } }, - { text = '\187', - x = -3, - dropdown = { - { text = 'Associations', event = 'associate' }, - } }, - }, - }, - grid = UI.ScrollingGrid { - columns = { - { heading = 'Name', key = 'name' }, - { key = 'flags', width = 2 }, - { heading = 'Size', key = 'fsize', width = 5 }, - }, - sortColumn = 'name', - y = 2, ey = -2, - }, - statusBar = UI.StatusBar { - columns = { - { key = 'status' }, - { key = 'totalSize', width = 6 }, - }, - }, - notification = UI.Notification { }, - associations = UI.SlideOut { - backgroundColor = colors.cyan, - menuBar = UI.MenuBar { - buttons = { - { text = 'Save', event = 'save' }, - { text = 'Cancel', event = 'cancel' }, - }, - }, - grid = UI.ScrollingGrid { - x = 2, ex = -6, y = 3, ey = -5, - columns = { - { heading = 'Extension', key = 'name' }, - { heading = 'Program', key = 'value' }, - }, - autospace = true, - sortColumn = 'name', - accelerators = { - delete = 'remove_entry', - }, - }, - remove = UI.Button { - x = -4, y = 6, - text = '-', event = 'remove_entry', help = 'Remove', - }, - form = UI.Form { - x = 3, y = -3, ey = -2, - margin = 1, - manualControls = true, - [1] = UI.TextEntry { - width = 20, - formLabel = 'Extension', formKey = 'name', - shadowText = 'extension', - required = true, - limit = 64, - }, - [2] = UI.TextEntry { - width = 20, - formLabel = 'Program', formKey = 'value', - shadowText = 'program', - required = true, - limit = 128, - }, - add = UI.Button { - x = -11, y = 1, - text = 'Add', event = 'add_association', - }, - }, - statusBar = UI.StatusBar { - backgroundColor = colors.cyan, - }, - }, - accelerators = { - q = 'quit', - c = 'cedit', - e = 'edit', - s = 'shell', - p = 'pastebin', - r = 'refresh', - [ ' ' ] = 'mark', - m = 'mark', - backspace = 'updir', - u = 'unmark', - d = 'delete', - delete = 'delete', - [ 'control-h' ] = 'toggle_hidden', - [ 'control-s' ] = 'toggle_dirSize', - [ 'control-x' ] = 'cut', - [ 'control-c' ] = 'copy', - paste = 'paste', - }, + menuBar = UI.MenuBar { + buttons = { + { text = '^-', event = 'updir' }, + { text = 'File', dropdown = { + { text = 'Run', event = 'run', flags = FILE }, + { text = 'Edit e', event = 'edit', flags = FILE }, + { text = 'Cloud edit c', event = 'cedit', flags = FILE }, + { text = 'Pastebin put p', event = 'pastebin', flags = FILE }, + { text = 'Shell s', event = 'shell' }, + { spacer = true }, + { text = 'Quit q', event = 'quit' }, + } }, + { text = 'Edit', dropdown = { + { text = 'Cut ^x', event = 'cut' }, + { text = 'Copy ^c', event = 'copy' }, + { text = 'Copy path ', event = 'copy_path' }, + { text = 'Paste ^v', event = 'paste' }, + { spacer = true }, + { text = 'Mark m', event = 'mark' }, + { text = 'Unmark all u', event = 'unmark' }, + { spacer = true }, + { text = 'Delete del', event = 'delete' }, + } }, + { text = 'View', dropdown = { + { text = 'Refresh r', event = 'refresh' }, + { text = 'Hidden ^h', event = 'toggle_hidden' }, + { text = 'Dir Size ^s', event = 'toggle_dirSize' }, + } }, + { text = '\187', + x = -3, + dropdown = { + { text = 'Associations', event = 'associate' }, + } }, + }, + }, + grid = UI.ScrollingGrid { + columns = { + { heading = 'Name', key = 'name' }, + { key = 'flags', width = 2 }, + { heading = 'Size', key = 'fsize', width = 5 }, + }, + sortColumn = 'name', + y = 2, ey = -2, + }, + statusBar = UI.StatusBar { + columns = { + { key = 'status' }, + { key = 'totalSize', width = 6 }, + }, + }, + notification = UI.Notification { }, + associations = UI.SlideOut { + backgroundColor = colors.cyan, + menuBar = UI.MenuBar { + buttons = { + { text = 'Save', event = 'save' }, + { text = 'Cancel', event = 'cancel' }, + }, + }, + grid = UI.ScrollingGrid { + x = 2, ex = -6, y = 3, ey = -5, + columns = { + { heading = 'Extension', key = 'name' }, + { heading = 'Program', key = 'value' }, + }, + autospace = true, + sortColumn = 'name', + accelerators = { + delete = 'remove_entry', + }, + }, + remove = UI.Button { + x = -4, y = 6, + text = '-', event = 'remove_entry', help = 'Remove', + }, + form = UI.Form { + x = 3, y = -3, ey = -2, + margin = 1, + manualControls = true, + [1] = UI.TextEntry { + width = 20, + formLabel = 'Extension', formKey = 'name', + shadowText = 'extension', + required = true, + limit = 64, + }, + [2] = UI.TextEntry { + width = 20, + formLabel = 'Program', formKey = 'value', + shadowText = 'program', + required = true, + limit = 128, + }, + add = UI.Button { + x = -11, y = 1, + text = 'Add', event = 'add_association', + }, + }, + statusBar = UI.StatusBar { + backgroundColor = colors.cyan, + }, + }, + accelerators = { + q = 'quit', + c = 'cedit', + e = 'edit', + s = 'shell', + p = 'pastebin', + r = 'refresh', + [ ' ' ] = 'mark', + m = 'mark', + backspace = 'updir', + u = 'unmark', + d = 'delete', + delete = 'delete', + [ 'control-h' ] = 'toggle_hidden', + [ 'control-s' ] = 'toggle_dirSize', + [ 'control-x' ] = 'cut', + [ 'control-c' ] = 'copy', + paste = 'paste', + }, } function Browser:enable() - UI.Page.enable(self) - self:setFocus(self.grid) + UI.Page.enable(self) + self:setFocus(self.grid) end function Browser.menuBar:getActive(menuItem) - local file = Browser.grid:getSelected() - if menuItem.flags == FILE then - return file and not file.isDir - end - return true + local file = Browser.grid:getSelected() + if menuItem.flags == FILE then + return file and not file.isDir + end + return true end function Browser.grid:sortCompare(a, b) - if self.sortColumn == 'fsize' then - return a.size < b.size - elseif self.sortColumn == 'flags' then - return a.flags < b.flags - end - if a.isDir == b.isDir then - return a.name:lower() < b.name:lower() - end - return a.isDir + if self.sortColumn == 'fsize' then + return a.size < b.size + elseif self.sortColumn == 'flags' then + return a.flags < b.flags + end + if a.isDir == b.isDir then + return a.name:lower() < b.name:lower() + end + return a.isDir end function Browser.grid:getRowTextColor(file) - if file.marked then - return colors.green - end - if file.isDir then - return colors.cyan - end - if file.isReadOnly then - return colors.pink - end - return colors.white + if file.marked then + return colors.green + end + if file.isDir then + return colors.cyan + end + if file.isReadOnly then + return colors.pink + end + return colors.white end function Browser.grid:eventHandler(event) - if event.type == 'copy' then -- let copy be handled by parent - return false - end - return UI.ScrollingGrid.eventHandler(self, event) + if event.type == 'copy' then -- let copy be handled by parent + return false + end + return UI.ScrollingGrid.eventHandler(self, event) end function Browser.statusBar:draw() - if self.parent.dir then - local info = '#:' .. Util.size(self.parent.dir.files) - local numMarked = Util.size(marked) - if numMarked > 0 then - info = info .. ' M:' .. numMarked - end - self:setValue('info', info) - self:setValue('totalSize', formatSize(self.parent.dir.totalSize)) - UI.StatusBar.draw(self) - end + if self.parent.dir then + local info = '#:' .. Util.size(self.parent.dir.files) + local numMarked = Util.size(marked) + if numMarked > 0 then + info = info .. ' M:' .. numMarked + end + self:setValue('info', info) + self:setValue('totalSize', formatSize(self.parent.dir.totalSize)) + UI.StatusBar.draw(self) + end end function Browser:setStatus(status, ...) - self.notification:info(string.format(status, ...)) + self.notification:info(string.format(status, ...)) end function Browser:unmarkAll() - for _,m in pairs(marked) do - m.marked = false - end - Util.clear(marked) + for _,m in pairs(marked) do + m.marked = false + end + Util.clear(marked) end function Browser:getDirectory(directory) - local s, dir = pcall(function() + local s, dir = pcall(function() - local dir = directories[directory] - if not dir then - dir = { - name = directory, - size = 0, - files = { }, - totalSize = 0, - index = 1 - } - directories[directory] = dir - end + local dir = directories[directory] + if not dir then + dir = { + name = directory, + size = 0, + files = { }, + totalSize = 0, + index = 1 + } + directories[directory] = dir + end - self:updateDirectory(dir) + self:updateDirectory(dir) - return dir - end) + return dir + end) - return s, dir + return s, dir end function Browser:updateDirectory(dir) - dir.size = 0 - dir.totalSize = 0 - Util.clear(dir.files) + dir.size = 0 + dir.totalSize = 0 + Util.clear(dir.files) - local files = fs.listEx(dir.name) - if files then - dir.size = #files - for _, file in pairs(files) do - file.fullName = fs.combine(dir.name, file.name) - file.flags = '' - if not file.isDir then - dir.totalSize = dir.totalSize + file.size - file.fsize = formatSize(file.size) - else - if config.showDirSizes then - file.size = fs.getSize(file.fullName, true) + local files = fs.listEx(dir.name) + if files then + dir.size = #files + for _, file in pairs(files) do + file.fullName = fs.combine(dir.name, file.name) + file.flags = '' + if not file.isDir then + dir.totalSize = dir.totalSize + file.size + file.fsize = formatSize(file.size) + else + if config.showDirSizes then + file.size = fs.getSize(file.fullName, true) - dir.totalSize = dir.totalSize + file.size - file.fsize = formatSize(file.size) - end - file.flags = 'D' - end - if file.isReadOnly then - file.flags = file.flags .. 'R' - end - if config.showHidden or file.name:sub(1, 1) ~= '.' then - dir.files[file.fullName] = file - end - end - end + dir.totalSize = dir.totalSize + file.size + file.fsize = formatSize(file.size) + end + file.flags = 'D' + end + if file.isReadOnly then + file.flags = file.flags .. 'R' + end + if config.showHidden or file.name:sub(1, 1) ~= '.' then + dir.files[file.fullName] = file + end + end + end -- self.grid:update() -- self.grid:setIndex(dir.index) - self.grid:setValues(dir.files) + self.grid:setValues(dir.files) end function Browser:setDir(dirName, noStatus) - self:unmarkAll() + self:unmarkAll() - if self.dir then - self.dir.index = self.grid:getIndex() - end - local DIR = fs.combine('', dirName) - shell.setDir(DIR) - local s, dir = self:getDirectory(DIR) - if s then - self.dir = dir - elseif noStatus then - error(dir) - else - self:setStatus(dir) - self:setDir('', true) - return - end + if self.dir then + self.dir.index = self.grid:getIndex() + end + local DIR = fs.combine('', dirName) + shell.setDir(DIR) + local s, dir = self:getDirectory(DIR) + if s then + self.dir = dir + elseif noStatus then + error(dir) + else + self:setStatus(dir) + self:setDir('', true) + return + end - if not noStatus then - self.statusBar:setValue('status', '/' .. self.dir.name) - self.statusBar:draw() - end - self.grid:setIndex(self.dir.index) + if not noStatus then + self.statusBar:setValue('status', '/' .. self.dir.name) + self.statusBar:draw() + end + self.grid:setIndex(self.dir.index) end function Browser:run(...) - if multishell then - local tabId = shell.openTab(...) - multishell.setFocus(tabId) - else - shell.run(...) - Event.terminate = false - self:draw() - end + if multishell then + local tabId = shell.openTab(...) + multishell.setFocus(tabId) + else + shell.run(...) + Event.terminate = false + self:draw() + end end function Browser:hasMarked() - if Util.size(marked) == 0 then - local file = self.grid:getSelected() - if file then - file.marked = true - marked[file.fullName] = file - self.grid:draw() - end - end - return Util.size(marked) > 0 + if Util.size(marked) == 0 then + local file = self.grid:getSelected() + if file then + file.marked = true + marked[file.fullName] = file + self.grid:draw() + end + end + return Util.size(marked) > 0 end function Browser:eventHandler(event) - local file = self.grid:getSelected() + local file = self.grid:getSelected() - if event.type == 'quit' then - Event.exitPullEvents() + if event.type == 'quit' then + Event.exitPullEvents() - elseif event.type == 'edit' and file then - self:run('edit', file.name) + elseif event.type == 'edit' and file then + self:run('edit', file.name) - elseif event.type == 'cedit' and file then - self:run('cedit', file.name) - self:setStatus('Started cloud edit') + elseif event.type == 'cedit' and file then + self:run('cedit', file.name) + self:setStatus('Started cloud edit') - elseif event.type == 'shell' then - self:run('sys/apps/shell.lua') + elseif event.type == 'shell' then + self:run('sys/apps/shell.lua') - elseif event.type == 'refresh' then - self:updateDirectory(self.dir) - self.grid:draw() - self:setStatus('Refreshed') + elseif event.type == 'refresh' then + self:updateDirectory(self.dir) + self.grid:draw() + self:setStatus('Refreshed') - elseif event.type == 'associate' then - self.associations:show() + elseif event.type == 'associate' then + self.associations:show() - elseif event.type == 'pastebin' then - if file and not file.isDir then - local s, m = pastebin.put(file.fullName) - if s then - os.queueEvent('clipboard_copy', s) - self.notification:success(string.format('Uploaded as %s', s), 0) - else - self.notification:error(m) - end - end + elseif event.type == 'pastebin' then + if file and not file.isDir then + local s, m = pastebin.put(file.fullName) + if s then + os.queueEvent('clipboard_copy', s) + self.notification:success(string.format('Uploaded as %s', s), 0) + else + self.notification:error(m) + end + end - elseif event.type == 'toggle_hidden' then - config.showHidden = not config.showHidden - Config.update('Files', config) + elseif event.type == 'toggle_hidden' then + config.showHidden = not config.showHidden + Config.update('Files', config) - self:updateDirectory(self.dir) - self.grid:draw() - if not config.showHidden then - self:setStatus('Hiding hidden') - else - self:setStatus('Displaying hidden') - end + self:updateDirectory(self.dir) + self.grid:draw() + if not config.showHidden then + self:setStatus('Hiding hidden') + else + self:setStatus('Displaying hidden') + end - elseif event.type == 'toggle_dirSize' then - config.showDirSizes = not config.showDirSizes - Config.update('Files', config) + elseif event.type == 'toggle_dirSize' then + config.showDirSizes = not config.showDirSizes + Config.update('Files', config) - self:updateDirectory(self.dir) - self.grid:draw() - if config.showDirSizes then - self:setStatus('Displaying dir sizes') - end + self:updateDirectory(self.dir) + self.grid:draw() + if config.showDirSizes then + self:setStatus('Displaying dir sizes') + end - elseif event.type == 'mark' and file then - file.marked = not file.marked - if file.marked then - marked[file.fullName] = file - else - marked[file.fullName] = nil - end - self.grid:draw() - self.statusBar:draw() + elseif event.type == 'mark' and file then + file.marked = not file.marked + if file.marked then + marked[file.fullName] = file + else + marked[file.fullName] = nil + end + self.grid:draw() + self.statusBar:draw() - elseif event.type == 'unmark' then - self:unmarkAll() - self.grid:draw() - self:setStatus('Marked files cleared') + elseif event.type == 'unmark' then + self:unmarkAll() + self.grid:draw() + self:setStatus('Marked files cleared') - elseif event.type == 'grid_select' or event.type == 'run' then - if file then - if file.isDir then - self:setDir(file.fullName) - else - local ext = file.name:match('%.(%w+)$') - if ext and config.associations[ext] then - self:run(config.associations[ext], '/' .. file.fullName) - else - self:run(file.name) - end - end - end + elseif event.type == 'grid_select' or event.type == 'run' then + if file then + if file.isDir then + self:setDir(file.fullName) + else + local ext = file.name:match('%.(%w+)$') + if ext and config.associations[ext] then + self:run(config.associations[ext], '/' .. file.fullName) + else + self:run(file.name) + end + end + end - elseif event.type == 'updir' then - local dir = (self.dir.name:match("(.*/)")) - self:setDir(dir or '/') + elseif event.type == 'updir' then + local dir = (self.dir.name:match("(.*/)")) + self:setDir(dir or '/') - elseif event.type == 'delete' then - if self:hasMarked() then - local width = self.statusBar:getColumnWidth('status') - self.statusBar:setColumnWidth('status', UI.term.width) - self.statusBar:setValue('status', 'Delete marked? (y/n)') - self.statusBar:draw() - self.statusBar:sync() - local _, ch = os.pullEvent('char') - if ch == 'y' or ch == 'Y' then - for _,m in pairs(marked) do - pcall(function() - fs.delete(m.fullName) - end) - end - end - marked = { } - self.statusBar:setColumnWidth('status', width) - self.statusBar:setValue('status', '/' .. self.dir.name) - self:updateDirectory(self.dir) + elseif event.type == 'delete' then + if self:hasMarked() then + local width = self.statusBar:getColumnWidth('status') + self.statusBar:setColumnWidth('status', UI.term.width) + self.statusBar:setValue('status', 'Delete marked? (y/n)') + self.statusBar:draw() + self.statusBar:sync() + local _, ch = os.pullEvent('char') + if ch == 'y' or ch == 'Y' then + for _,m in pairs(marked) do + pcall(function() + fs.delete(m.fullName) + end) + end + end + marked = { } + self.statusBar:setColumnWidth('status', width) + self.statusBar:setValue('status', '/' .. self.dir.name) + self:updateDirectory(self.dir) - self.statusBar:draw() - self.grid:draw() - self:setFocus(self.grid) - end + self.statusBar:draw() + self.grid:draw() + self:setFocus(self.grid) + end - elseif event.type == 'copy' or event.type == 'cut' then - if self:hasMarked() then - cutMode = event.type == 'cut' - Util.clear(copied) - Util.merge(copied, marked) - --self:unmarkAll() - self.grid:draw() - self:setStatus('Copied %d file(s)', Util.size(copied)) - end + elseif event.type == 'copy' or event.type == 'cut' then + if self:hasMarked() then + cutMode = event.type == 'cut' + Util.clear(copied) + Util.merge(copied, marked) + --self:unmarkAll() + self.grid:draw() + self:setStatus('Copied %d file(s)', Util.size(copied)) + end - elseif event.type == 'copy_path' then - if file then - os.queueEvent('clipboard_copy', file.fullName) - end + elseif event.type == 'copy_path' then + if file then + os.queueEvent('clipboard_copy', file.fullName) + end - elseif event.type == 'paste' then - for _,m in pairs(copied) do - local s, m = pcall(function() - if cutMode then - fs.move(m.fullName, fs.combine(self.dir.name, m.name)) - else - fs.copy(m.fullName, fs.combine(self.dir.name, m.name)) - end - end) - end - self:updateDirectory(self.dir) - self.grid:draw() - self:setStatus('Pasted ' .. Util.size(copied) .. ' file(s)') + elseif event.type == 'paste' then + for _,m in pairs(copied) do + local s, m = pcall(function() + if cutMode then + fs.move(m.fullName, fs.combine(self.dir.name, m.name)) + else + fs.copy(m.fullName, fs.combine(self.dir.name, m.name)) + end + end) + end + self:updateDirectory(self.dir) + self.grid:draw() + self:setStatus('Pasted ' .. Util.size(copied) .. ' file(s)') - else - return UI.Page.eventHandler(self, event) - end - self:setFocus(self.grid) - return true + else + return UI.Page.eventHandler(self, event) + end + self:setFocus(self.grid) + return true end --[[ Associations slide out ]] -- function Browser.associations:show() - self.grid.values = { } - for k, v in pairs(config.associations) do - table.insert(self.grid.values, { - name = k, - value = v, - }) - end - self.grid:update() - UI.SlideOut.show(self) - self:setFocus(self.form[1]) + self.grid.values = { } + for k, v in pairs(config.associations) do + table.insert(self.grid.values, { + name = k, + value = v, + }) + end + self.grid:update() + UI.SlideOut.show(self) + self:setFocus(self.form[1]) end function Browser.associations:eventHandler(event) - if event.type == 'remove_entry' then - local row = self.grid:getSelected() - if row then - Util.removeByValue(self.grid.values, row) - self.grid:update() - self.grid:draw() - end + if event.type == 'remove_entry' then + local row = self.grid:getSelected() + if row then + Util.removeByValue(self.grid.values, row) + self.grid:update() + self.grid:draw() + end - elseif event.type == 'add_association' then - if self.form:save() then - local entry = Util.find(self.grid.values, 'name', self.form[1].value) or { } - entry.name = self.form[1].value - entry.value = self.form[2].value - table.insert(self.grid.values, entry) - self.form[1]:reset() - self.form[2]:reset() - self.grid:update() - self.grid:draw() - end + elseif event.type == 'add_association' then + if self.form:save() then + local entry = Util.find(self.grid.values, 'name', self.form[1].value) or { } + entry.name = self.form[1].value + entry.value = self.form[2].value + table.insert(self.grid.values, entry) + self.form[1]:reset() + self.form[2]:reset() + self.grid:update() + self.grid:draw() + end - elseif event.type == 'cancel' then - self:hide() + elseif event.type == 'cancel' then + self:hide() - elseif event.type == 'save' then - config.associations = { } - for _, v in pairs(self.grid.values) do - config.associations[v.name] = v.value - end - Config.update('Files', config) - self:hide() + elseif event.type == 'save' then + config.associations = { } + for _, v in pairs(self.grid.values) do + config.associations[v.name] = v.value + end + Config.update('Files', config) + self:hide() - else - return UI.SlideOut.eventHandler(self, event) - end - return true + else + return UI.SlideOut.eventHandler(self, event) + end + return true end --[[-- Startup logic --]]-- diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index 4eba8ab..bfc080b 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -294,7 +294,6 @@ end function page:rawExecute(s) local fn, m local wrapped - local t = os.clock() fn = load('return (' ..s.. ')', 'lua', nil, sandboxEnv) @@ -303,6 +302,7 @@ function page:rawExecute(s) wrapped = true end + local t = os.clock() if fn then fn, m = pcall(fn) if #m <= 1 and wrapped then @@ -311,19 +311,24 @@ function page:rawExecute(s) else fn, m = load(s, 'lua', nil, sandboxEnv) if fn then + t = os.clock() fn, m = pcall(fn) end end if fn then + t = os.clock() - t + + local bg, fg = term.getBackgroundColor(), term.getTextColor() + term.setTextColor(colors.cyan) + term.setBackgroundColor(colors.black) + term.write(string.format('out [%.2f]: ', t)) + term.setBackgroundColor(bg) + term.setTextColor(fg) if m or wrapped then - local bg, fg = term.getBackgroundColor(), term.getTextColor() - term.setTextColor(colors.cyan) - term.setBackgroundColor(colors.black) - term.write(string.format('out [%.2f]: ', os.clock() - t)) - term.setBackgroundColor(bg) - term.setTextColor(fg) Util.print(m or 'nil') + else + print() end else _G.printError(m) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 8b7b7b2..e6341eb 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -127,12 +127,14 @@ local function sendCommand(host, command) end end +--[[ function page.ports:eventHandler(event) if event.type == 'grid_select' then shell.openForegroundTab('sniff ' .. event.selected.port) end return UI.SlideOut.eventHandler(self, event) end +]] function page.ports.grid:update() local function findConnection(port) diff --git a/sys/apps/ShellLauncher.lua b/sys/apps/ShellLauncher.lua index 9407e46..d905653 100644 --- a/sys/apps/ShellLauncher.lua +++ b/sys/apps/ShellLauncher.lua @@ -5,23 +5,23 @@ local shell = _ENV.shell local launcherTab = kernel.getCurrent() kernel.hook('kernel_focus', function(_, eventData) - local focusTab = eventData and eventData[1] - if focusTab == launcherTab.uid then - local previousTab = eventData[2] - local nextTab = launcherTab - if not previousTab then - for _, v in pairs(kernel.routines) do - if not v.hidden and v.uid > nextTab.uid then - nextTab = v - end - end - end - if nextTab == launcherTab then - shell.switchTab(shell.openTab('sys/apps/shell.lua')) - else - shell.switchTab(nextTab.uid) - end - end + local focusTab = eventData and eventData[1] + if focusTab == launcherTab.uid then + local previousTab = eventData[2] + local nextTab = launcherTab + if not previousTab then + for _, v in pairs(kernel.routines) do + if not v.hidden and v.uid > nextTab.uid then + nextTab = v + end + end + end + if nextTab == launcherTab then + shell.switchTab(shell.openTab('sys/apps/shell.lua')) + else + shell.switchTab(nextTab.uid) + end + end end) -while os.pullEventRaw() do end \ No newline at end of file +os.pullEventRaw('kernel_halt') \ No newline at end of file diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index e735840..80d170e 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -23,115 +23,115 @@ local packagesIntro = [[Setup Complete local page = UI.Page { wizard = UI.Wizard { - ey = -2, + ey = -2, pages = { splash = UI.WizardPage { - index = 1, - intro = UI.TextArea { - textColor = colors.yellow, - inactive = true, - x = 3, ex = -3, y = 2, ey = -2, - value = string.format(splashIntro, Ansi.white), - }, - }, + index = 1, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 2, ey = -2, + value = string.format(splashIntro, Ansi.white), + }, + }, label = UI.WizardPage { - index = 2, - labelText = UI.Text { - x = 3, y = 2, - value = 'Label' - }, - label = UI.TextEntry { - x = 9, y = 2, ex = -3, - limit = 32, - value = os.getComputerLabel(), - }, - intro = UI.TextArea { - textColor = colors.yellow, - inactive = true, - x = 3, ex = -3, y = 4, ey = -3, - value = string.format(labelIntro, Ansi.white), - }, - }, + index = 2, + labelText = UI.Text { + x = 3, y = 2, + value = 'Label' + }, + label = UI.TextEntry { + x = 9, y = 2, ex = -3, + limit = 32, + value = os.getComputerLabel(), + }, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 4, ey = -3, + value = string.format(labelIntro, Ansi.white), + }, + }, password = UI.WizardPage { index = 3, - passwordLabel = UI.Text { - x = 3, y = 2, - value = 'Password' - }, - newPass = UI.TextEntry { - x = 12, ex = -3, y = 2, - limit = 32, - mask = true, - shadowText = 'password', - }, + passwordLabel = UI.Text { + x = 3, y = 2, + value = 'Password' + }, + newPass = UI.TextEntry { + x = 12, ex = -3, y = 2, + limit = 32, + mask = true, + shadowText = 'password', + }, --[[ - groupLabel = UI.Text { - x = 3, y = 3, - value = 'Group' - }, - group = UI.TextEntry { - x = 12, ex = -3, y = 3, - limit = 32, - shadowText = 'network group', - }, + groupLabel = UI.Text { + x = 3, y = 3, + value = 'Group' + }, + group = UI.TextEntry { + x = 12, ex = -3, y = 3, + limit = 32, + shadowText = 'network group', + }, ]] - intro = UI.TextArea { - textColor = colors.yellow, - inactive = true, - x = 3, ex = -3, y = 5, ey = -3, - value = string.format(passwordIntro, Ansi.white), - }, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 5, ey = -3, + value = string.format(passwordIntro, Ansi.white), + }, }, packages = UI.WizardPage { index = 4, - button = UI.Button { - x = 3, y = -3, - text = 'Open Package Manager', - event = 'packages', - }, - intro = UI.TextArea { - textColor = colors.yellow, - inactive = true, - x = 3, ex = -3, y = 2, ey = -4, - value = string.format(packagesIntro, Ansi.white), - }, + button = UI.Button { + x = 3, y = -3, + text = 'Open Package Manager', + event = 'packages', + }, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 2, ey = -4, + value = string.format(packagesIntro, Ansi.white), + }, }, }, - }, - notification = UI.Notification { }, + }, + notification = UI.Notification { }, } function page.wizard.pages.label:validate() - os.setComputerLabel(self.label.value) - return true + os.setComputerLabel(self.label.value) + return true end function page.wizard.pages.password:validate() - if #self.newPass.value > 0 then - Security.updatePassword(SHA1.sha1(self.newPass.value)) - end - --[[ - if #self.group.value > 0 then - local config = Config.load('os') - config.group = self.group.value - Config.update('os', config) - end - ]] - return true + if #self.newPass.value > 0 then + Security.updatePassword(SHA1.sha1(self.newPass.value)) + end + --[[ + if #self.group.value > 0 then + local config = Config.load('os') + config.group = self.group.value + Config.update('os', config) + end + ]] + return true end function page:eventHandler(event) - if event.type == 'skip' then - self.wizard:emit({ type = 'nextView' }) + if event.type == 'skip' then + self.wizard:emit({ type = 'nextView' }) - elseif event.type == 'view_enabled' then - event.view:focusFirst() + elseif event.type == 'view_enabled' then + event.view:focusFirst() - elseif event.type == 'packages' then - shell.openForegroundTab('PackageManager') + elseif event.type == 'packages' then + shell.openForegroundTab('PackageManager') - elseif event.type == 'wizard_complete' or event.type == 'cancel' then - UI.exitPullEvents() + elseif event.type == 'wizard_complete' or event.type == 'cancel' then + UI.exitPullEvents() else return UI.Page.eventHandler(self, event) diff --git a/sys/apps/autorun.lua b/sys/apps/autorun.lua index 40e0e74..1d650da 100644 --- a/sys/apps/autorun.lua +++ b/sys/apps/autorun.lua @@ -11,60 +11,60 @@ local term = _G.term local success = true local function runDir(directory) - if not fs.exists(directory) then - return true - end + if not fs.exists(directory) then + return true + end - local files = fs.list(directory) - table.sort(files) + local files = fs.list(directory) + table.sort(files) - for _,file in ipairs(files) do - os.sleep(0) - local result, err = shell.run(directory .. '/' .. file) + for _,file in ipairs(files) do + os.sleep(0) + local result, err = shell.run(directory .. '/' .. file) - if result then - if term.isColor() then - term.setTextColor(colors.green) - end - term.write('[PASS] ') - term.setTextColor(colors.white) - term.write(fs.combine(directory, file)) - print() - else - if term.isColor() then - term.setTextColor(colors.red) - end - term.write('[FAIL] ') - term.setTextColor(colors.white) - term.write(fs.combine(directory, file)) - if err then - _G.printError('\n' .. err) - end - print() - success = false - end - end + if result then + if term.isColor() then + term.setTextColor(colors.green) + end + term.write('[PASS] ') + term.setTextColor(colors.white) + term.write(fs.combine(directory, file)) + print() + else + if term.isColor() then + term.setTextColor(colors.red) + end + term.write('[FAIL] ') + term.setTextColor(colors.white) + term.write(fs.combine(directory, file)) + if err then + _G.printError('\n' .. err) + end + print() + success = false + end + end end runDir('sys/autorun') for name in pairs(Packages:installed()) do - local packageDir = 'packages/' .. name .. '/autorun' - runDir(packageDir) + local packageDir = 'packages/' .. name .. '/autorun' + runDir(packageDir) end runDir('usr/autorun') if not success then - if multishell then - multishell.setFocus(multishell.getCurrent()) - end - _G.printError('A startup program has errored') - print('Press enter to continue') + if multishell then + multishell.setFocus(multishell.getCurrent()) + end + _G.printError('A startup program has errored') + print('Press enter to continue') - while true do - local e, code = os.pullEventRaw('key') - if e == 'terminate' or e == 'key' and code == keys.enter then - break - end - end + while true do + local e, code = os.pullEventRaw('key') + if e == 'terminate' or e == 'key' and code == keys.enter then + break + end + end end diff --git a/sys/apps/cedit.lua b/sys/apps/cedit.lua index f62a063..138f977 100644 --- a/sys/apps/cedit.lua +++ b/sys/apps/cedit.lua @@ -7,32 +7,32 @@ local shell = _ENV.shell local args = { ... } if not args[1] then - error('Syntax: cedit ') + error('Syntax: cedit ') end if not _G.http.websocket then - error('Requires CC: Tweaked') + error('Requires CC: Tweaked') end if not _G.cloud_catcher then - local key = Config.load('cloud').key + local key = Config.load('cloud').key - if not key then - print('Visit https://cloud-catcher.squiddev.cc') - print('Paste key: ') - key = read() - if #key == 0 then - return - end - end + if not key then + print('Visit https://cloud-catcher.squiddev.cc') + print('Paste key: ') + key = read() + if #key == 0 then + return + end + end - -- open an unfocused tab - local id = shell.openTab('cloud ' .. key) - print('Connecting...') - while not _G.cloud_catcher do - os.sleep(.2) - end - multishell.setTitle(id, 'Cloud') + -- open an unfocused tab + local id = shell.openTab('cloud ' .. key) + print('Connecting...') + while not _G.cloud_catcher do + os.sleep(.2) + end + multishell.setTitle(id, 'Cloud') end shell.run('cloud edit ' .. table.unpack({ ... })) diff --git a/sys/apps/cshell.lua b/sys/apps/cshell.lua index 44cee34..34e5c91 100644 --- a/sys/apps/cshell.lua +++ b/sys/apps/cshell.lua @@ -4,20 +4,20 @@ local read = _G.read local shell = _ENV.shell if not _G.http.websocket then - error('Requires CC: Tweaked') + error('Requires CC: Tweaked') end if not _G.cloud_catcher then - local key = Config.load('cloud').key + local key = Config.load('cloud').key - if not key then - print('Visit https://cloud-catcher.squiddev.cc') - print('Paste key: ') - key = read() - if #key == 0 then - return - end - end - print('Connecting...') - shell.run('cloud ' .. key) + if not key then + print('Visit https://cloud-catcher.squiddev.cc') + print('Paste key: ') + key = read() + if #key == 0 then + return + end + end + print('Connecting...') + shell.run('cloud ' .. key) end diff --git a/sys/apps/network/redserver.lua b/sys/apps/network/redserver.lua deleted file mode 100644 index 6c63d21..0000000 --- a/sys/apps/network/redserver.lua +++ /dev/null @@ -1,115 +0,0 @@ -local Event = require('event') -local Util = require('util') - -local fs = _G.fs -local modem = _G.device.wireless_modem -local os = _G.os - -local computerId = os.getComputerID() - ---modem.open(80) - --- https://github.com/golgote/neturl/blob/master/lib/net/url.lua -local function parseQuery(str) - local sep = '&' - - local values = {} - for key,val in str:gmatch(string.format('([^%q=]+)(=*[^%q=]*)', sep, sep)) do - --local key = decode(key) - local keys = {} - key = key:gsub('%[([^%]]*)%]', function(v) - -- extract keys between balanced brackets - if string.find(v, "^-?%d+$") then - v = tonumber(v) - --else - --v = decode(v) - end - table.insert(keys, v) - return "=" - end) - key = key:gsub('=+.*$', "") - key = key:gsub('%s', "_") -- remove spaces in parameter name - val = val:gsub('^=+', "") - - if not values[key] then - values[key] = {} - end - if #keys > 0 and type(values[key]) ~= 'table' then - values[key] = {} - elseif #keys == 0 and type(values[key]) == 'table' then - values[key] = val --decode(val) - end - - local t = values[key] - for i,k in ipairs(keys) do - if type(t) ~= 'table' then - t = {} - end - if k == "" then - k = #t+1 - end - if not t[k] then - t[k] = {} - end - if i == #keys then - t[k] = val --decode(val) - end - t = t[k] - end - end - return values -end - -local function getListing(path, recursive) - local list = { } - local function listing(p) - for _, f in pairs(fs.listEx(p)) do - local abs = fs.combine(p, f.name) - table.insert(list, { - isDir = f.isDir, - path = string.sub(abs, #path + 1), - size = f.size, - }) - if recursive and f.isDir then - listing(abs) - end - end - end - listing(path) - return list -end - ---[[ -Event.on('modem_message', function(_, _, dport, dhost, request) - if dport == 80 and dhost == computerId and type(request) == 'table' then - if request.method == 'GET' then - local query - if not request.path or type(request.path) ~= 'string' then - return - end - local path = request.path:gsub('%?(.*)', function(v) - query = parseQuery(v) - return '' - end) - if fs.isDir(path) then - -- TODO: more validation - modem.transmit(request.replyPort, request.replyAddress, { - statusCode = 200, - contentType = 'table/directory', - data = getListing(path, query and query.recursive == 'true'), - }) - elseif fs.exists(path) then - modem.transmit(request.replyPort, request.replyAddress, { - statusCode = 200, - contentType = 'table/file', - data = Util.readFile(path), - }) - else - modem.transmit(request.replyPort, request.replyAddress, { - statusCode = 404, - }) - end - end - end -end) -]] diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index 0e69a03..11ed673 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -156,7 +156,7 @@ local function sendInfo() info.label = os.getComputerLabel() info.uptime = math.floor(os.clock()) info.group = network.getGroup() - if turtle then + if turtle and turtle.getStatus then info.fuel = turtle.getFuelLevel() info.status = turtle.getStatus() info.point = turtle.point diff --git a/sys/apps/sniff.lua b/sys/apps/sniff.lua deleted file mode 100644 index ada3d77..0000000 --- a/sys/apps/sniff.lua +++ /dev/null @@ -1,69 +0,0 @@ -local Event = require('event') -local Terminal = require('terminal') -local Util = require('util') - -local colors = _G.colors -local modem = _G.device.wireless_modem -local term = _G.term -local textutils = _G.textutils - -local terminal = Terminal.window(term.current()) -terminal.setMaxScroll(300) -local oldTerm = term.redirect(terminal) - -local function syntax() - error('Syntax: sniff [port]') -end - -local port = ({ ... })[1] or syntax() -port = tonumber(port) or syntax() - -Event.on('modem_message', - function(_, _, dport, _, data, _) - if dport == port then - terminal.scrollBottom() - terminal.setTextColor(colors.white) - print(textutils.serialize(data)) - end - end) - -Event.on('mouse_scroll', function(_, direction) - if direction == -1 then - terminal.scrollUp() - else - terminal.scrollDown() - end -end) - -local function sniffer(_, _, data) - terminal.scrollBottom() - terminal.setTextColor(colors.yellow) - local ot = term.redirect(terminal) - print(textutils.serialize(data)) - term.redirect(ot) -end - -local socket = _G.transport.sockets[port] -if socket then - if not socket.sniffers then - socket.sniffers = { modem.transmit } - socket.transmit = function(...) - for _,v in pairs(socket.sniffers) do - v(...) - end - end - end - table.insert(socket.sniffers, sniffer) -end - -local s, m = pcall(Event.pullEvents) - -if socket then - Util.removeByValue(socket.sniffers, sniffer) -end - -term.redirect(oldTerm) - -if not s and m then - error(m) -end diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua index 434a16c..61d47f9 100644 --- a/sys/apps/system/cloud.lua +++ b/sys/apps/system/cloud.lua @@ -7,51 +7,51 @@ local colors = _G.colors -- -t80x30 if _G.http.websocket then - local config = Config.load('cloud') + local config = Config.load('cloud') - local tab = UI.Tab { - tabTitle = 'Cloud', - description = 'Cloud catcher options', - key = UI.TextEntry { - x = 3, ex = -3, y = 2, - limit = 32, - value = config.key, - shadowText = 'Cloud key', - accelerators = { - enter = 'update_key', - }, - }, - button = UI.Button { - x = 3, y = 4, - text = 'Update', - event = 'update_key', - }, - labelText = UI.TextArea { - x = 3, ex = -3, y = 6, - textColor = colors.yellow, - marginLeft = 0, marginRight = 0, - value = string.format( + local tab = UI.Tab { + tabTitle = 'Cloud', + description = 'Cloud catcher options', + key = UI.TextEntry { + x = 3, ex = -3, y = 2, + limit = 32, + value = config.key, + shadowText = 'Cloud key', + accelerators = { + enter = 'update_key', + }, + }, + button = UI.Button { + x = 3, y = 4, + text = 'Update', + event = 'update_key', + }, + labelText = UI.TextArea { + x = 3, ex = -3, y = 6, + textColor = colors.yellow, + marginLeft = 0, marginRight = 0, + value = string.format( [[Use a non-changing cloud key. Note that only a single computer can use this session at one time. To obtain a key, visit: %shttps://cloud-catcher.squiddev.cc%s then bookmark: %shttps://cloud-catcher.squiddev.cc/?id=KEY - ]], - Ansi.white, Ansi.reset, Ansi.white), - }, - } + ]], + Ansi.white, Ansi.reset, Ansi.white), + }, + } - function tab:eventHandler(event) - if event.type == 'update_key' then - if #self.key.value > 0 then - config.key = self.key.value - else - config.key = nil - end - Config.update('cloud', config) - self:emit({ type = 'success_message', message = 'Updated' }) - end - end + function tab:eventHandler(event) + if event.type == 'update_key' then + if #self.key.value > 0 then + config.key = self.key.value + else + config.key = nil + end + Config.update('cloud', config) + self:emit({ type = 'success_message', message = 'Updated' }) + end + end - return tab + return tab end diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua index 89a24e2..1adb110 100644 --- a/sys/apps/system/kiosk.lua +++ b/sys/apps/system/kiosk.lua @@ -14,13 +14,13 @@ local tab = UI.Tab { formLabel = 'Monitor', formKey = 'monitor', }, textScale = UI.Chooser { - formLabel = 'Font Size', formKey = 'textScale', - nochoice = 'Small', - choices = { - { name = 'Small', value = '.5' }, - { name = 'Large', value = '1' }, - }, - help = 'Adjust text scaling', + formLabel = 'Font Size', formKey = 'textScale', + nochoice = 'Small', + choices = { + { name = 'Small', value = '.5' }, + { name = 'Large', value = '1' }, + }, + help = 'Adjust text scaling', }, labelText = UI.TextArea { x = 2, ex = -2, y = 5, diff --git a/sys/apps/system/launcher.lua b/sys/apps/system/launcher.lua index 5108ad0..cebd5b7 100644 --- a/sys/apps/system/launcher.lua +++ b/sys/apps/system/launcher.lua @@ -9,76 +9,76 @@ local config = Config.load('multishell') local tab = UI.Tab { tabTitle = 'Launcher', description = 'Set the application launcher', - launcherLabel = UI.Text { - x = 3, y = 2, - value = 'Launcher', - }, - launcher = UI.Chooser { - x = 13, y = 2, width = 12, - choices = { - { name = 'Overview', value = 'sys/apps/Overview.lua' }, - { name = 'Shell', value = 'sys/apps/ShellLauncher.lua' }, - { name = 'Custom', value = 'custom' }, - }, - }, - custom = UI.TextEntry { - x = 13, ex = -3, y = 3, - limit = 128, - shadowText = 'File name', - }, - button = UI.Button { - x = 3, y = 5, - text = 'Update', - event = 'update', - }, - labelText = UI.TextArea { - x = 3, ex = -3, y = 7, - textColor = colors.yellow, - value = 'Choose an application launcher', - }, + launcherLabel = UI.Text { + x = 3, y = 2, + value = 'Launcher', + }, + launcher = UI.Chooser { + x = 13, y = 2, width = 12, + choices = { + { name = 'Overview', value = 'sys/apps/Overview.lua' }, + { name = 'Shell', value = 'sys/apps/ShellLauncher.lua' }, + { name = 'Custom', value = 'custom' }, + }, + }, + custom = UI.TextEntry { + x = 13, ex = -3, y = 3, + limit = 128, + shadowText = 'File name', + }, + button = UI.Button { + x = 3, y = 5, + text = 'Update', + event = 'update', + }, + labelText = UI.TextArea { + x = 3, ex = -3, y = 7, + textColor = colors.yellow, + value = 'Choose an application launcher', + }, } function tab:enable() - local launcher = config.launcher and 'custom' or 'sys/apps/Overview.lua' + local launcher = config.launcher and 'custom' or 'sys/apps/Overview.lua' - for _, v in pairs(self.launcher.choices) do - if v.value == config.launcher then - launcher = v.value - break - end - end + for _, v in pairs(self.launcher.choices) do + if v.value == config.launcher then + launcher = v.value + break + end + end UI.Tab.enable(self) - self.launcher.value = launcher - self.custom.enabled = launcher == 'custom' + self.launcher.value = launcher + self.custom.enabled = launcher == 'custom' end function tab:eventHandler(event) if event.type == 'choice_change' then - self.custom.enabled = event.value == 'custom' - if self.custom.enabled then - self.custom.value = config.launcher - end - self:draw() + self.custom.enabled = event.value == 'custom' + if self.custom.enabled then + self.custom.value = config.launcher + end + self:draw() - elseif event.type == 'update' then - local launcher + elseif event.type == 'update' then + local launcher - if self.launcher.value ~= 'custom' then - launcher = self.launcher.value - elseif fs.exists(self.custom.value) and not fs.isDir(self.custom.value) then - launcher = self.custom.value - end + if self.launcher.value ~= 'custom' then + launcher = self.launcher.value + elseif fs.exists(self.custom.value) and not fs.isDir(self.custom.value) then + launcher = self.custom.value + end - if launcher then - config.launcher = launcher - Config.update('multishell', config) - self:emit({ type = 'success_message', message = 'Updated' }) - else - self:emit({ type = 'error_message', message = 'Invalid file' }) - end - end + if launcher then + config.launcher = launcher + Config.update('multishell', config) + self:emit({ type = 'success_message', message = 'Updated' }) + else + self:emit({ type = 'error_message', message = 'Invalid file' }) + end + end end return tab diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index 504c7e1..803ed51 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -13,91 +13,91 @@ local tab = UI.Tab { accelerators = { enter = 'update_path', }, - help = 'add a new path', + help = 'add a new path', }, grid = UI.Grid { y = 4, ey = -3, disableHeader = true, columns = { { key = 'value' } }, autospace = true, - sortColumn = 'index', - help = 'double-click to remove, shift-arrow to move', - accelerators = { - delete = 'remove', - }, + sortColumn = 'index', + help = 'double-click to remove, shift-arrow to move', + accelerators = { + delete = 'remove', + }, + }, + statusBar = UI.StatusBar { }, + accelerators = { + [ 'shift-up' ] = 'move_up', + [ 'shift-down' ] = 'move_down', }, - statusBar = UI.StatusBar { }, - accelerators = { - [ 'shift-up' ] = 'move_up', - [ 'shift-down' ] = 'move_down', - }, } function tab:updateList(path) self.grid.values = { } for k,v in ipairs(Util.split(path, '(.-):')) do table.insert(self.grid.values, { index = k, value = v }) - end - self.grid:update() + end + self.grid:update() end function tab:enable() - local env = Config.load('shell') - self:updateList(env.path) + local env = Config.load('shell') + self:updateList(env.path) UI.Tab.enable(self) end function tab:save() - local t = { } - for _, v in ipairs(self.grid.values) do - table.insert(t, v.value) - end - local env = Config.load('shell') - env.path = table.concat(t, ':') - self:updateList(env.path) - Config.update('shell', env) + local t = { } + for _, v in ipairs(self.grid.values) do + table.insert(t, v.value) + end + local env = Config.load('shell') + env.path = table.concat(t, ':') + self:updateList(env.path) + Config.update('shell', env) end function tab:eventHandler(event) - if event.type == 'update_path' then - table.insert(self.grid.values, { - value = self.entry.value, - }) + if event.type == 'update_path' then + table.insert(self.grid.values, { + value = self.entry.value, + }) self:save() self.entry:reset() - self.entry:draw() - self.grid:draw() + self.entry:draw() + self.grid:draw() return true - elseif event.type == 'grid_select' or event.type == 'remove' then - local selected = self.grid:getSelected() - if selected then - table.remove(self.grid.values, selected.index) - self:save() - self.grid:draw() - end + elseif event.type == 'grid_select' or event.type == 'remove' then + local selected = self.grid:getSelected() + if selected then + table.remove(self.grid.values, selected.index) + self:save() + self.grid:draw() + end - elseif event.type == 'focus_change' then + elseif event.type == 'focus_change' then self.statusBar:setStatus(event.focused.help) - elseif event.type == 'move_up' then - local entry = self.grid:getSelected() - if entry.index > 1 then - table.insert(self.grid.values, entry.index - 1, table.remove(self.grid.values, entry.index)) - self.grid:setIndex(entry.index - 1) - self:save() - self.grid:draw() - end + elseif event.type == 'move_up' then + local entry = self.grid:getSelected() + if entry.index > 1 then + table.insert(self.grid.values, entry.index - 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index - 1) + self:save() + self.grid:draw() + end - elseif event.type == 'move_down' then - local entry = self.grid:getSelected() - if entry.index < #self.grid.values then - table.insert(self.grid.values, entry.index + 1, table.remove(self.grid.values, entry.index)) - self.grid:setIndex(entry.index + 1) - self:save() - self.grid:draw() - end - end + elseif event.type == 'move_down' then + local entry = self.grid:getSelected() + if entry.index < #self.grid.values then + table.insert(self.grid.values, entry.index + 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index + 1) + self:save() + self.grid:draw() + end + end end return tab diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua index 2bd97cf..b98d93b 100644 --- a/sys/apps/system/requires.lua +++ b/sys/apps/system/requires.lua @@ -13,91 +13,91 @@ local tab = UI.Tab { accelerators = { enter = 'update_path', }, - help = 'add a new path (reboot required)', + help = 'add a new path (reboot required)', }, grid = UI.Grid { y = 4, ey = -3, disableHeader = true, columns = { { key = 'value' } }, - autospace = true, - sortColumn = 'index', - help = 'double-click to remove, shift-arrow to move', - accelerators = { - delete = 'remove', - }, - }, - statusBar = UI.StatusBar { }, - accelerators = { - [ 'shift-up' ] = 'move_up', - [ 'shift-down' ] = 'move_down', - }, + autospace = true, + sortColumn = 'index', + help = 'double-click to remove, shift-arrow to move', + accelerators = { + delete = 'remove', + }, + }, + statusBar = UI.StatusBar { }, + accelerators = { + [ 'shift-up' ] = 'move_up', + [ 'shift-down' ] = 'move_down', + }, } function tab:updateList(lua_path) self.grid.values = { } for k,v in ipairs(Util.split(lua_path, '(.-);')) do table.insert(self.grid.values, { index = k, value = v }) - end - self.grid:update() + end + self.grid:update() end function tab:enable() - local env = Config.load('shell') - self:updateList(env.lua_path) + local env = Config.load('shell') + self:updateList(env.lua_path) UI.Tab.enable(self) end function tab:save() - local t = { } - for _, v in ipairs(self.grid.values) do - table.insert(t, v.value) - end - local env = Config.load('shell') - env.lua_path = table.concat(t, ';') - self:updateList(env.lua_path) - Config.update('shell', env) + local t = { } + for _, v in ipairs(self.grid.values) do + table.insert(t, v.value) + end + local env = Config.load('shell') + env.lua_path = table.concat(t, ';') + self:updateList(env.lua_path) + Config.update('shell', env) end function tab:eventHandler(event) - if event.type == 'update_path' then - table.insert(self.grid.values, { - value = self.entry.value, - }) - self:save() + if event.type == 'update_path' then + table.insert(self.grid.values, { + value = self.entry.value, + }) + self:save() self.entry:reset() - self.entry:draw() - self.grid:draw() + self.entry:draw() + self.grid:draw() return true - elseif event.type == 'grid_select' or event.type == 'remove' then - local selected = self.grid:getSelected() - if selected then - table.remove(self.grid.values, selected.index) - self:save() - self.grid:draw() - end + elseif event.type == 'grid_select' or event.type == 'remove' then + local selected = self.grid:getSelected() + if selected then + table.remove(self.grid.values, selected.index) + self:save() + self.grid:draw() + end - elseif event.type == 'focus_change' then + elseif event.type == 'focus_change' then self.statusBar:setStatus(event.focused.help) - elseif event.type == 'move_up' then - local entry = self.grid:getSelected() - if entry.index > 1 then - table.insert(self.grid.values, entry.index - 1, table.remove(self.grid.values, entry.index)) - self.grid:setIndex(entry.index - 1) - self:save() - self.grid:draw() - end + elseif event.type == 'move_up' then + local entry = self.grid:getSelected() + if entry.index > 1 then + table.insert(self.grid.values, entry.index - 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index - 1) + self:save() + self.grid:draw() + end - elseif event.type == 'move_down' then - local entry = self.grid:getSelected() - if entry.index < #self.grid.values then - table.insert(self.grid.values, entry.index + 1, table.remove(self.grid.values, entry.index)) - self.grid:setIndex(entry.index + 1) - self:save() - self.grid:draw() - end - end + elseif event.type == 'move_down' then + local entry = self.grid:getSelected() + if entry.index < #self.grid.values then + table.insert(self.grid.values, entry.index + 1, table.remove(self.grid.values, entry.index)) + self.grid:setIndex(entry.index + 1) + self:save() + self.grid:draw() + end + end end return tab diff --git a/sys/apps/system/shell.lua b/sys/apps/system/shell.lua index ee413f5..238a8d9 100644 --- a/sys/apps/system/shell.lua +++ b/sys/apps/system/shell.lua @@ -9,134 +9,134 @@ local config = Config.load('shellprompt') local allColors = { } for k,v in pairs(colors) do - if type(v) == 'number' then - table.insert(allColors, { name = k, value = v }) - end + if type(v) == 'number' then + table.insert(allColors, { name = k, value = v }) + end end local defaults = { - textColor = colors.white, - commandTextColor = colors.yellow, - directoryTextColor = colors.orange, - directoryBackgroundColor = colors.black, - promptTextColor = colors.blue, - promptBackgroundColor = colors.black, - directoryColor = colors.green, - fileColor = colors.white, - backgroundColor = colors.black, + textColor = colors.white, + commandTextColor = colors.yellow, + directoryTextColor = colors.orange, + directoryBackgroundColor = colors.black, + promptTextColor = colors.blue, + promptBackgroundColor = colors.black, + directoryColor = colors.green, + fileColor = colors.white, + backgroundColor = colors.black, } local _colors = config.color or Util.shallowCopy(defaults) local allSettings = { } for k, v in pairs(defaults) do - table.insert(allSettings, { name = k }) + table.insert(allSettings, { name = k }) end -- temp if not _colors.backgroundColor then - _colors.backgroundColor = colors.black - _colors.fileColor = colors.white + _colors.backgroundColor = colors.black + _colors.fileColor = colors.white end local tab = UI.Tab { tabTitle = 'Shell', - description = 'Shell options', - grid1 = UI.ScrollingGrid { - y = 2, ey = -10, x = 3, ex = -16, - disableHeader = true, - columns = { { key = 'name' } }, - values = allSettings, - sortColumn = 'name', - }, - grid2 = UI.ScrollingGrid { - y = 2, ey = -10, x = -14, ex = -3, + description = 'Shell options', + grid1 = UI.ScrollingGrid { + y = 2, ey = -10, x = 3, ex = -16, disableHeader = true, columns = { { key = 'name' } }, - values = allColors, - sortColumn = 'name', + values = allSettings, + sortColumn = 'name', + }, + grid2 = UI.ScrollingGrid { + y = 2, ey = -10, x = -14, ex = -3, + disableHeader = true, + columns = { { key = 'name' } }, + values = allColors, + sortColumn = 'name', + }, + directoryLabel = UI.Text { + x = 2, y = -2, + value = 'Display directory', + }, + directory = UI.Checkbox { + x = 20, y = -2, + value = config.displayDirectory + }, + reset = UI.Button { + x = -18, y = -2, + text = 'Reset', + event = 'reset', + }, + button = UI.Button { + x = -9, y = -2, + text = 'Update', + event = 'update', + }, + display = UI.Window { + x = 3, ex = -3, y = -8, height = 5, }, - directoryLabel = UI.Text { - x = 2, y = -2, - value = 'Display directory', - }, - directory = UI.Checkbox { - x = 20, y = -2, - value = config.displayDirectory - }, - reset = UI.Button { - x = -18, y = -2, - text = 'Reset', - event = 'reset', - }, - button = UI.Button { - x = -9, y = -2, - text = 'Update', - event = 'update', - }, - display = UI.Window { - x = 3, ex = -3, y = -8, height = 5, - }, } function tab.grid2:getRowTextColor(row) - local selected = tab.grid1:getSelected() - if _colors[selected.name] == row.value then - return colors.yellow - end - return UI.Grid.getRowTextColor(self, row) + local selected = tab.grid1:getSelected() + if _colors[selected.name] == row.value then + return colors.yellow + end + return UI.Grid.getRowTextColor(self, row) end function tab.display:draw() - self:clear(_colors.backgroundColor) - local offset = 0 - if config.displayDirectory then - self:write(1, 1, - '==' .. os.getComputerLabel() .. ':/dir/etc', - _colors.directoryBackgroundColor, _colors.directoryTextColor) - offset = 1 - end + self:clear(_colors.backgroundColor) + local offset = 0 + if config.displayDirectory then + self:write(1, 1, + '==' .. os.getComputerLabel() .. ':/dir/etc', + _colors.directoryBackgroundColor, _colors.directoryTextColor) + offset = 1 + end - self:write(1, 1 + offset, '$ ', - _colors.promptBackgroundColor, _colors.promptTextColor) + self:write(1, 1 + offset, '$ ', + _colors.promptBackgroundColor, _colors.promptTextColor) - self:write(3, 1 + offset, 'ls /', - _colors.backgroundColor, _colors.commandTextColor) + self:write(3, 1 + offset, 'ls /', + _colors.backgroundColor, _colors.commandTextColor) - self:write(1, 2 + offset, 'sys usr', - _colors.backgroundColor, _colors.directoryColor) + self:write(1, 2 + offset, 'sys usr', + _colors.backgroundColor, _colors.directoryColor) - self:write(1, 3 + offset, 'startup', - _colors.backgroundColor, _colors.fileColor) + self:write(1, 3 + offset, 'startup', + _colors.backgroundColor, _colors.fileColor) end function tab:eventHandler(event) - if event.type =='checkbox_change' then - config.displayDirectory = not not event.checked - self.display:draw() + if event.type =='checkbox_change' then + config.displayDirectory = not not event.checked + self.display:draw() - elseif event.type == 'grid_focus_row' and event.element == self.grid1 then - self.grid2:draw() + elseif event.type == 'grid_focus_row' and event.element == self.grid1 then + self.grid2:draw() - elseif event.type == 'grid_select' and event.element == self.grid2 then - _colors[tab.grid1:getSelected().name] = event.selected.value - self.display:draw() - self.grid2:draw() + elseif event.type == 'grid_select' and event.element == self.grid2 then + _colors[tab.grid1:getSelected().name] = event.selected.value + self.display:draw() + self.grid2:draw() - elseif event.type == 'reset' then - config.color = defaults - config.displayDirectory = true - self.directory.value = true - _colors = Util.shallowCopy(defaults) + elseif event.type == 'reset' then + config.color = defaults + config.displayDirectory = true + self.directory.value = true + _colors = Util.shallowCopy(defaults) - Config.update('shellprompt', config) - self:draw() + Config.update('shellprompt', config) + self:draw() - elseif event.type == 'update' then - config.color = _colors - Config.update('shellprompt', config) + elseif event.type == 'update' then + config.color = _colors + Config.update('shellprompt', config) - end - return UI.Tab.eventHandler(self, event) + end + return UI.Tab.eventHandler(self, event) end return tab diff --git a/sys/autorun/complete.lua b/sys/autorun/complete.lua index 332c8a3..82b2fe5 100644 --- a/sys/autorun/complete.lua +++ b/sys/autorun/complete.lua @@ -1,22 +1,22 @@ local function completeMultipleChoice(sText, tOptions, bAddSpaces) - local tResults = { } - for n = 1,#tOptions do - local sOption = tOptions[n] - if #sOption + (bAddSpaces and 1 or 0) > #sText and string.sub(sOption, 1, #sText) == sText then - local sResult = string.sub(sOption, #sText + 1) - if bAddSpaces then - table.insert(tResults, sResult .. " ") - else - table.insert(tResults, sResult) - end - end - end - return tResults + local tResults = { } + for n = 1,#tOptions do + local sOption = tOptions[n] + if #sOption + (bAddSpaces and 1 or 0) > #sText and string.sub(sOption, 1, #sText) == sText then + local sResult = string.sub(sOption, #sText + 1) + if bAddSpaces then + table.insert(tResults, sResult .. " ") + else + table.insert(tResults, sResult) + end + end + end + return tResults end _ENV.shell.setCompletionFunction("sys/apps/package.lua", - function(_, index, text) - if index == 1 then - return completeMultipleChoice(text, { "install ", "update ", "uninstall " }) - end - end) + function(_, index, text) + if index == 1 then + return completeMultipleChoice(text, { "install ", "update ", "uninstall " }) + end + end) diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua index df0b2fd..2ecf6d8 100644 --- a/sys/autorun/welcome.lua +++ b/sys/autorun/welcome.lua @@ -4,8 +4,8 @@ local shell = _ENV.shell local config = Config.load('os') if not config.welcomed and shell.openForegroundTab then - config.welcomed = true - Config.update('os', config) + config.welcomed = true + Config.update('os', config) - shell.openForegroundTab('Welcome') + shell.openForegroundTab('Welcome') end diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index 6eb8c57..91a7159 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -6,47 +6,47 @@ local os = _G.os local peripheral = _G.peripheral local containers = { - manipulator = true, - neuralInterface = true, + manipulator = true, + neuralInterface = true, } local function getModules(dev, side) - local list = { } + local list = { } - if dev then - for _, module in pairs(dev.listModules()) do - list[module] = Util.shallowCopy(dev) - list[module].name = module - list[module].type = module - list[module].side = side - end - end - return list + if dev then + for _, module in pairs(dev.listModules()) do + list[module] = Util.shallowCopy(dev) + list[module].name = module + list[module].type = module + list[module].side = side + end + end + return list end for _,v in pairs(device) do - if containers[v.type] then - local list = getModules(v, v.side) - for k, dev in pairs(list) do - -- neural and attached modules have precedence over manipulator modules - if not device[k] or v.type ~= 'manipulator' then - device[k] = dev - end - end - end + if containers[v.type] then + local list = getModules(v, v.side) + for k, dev in pairs(list) do + -- neural and attached modules have precedence over manipulator modules + if not device[k] or v.type ~= 'manipulator' then + device[k] = dev + end + end + end end -- register modules as peripherals kernel.hook('device_attach', function(_, eventData) - local dev = eventData[2] + local dev = eventData[2] - if dev and containers[dev.type] then - local list = getModules(peripheral.wrap(dev.side), dev.side) - for k,v in pairs(list) do - if not device[k] or dev.type ~= 'manipulator' then - device[k] = v - os.queueEvent('device_attach', k, v) - end - end - end + if dev and containers[dev.type] then + local list = getModules(peripheral.wrap(dev.side), dev.side) + for k,v in pairs(list) do + if not device[k] or dev.type ~= 'manipulator' then + device[k] = v + os.queueEvent('device_attach', k, v) + end + end + end end) diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua index ca75dc2..5ddc4bc 100644 --- a/sys/init/3.relay.lua +++ b/sys/init/3.relay.lua @@ -2,26 +2,26 @@ local device = _G.device local kernel = _G.kernel local function register(v) - if v and v.isWireless and v.isAccessPoint and v.getNamesRemote then - v._children = { } - for _, name in pairs(v.getNamesRemote()) do - local dev = v.getMethodsRemote(name) - if dev then - dev.name = name - dev.side = name - dev.type = v.getTypeRemote(name) - device[name] = dev - table.insert(v._children, dev) - end - end - end + if v and v.isWireless and v.isAccessPoint and v.getNamesRemote then + v._children = { } + for _, name in pairs(v.getNamesRemote()) do + local dev = v.getMethodsRemote(name) + if dev then + dev.name = name + dev.side = name + dev.type = v.getTypeRemote(name) + device[name] = dev + table.insert(v._children, dev) + end + end + end end for _,v in pairs(device) do - register(v) + register(v) end -- register oc devices as peripherals kernel.hook('device_attach', function(_, eventData) - register(device[eventData[2]]) + register(device[eventData[2]]) end) diff --git a/sys/init/6.packages.lua b/sys/init/6.packages.lua index 9baf271..ba52af1 100644 --- a/sys/init/6.packages.lua +++ b/sys/init/6.packages.lua @@ -6,7 +6,9 @@ local help = _G.help local shell = _ENV.shell if not fs.exists('usr/config/packages') then - Packages:downloadList() + pcall(function() + Packages:downloadList() + end) end local appPaths = Util.split(shell.path(), '(.-):') diff --git a/sys/init/6.tl3.lua b/sys/init/6.tl3.lua index 53519c4..4e797e2 100644 --- a/sys/init/6.tl3.lua +++ b/sys/init/6.tl3.lua @@ -52,6 +52,7 @@ function turtle.resetState() state.movePolicy = _defaultMove state.moveCallback = noop state.blacklist = nil + state.reference = nil -- gps reference when converting to relative coords Pathing.reset() return true end @@ -77,8 +78,6 @@ local function _dig(name, inspect, dig) return dig() end --- override dig --- optionally check that the block is a certain type function turtle.dig(s) return _dig(s, turtle.inspect, turtle.native.dig) end @@ -359,7 +358,7 @@ function turtle.set(args) turtle.setDigPolicy(turtle.getPolicy(v)) elseif k == 'movePolicy' then - turtle.setMovePolicy(turtle.getPolicy(v)) + state.movePolicy = turtle.getPolicy(v) elseif k == 'movementStrategy' then turtle.setMovementStrategy(v) @@ -379,6 +378,9 @@ function turtle.set(args) elseif k == 'blacklist' then state.blacklist = v + elseif k == 'reference' then + state.reference = v + else error('Invalid turle.set: ' .. tostring(k)) end @@ -426,6 +428,10 @@ function turtle.setHeading(heading) return false, 'Invalid heading' end + if heading == turtle.point.heading then + return turtle.point + end + local fi = Point.facings[heading] if not fi then return false, 'Invalid heading' From 97a442e99974356e313fd9c9d0bcb5723737f69c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 27 Jun 2019 16:29:12 -0400 Subject: [PATCH 153/231] socket update --- sys/apis/socket.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/apis/socket.lua b/sys/apis/socket.lua index fd73abd..726b4d3 100644 --- a/sys/apis/socket.lua +++ b/sys/apis/socket.lua @@ -115,7 +115,7 @@ function Socket.connect(host, port) type = 'OPEN', shost = socket.shost, dhost = socket.dhost, - t = Crypto.encrypt({ ts = os.time(), seq = socket.seq }, Security.getPublicKey()), + t = Crypto.encrypt({ ts = os.time(), seq = socket.seq, nts = os.epoch('utc') }, Security.getPublicKey()), rseq = socket.wseq, wseq = socket.rseq, }) @@ -170,6 +170,10 @@ local function trusted(msg, port) if pubKey then local data = Crypto.decrypt(msg.t or '', pubKey) + if data.nts then -- upgraded security + return data.nts and tonumber(data.nts) and math.abs(os.epoch('utc') - data.nts) < 1024 + end + --local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod) return data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 24 end From bcd33af599c1fda61043276b1f959f2fe5edd03b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 27 Jun 2019 21:08:46 -0400 Subject: [PATCH 154/231] The big Anavrins security update (round 1) --- sys/apis/crypto.lua | 150 ----- sys/apis/crypto/chacha20.lua | 167 ++++++ sys/apis/crypto/ecc/elliptic.lua | 300 ++++++++++ sys/apis/crypto/ecc/fp.lua | 928 +++++++++++++++++++++++++++++++ sys/apis/crypto/ecc/fq.lua | 741 ++++++++++++++++++++++++ sys/apis/crypto/ecc/init.lua | 87 +++ sys/apis/{ => crypto}/sha2.lua | 21 +- sys/apis/injector.lua | 2 +- sys/apis/security.lua | 29 +- sys/apis/socket.lua | 11 +- sys/apis/util.lua | 13 + sys/apps/Welcome.lua | 5 +- sys/apps/network/trust.lua | 6 +- sys/apps/password.lua | 4 +- sys/apps/system/password.lua | 6 +- sys/apps/trust.lua | 6 +- sys/autorun/welcome.lua | 36 +- 17 files changed, 2308 insertions(+), 204 deletions(-) delete mode 100644 sys/apis/crypto.lua create mode 100644 sys/apis/crypto/chacha20.lua create mode 100644 sys/apis/crypto/ecc/elliptic.lua create mode 100644 sys/apis/crypto/ecc/fp.lua create mode 100644 sys/apis/crypto/ecc/fq.lua create mode 100644 sys/apis/crypto/ecc/init.lua rename sys/apis/{ => crypto}/sha2.lua (92%) diff --git a/sys/apis/crypto.lua b/sys/apis/crypto.lua deleted file mode 100644 index fc1075b..0000000 --- a/sys/apis/crypto.lua +++ /dev/null @@ -1,150 +0,0 @@ --- https://github.com/PixelToast/ComputerCraft/blob/master/apis/enc - -local Crypto = { } - -local function serialize(t) - local sType = type(t) - if sType == "table" then - local lstcnt=0 - for k,v in pairs(t) do - lstcnt = lstcnt + 1 - end - local result = "{" - local aset=1 - for k,v in pairs(t) do - if k==aset then - result = result..serialize(v).."," - aset=aset+1 - else - result = result..("["..serialize(k).."]="..serialize(v)..",") - end - end - result = result.."}" - return result - elseif sType == "string" then - return string.format("%q",t) - elseif sType == "number" or sType == "boolean" or sType == "nil" then - return tostring(t) - elseif sType == "function" then - local status,data=pcall(string.dump,t) - if status then - data2="" - for char in string.gmatch(data,".") do - data2=data2..zfill(string.byte(char)) - end - return 'f("'..data2..'")' - else - error("Invalid function: "..data) - end - else - error("Could not serialize type "..sType..".") - end -end - -local function unserialize( s ) - local func, e = loadstring( "return "..s, "serialize" ) - if not func then - return s,e - else - setfenv( func, { - f=function(S) - return loadstring(splitnum(S)) - end, - }) - return func() - end -end - -local function splitnum(S) - local Out="" - for l1=1,#S,2 do - local l2=(#S-l1)+1 - local function sure(N,n) - if (l2-n)<1 then N="0" end - return N - end - local CNum=tonumber("0x"..sure(string.sub(S,l2-1,l2-1),1) .. sure(string.sub(S,l2,l2),0)) - Out=string.char(CNum)..Out - end - return Out -end - -local function zfill(N) - N=string.format("%X",N) - Zs="" - if #N==1 then - Zs="0" - end - return Zs..N -end - -local function wrap(N) - return N-(math.floor(N/256)*256) -end - -local function checksum(S) - local sum=0 - for char in string.gmatch(S,".") do - math.randomseed(string.byte(char)+sum) - sum=sum+math.random(0,9999) - end - math.randomseed(sum) - return sum -end - -local function genkey(len,psw) - checksum(psw) - local key={} - local tKeys={} - for l1=1,len do - local num=math.random(1,len) - while tKeys[num] do - num=math.random(1,len) - end - tKeys[num]=true - key[l1]={num,math.random(0,255)} - end - return key -end - -function Crypto.encrypt(data,psw) - data=serialize(data) - local chs=checksum(data) - local key=genkey(#data,psw) - local out={} - local cnt=1 - for char in string.gmatch(data,".") do - table.insert(out,key[cnt][1],zfill(wrap(string.byte(char)+key[cnt][2])),chars) - cnt=cnt+1 - end - return string.sub(serialize({chs,table.concat(out)}),2,-3) -end - -function Crypto.decrypt(data,psw) - local oData=data - data=unserialize("{"..data.."}") - if type(data)~="table" then - return oData - end - local chs=data[1] - data=data[2] - local key=genkey((#data)/2,psw) - local sKey={} - for k,v in pairs(key) do - sKey[v[1]]={k,v[2]} - end - local str=splitnum(data) - local cnt=1 - local out={} - for char in string.gmatch(str,".") do - table.insert(out,sKey[cnt][1],string.char(wrap(string.byte(char)-sKey[cnt][2]))) - cnt=cnt+1 - end - out=table.concat(out) - if checksum(out or "")==chs then - return unserialize(out) - end - return oData,out,chs -end - -return Crypto diff --git a/sys/apis/crypto/chacha20.lua b/sys/apis/crypto/chacha20.lua new file mode 100644 index 0000000..b0763dd --- /dev/null +++ b/sys/apis/crypto/chacha20.lua @@ -0,0 +1,167 @@ +-- Chacha20 cipher in ComputerCraft +-- By Anavrins + +local sha2 = require('crypto.sha2') +local util = require('util') + +local ROUNDS = 20 -- Adjust this for speed tradeoff + +local bxor = bit32.bxor +local band = bit32.band +local blshift = bit32.lshift +local brshift = bit32.arshift +local textutils = _G.textutils + +local mod = 2^32 +local tau = {("expand 16-byte k"):byte(1,-1)} +local sigma = {("expand 32-byte k"):byte(1,-1)} + +local function rotl(n, b) + local s = n/(2^(32-b)) + local f = s%1 + return (s-f) + f*mod +end + +local function quarterRound(s, a, b, c, d) + s[a] = (s[a]+s[b])%mod; s[d] = rotl(bxor(s[d], s[a]), 16) + s[c] = (s[c]+s[d])%mod; s[b] = rotl(bxor(s[b], s[c]), 12) + s[a] = (s[a]+s[b])%mod; s[d] = rotl(bxor(s[d], s[a]), 8) + s[c] = (s[c]+s[d])%mod; s[b] = rotl(bxor(s[b], s[c]), 7) + return s +end + +local function hashBlock(state, rnd) + local s = {unpack(state)} + for i = 1, rnd do + local r = i%2==1 + s = r and quarterRound(s, 1, 5, 9, 13) or quarterRound(s, 1, 6, 11, 16) + s = r and quarterRound(s, 2, 6, 10, 14) or quarterRound(s, 2, 7, 12, 13) + s = r and quarterRound(s, 3, 7, 11, 15) or quarterRound(s, 3, 8, 9, 14) + s = r and quarterRound(s, 4, 8, 12, 16) or quarterRound(s, 4, 5, 10, 15) + end + for i = 1, 16 do s[i] = (s[i]+state[i])%mod end + return s +end + +local function LE_toInt(bs, i) + return (bs[i+1] or 0)+ + blshift((bs[i+2] or 0), 8)+ + blshift((bs[i+3] or 0), 16)+ + blshift((bs[i+4] or 0), 24) +end + +local function initState(key, nonce, counter) + local isKey256 = #key == 32 + local const = isKey256 and sigma or tau + local state = {} + + state[ 1] = LE_toInt(const, 0) + state[ 2] = LE_toInt(const, 4) + state[ 3] = LE_toInt(const, 8) + state[ 4] = LE_toInt(const, 12) + + state[ 5] = LE_toInt(key, 0) + state[ 6] = LE_toInt(key, 4) + state[ 7] = LE_toInt(key, 8) + state[ 8] = LE_toInt(key, 12) + state[ 9] = LE_toInt(key, isKey256 and 16 or 0) + state[10] = LE_toInt(key, isKey256 and 20 or 4) + state[11] = LE_toInt(key, isKey256 and 24 or 8) + state[12] = LE_toInt(key, isKey256 and 28 or 12) + + state[13] = counter + state[14] = LE_toInt(nonce, 0) + state[15] = LE_toInt(nonce, 4) + state[16] = LE_toInt(nonce, 8) + + return state +end + +local function serialize(state) + local r = {} + for i = 1, 16 do + r[#r+1] = band(state[i], 0xFF) + r[#r+1] = band(brshift(state[i], 8), 0xFF) + r[#r+1] = band(brshift(state[i], 16), 0xFF) + r[#r+1] = band(brshift(state[i], 24), 0xFF) + end + return r +end + +local mt = { + __tostring = function(a) return string.char(unpack(a)) end, + __index = { + toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end, + isEqual = function(self, t) + if type(t) ~= "table" then return false end + if #self ~= #t then return false end + local ret = 0 + for i = 1, #self do + ret = bit32.bor(ret, bxor(self[i], t[i])) + end + return ret == 0 + end + } +} + +local function crypt(data, key, nonce, cntr, round) + assert(type(key) == "table", "ChaCha20: Invalid key format ("..type(key).."), must be table") + assert(type(nonce) == "table", "ChaCha20: Invalid nonce format ("..type(nonce).."), must be table") + assert(#key == 16 or #key == 32, "ChaCha20: Invalid key length ("..#key.."), must be 16 or 32") + assert(#nonce == 12, "ChaCha20: Invalid nonce length ("..#nonce.."), must be 12") + + local data = type(data) == "table" and {unpack(data)} or {tostring(data):byte(1,-1)} + cntr = tonumber(cntr) or 1 + round = tonumber(round) or 20 + + local out = {} + local state = initState(key, nonce, cntr) + local blockAmt = math.floor(#data/64) + for i = 0, blockAmt do + local ks = serialize(hashBlock(state, round)) + state[13] = (state[13]+1) % mod + + local block = {} + for j = 1, 64 do + block[j] = data[((i)*64)+j] + end + for j = 1, #block do + out[#out+1] = bxor(block[j], ks[j]) + end + + if i % 1000 == 0 then + os.queueEvent("") + os.pullEvent("") + end + end + return setmetatable(out, mt) +end + +local function genNonce(len) + local nonce = {} + for i = 1, len do + nonce[i] = math.random(0, 0xFF) + end + return setmetatable(nonce, mt) +end + +local function encrypt(data, key) + local nonce = genNonce(12) + data = textutils.serialise(data) + key = sha2.digest(key) + local ctx = crypt(data, key, nonce, 1, ROUNDS) + return { nonce:toHex(), ctx:toHex() } +end + +local function decrypt(data, key) + local nonce = util.hexToByteArray(data[1]) + data = util.hexToByteArray(data[2]) + key = sha2.digest(key) + local ptx = crypt(data, key, nonce, 1, ROUNDS) + return textutils.unserialise(tostring(ptx)) +end + +return { + encrypt = encrypt, + decrypt = decrypt, +} diff --git a/sys/apis/crypto/ecc/elliptic.lua b/sys/apis/crypto/ecc/elliptic.lua new file mode 100644 index 0000000..ca2b5b5 --- /dev/null +++ b/sys/apis/crypto/ecc/elliptic.lua @@ -0,0 +1,300 @@ +---- Elliptic Curve Arithmetic + +---- About the Curve Itself +-- Field Size: 192 bits +-- Field Modulus (p): 65533 * 2^176 + 3 +-- Equation: x^2 + y^2 = 1 + 108 * x^2 * y^2 +-- Parameters: Edwards Curve with c = 1, and d = 108 +-- Curve Order (n): 4 * 1569203598118192102418711808268118358122924911136798015831 +-- Cofactor (h): 4 +-- Generator Order (q): 1569203598118192102418711808268118358122924911136798015831 +---- About the Curve's Security +-- Current best attack security: 94.822 bits (Pollard's Rho) +-- Rho Security: log2(0.884 * sqrt(q)) = 94.822 +-- Transfer Security? Yes: p ~= q; k > 20 +-- Field Discriminant Security? Yes: t = 67602300638727286331433024168; s = 2^2; |D| = 5134296629560551493299993292204775496868940529592107064435 > 2^100 +-- Rigidity? A little, the parameters are somewhat small. +-- XZ/YZ Ladder Security? No: Single coordinate ladders are insecure, so they can't be used. +-- Small Subgroup Security? Yes: Secret keys are calculated modulo 4q. +-- Invalid Curve Security? Yes: Any point to be multiplied is checked beforehand. +-- Invalid Curve Twist Security? No: The curve is not protected against single coordinate ladder attacks, so don't use them. +-- Completeness? Yes: The curve is an Edwards Curve with non-square d and square a, so the curve is complete. +-- Indistinguishability? No: The curve does not support indistinguishability maps. + +local fp = require('crypto.ecc.fp') +local eq = fp.eq +local mul = fp.mul +local sqr = fp.sqr +local add = fp.add +local sub = fp.sub +local shr = fp.shr +local mont = fp.mont +local invMont = fp.invMont +local sub192 = fp.sub192 + +local bits = 192 +local pMinusTwoBinary = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} +local pMinusThreeOverFourBinary = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0} +local ZERO = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +local ONE = mont({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + +local p = mont({3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65533}) +local G = { + mont({30457, 58187, 5603, 63215, 8936, 58151, 26571, 7272, 26680, 23486, 32353, 59456}), + mont({3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), + mont({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) +} +local GTable = {G} + +local d = mont({108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + +local function generator() + return G +end + +local function expMod(a, t) + local a = {unpack(a)} + local result = {unpack(ONE)} + + for i = 1, bits do + if t[i] == 1 then + result = mul(result, a) + end + a = mul(a, a) + end + + return result +end + +-- We're using Projective Coordinates +-- For Edwards curves +-- The identity element is represented by (0:1:1) +local function pointDouble(P1) + local X1, Y1, Z1 = unpack(P1) + + local b = add(X1, Y1) + local B = sqr(b) + local C = sqr(X1) + local D = sqr(Y1) + local E = add(C, D) + local H = sqr(Z1) + local J = sub(E, add(H, H)) + local X3 = mul(sub(B, E), J) + local Y3 = mul(E, sub(C, D)) + local Z3 = mul(E, J) + + local P3 = {X3, Y3, Z3} + + return P3 +end + +local function pointAdd(P1, P2) + local X1, Y1, Z1 = unpack(P1) + local X2, Y2, Z2 = unpack(P2) + + local A = mul(Z1, Z2) + local B = sqr(A) + local C = mul(X1, X2) + local D = mul(Y1, Y2) + local E = mul(d, mul(C, D)) + local F = sub(B, E) + local G = add(B, E) + local X3 = mul(A, mul(F, sub(mul(add(X1, Y1), add(X2, Y2)), add(C, D)))) + local Y3 = mul(A, mul(G, sub(D, C))) + local Z3 = mul(F, G) + + local P3 = {X3, Y3, Z3} + + return P3 +end + +local function pointNeg(P1) + local X1, Y1, Z1 = unpack(P1) + + local X3 = sub(p, X1) + local Y3 = {unpack(Y1)} + local Z3 = {unpack(Z1)} + + local P3 = {X3, Y3, Z3} + + return P3 +end + +local function pointSub(P1, P2) + return pointAdd(P1, pointNeg(P2)) +end + +local function pointScale(P1) + local X1, Y1, Z1 = unpack(P1) + + local A = expMod(Z1, pMinusTwoBinary) + local X3 = mul(X1, A) + local Y3 = mul(Y1, A) + local Z3 = {unpack(ONE)} + + local P3 = {X3, Y3, Z3} + + return P3 +end + +local function pointEq(P1, P2) + local X1, Y1, Z1 = unpack(P1) + local X2, Y2, Z2 = unpack(P2) + + local A1 = mul(X1, Z2) + local B1 = mul(Y1, Z2) + local A2 = mul(X2, Z1) + local B2 = mul(Y2, Z1) + + return eq(A1, A2) and eq(B1, B2) +end + +local function isOnCurve(P1) + local X1, Y1, Z1 = unpack(P1) + + local X12 = sqr(X1) + local Y12 = sqr(Y1) + local Z12 = sqr(Z1) + local Z14 = sqr(Z12) + local a = add(X12, Y12) + a = mul(a, Z12) + local b = mul(d, mul(X12, Y12)) + b = add(Z14, b) + + return eq(a, b) +end + +local function mods(d) + -- w = 5 + local result = d[1] % 32 + + if result >= 16 then + result = result - 32 + end + + return result +end + +local function NAF(d) + local t = {} + local d = {unpack(d)} + + while d[12] >= 0 and not eq(d, ZERO) do + if d[1] % 2 == 1 then + t[#t + 1] = mods(d) + d = sub192(d, {t[#t], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + else + t[#t + 1] = 0 + end + + d = shr(d) + end + + return t +end + +local function scalarMul(s, P1) + local naf = NAF(s) + local PTable = {P1} + local P2 = pointDouble(P1) + + for i = 3, 31, 2 do + PTable[i] = pointAdd(PTable[i - 2], P2) + end + + local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}} + for i = #naf, 1, -1 do + Q = pointDouble(Q) + if naf[i] > 0 then + Q = pointAdd(Q, PTable[naf[i]]) + elseif naf[i] < 0 then + Q = pointSub(Q, PTable[-naf[i]]) + end + end + + return Q +end + +for i = 2, 196 do + GTable[i] = pointDouble(GTable[i - 1]) +end + +local function scalarMulG(s) + local result = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}} + local k = 1 + + for i = 1, 12 do + local w = s[i] + + for j = 1, 16 do + if w % 2 == 1 then + result = pointAdd(result, GTable[k]) + end + + k = k + 1 + + w = w / 2 + w = w - w % 1 + end + end + + return result +end + +local function pointEncode(P1) + P1 = pointScale(P1) + + local result = {} + local x, y = unpack(P1) + + result[1] = x[1] % 2 + + for i = 1, 12 do + local m = y[i] % 256 + result[2 * i] = m + result[2 * i + 1] = (y[i] - m) / 256 + end + + return result +end + +local function pointDecode(enc) + local y = {} + for i = 1, 12 do + y[i] = enc[2 * i] + y[i] = y[i] + enc[2 * i + 1] * 256 + end + + local y2 = sqr(y) + local u = sub(y2, ONE) + local v = sub(mul(d, y2), ONE) + local u2 = sqr(u) + local u3 = mul(u, u2) + local u5 = mul(u3, u2) + local v3 = mul(v, sqr(v)) + local w = mul(u5, v3) + local x = mul(u3, mul(v, expMod(w, pMinusThreeOverFourBinary))) + + if x[1] % 2 ~= enc[1] then + x = sub(p, x) + end + + local P3 = {x, y, {unpack(ONE)}} + + return P3 +end + +return { + generator = generator, + pointDouble = pointDouble, + pointAdd = pointAdd, + pointNeg = pointNeg, + pointSub = pointSub, + pointScale = pointScale, + pointEq = pointEq, + isOnCurve = isOnCurve, + scalarMul = scalarMul, + scalarMulG = scalarMulG, + pointEncode = pointEncode, + pointDecode = pointDecode, +} diff --git a/sys/apis/crypto/ecc/fp.lua b/sys/apis/crypto/ecc/fp.lua new file mode 100644 index 0000000..3a8c4c6 --- /dev/null +++ b/sys/apis/crypto/ecc/fp.lua @@ -0,0 +1,928 @@ +-- Fp Integer Arithmetic + +local n = 0xffff +local m = 0x10000 + +local p = {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65533} +local p2 = {21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 43690} +local r2 = {44014, 58358, 19452, 6484, 45852, 58974, 63348, 64806, 65292, 65454, 65508, 21512} + +local function eq(a, b) + for i = 1, 12 do + if a[i] ~= b[i] then + return false + end + end + + return true +end + +local function reduce(a) + local r1 = a[1] + local r2 = a[2] + local r3 = a[3] + local r4 = a[4] + local r5 = a[5] + local r6 = a[6] + local r7 = a[7] + local r8 = a[8] + local r9 = a[9] + local r10 = a[10] + local r11 = a[11] + local r12 = a[12] + + if r12 < 65533 or r12 == 65533 and r1 < 3 then + return {unpack(a)} + end + + r1 = r1 - 3 + r12 = r12 - 65533 + + if r1 < 0 then + r2 = r2 - 1 + r1 = r1 + m + end + if r2 < 0 then + r3 = r3 - 1 + r2 = r2 + m + end + if r3 < 0 then + r4 = r4 - 1 + r3 = r3 + m + end + if r4 < 0 then + r5 = r5 - 1 + r4 = r4 + m + end + if r5 < 0 then + r6 = r6 - 1 + r5 = r5 + m + end + if r6 < 0 then + r7 = r7 - 1 + r6 = r6 + m + end + if r7 < 0 then + r8 = r8 - 1 + r7 = r7 + m + end + if r8 < 0 then + r9 = r9 - 1 + r8 = r8 + m + end + if r9 < 0 then + r10 = r10 - 1 + r9 = r9 + m + end + if r10 < 0 then + r11 = r11 - 1 + r10 = r10 + m + end + if r11 < 0 then + r12 = r12 - 1 + r11 = r11 + m + end + + return {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} +end + +local function add(a, b) + local r1 = a[1] + b[1] + local r2 = a[2] + b[2] + local r3 = a[3] + b[3] + local r4 = a[4] + b[4] + local r5 = a[5] + b[5] + local r6 = a[6] + b[6] + local r7 = a[7] + b[7] + local r8 = a[8] + b[8] + local r9 = a[9] + b[9] + local r10 = a[10] + b[10] + local r11 = a[11] + b[11] + local r12 = a[12] + b[12] + + if r1 > n then + r2 = r2 + 1 + r1 = r1 - m + end + if r2 > n then + r3 = r3 + 1 + r2 = r2 - m + end + if r3 > n then + r4 = r4 + 1 + r3 = r3 - m + end + if r4 > n then + r5 = r5 + 1 + r4 = r4 - m + end + if r5 > n then + r6 = r6 + 1 + r5 = r5 - m + end + if r6 > n then + r7 = r7 + 1 + r6 = r6 - m + end + if r7 > n then + r8 = r8 + 1 + r7 = r7 - m + end + if r8 > n then + r9 = r9 + 1 + r8 = r8 - m + end + if r9 > n then + r10 = r10 + 1 + r9 = r9 - m + end + if r10 > n then + r11 = r11 + 1 + r10 = r10 - m + end + if r11 > n then + r12 = r12 + 1 + r11 = r11 - m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} + + return reduce(result) +end + +local function shr(a) + local r1 = a[1] + local r2 = a[2] + local r3 = a[3] + local r4 = a[4] + local r5 = a[5] + local r6 = a[6] + local r7 = a[7] + local r8 = a[8] + local r9 = a[9] + local r10 = a[10] + local r11 = a[11] + local r12 = a[12] + + r1 = r1 / 2 + r1 = r1 - r1 % 1 + r1 = r1 + (r2 % 2) * 0x8000 + r2 = r2 / 2 + r2 = r2 - r2 % 1 + r2 = r2 + (r3 % 2) * 0x8000 + r3 = r3 / 2 + r3 = r3 - r3 % 1 + r3 = r3 + (r4 % 2) * 0x8000 + r4 = r4 / 2 + r4 = r4 - r4 % 1 + r4 = r4 + (r5 % 2) * 0x8000 + r5 = r5 / 2 + r5 = r5 - r5 % 1 + r5 = r5 + (r6 % 2) * 0x8000 + r6 = r6 / 2 + r6 = r6 - r6 % 1 + r6 = r6 + (r7 % 2) * 0x8000 + r7 = r7 / 2 + r7 = r7 - r7 % 1 + r7 = r7 + (r8 % 2) * 0x8000 + r8 = r8 / 2 + r8 = r8 - r8 % 1 + r8 = r8 + (r9 % 2) * 0x8000 + r9 = r9 / 2 + r9 = r9 - r9 % 1 + r9 = r9 + (r10 % 2) * 0x8000 + r10 = r10 / 2 + r10 = r10 - r10 % 1 + r10 = r10 + (r11 % 2) * 0x8000 + r11 = r11 / 2 + r11 = r11 - r11 % 1 + r11 = r11 + (r12 % 2) * 0x8000 + r12 = r12 / 2 + r12 = r12 - r12 % 1 + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} + + return result +end + +local function sub192(a, b) + local r1 = a[1] - b[1] + local r2 = a[2] - b[2] + local r3 = a[3] - b[3] + local r4 = a[4] - b[4] + local r5 = a[5] - b[5] + local r6 = a[6] - b[6] + local r7 = a[7] - b[7] + local r8 = a[8] - b[8] + local r9 = a[9] - b[9] + local r10 = a[10] - b[10] + local r11 = a[11] - b[11] + local r12 = a[12] - b[12] + + if r1 < 0 then + r2 = r2 - 1 + r1 = r1 + m + end + if r2 < 0 then + r3 = r3 - 1 + r2 = r2 + m + end + if r3 < 0 then + r4 = r4 - 1 + r3 = r3 + m + end + if r4 < 0 then + r5 = r5 - 1 + r4 = r4 + m + end + if r5 < 0 then + r6 = r6 - 1 + r5 = r5 + m + end + if r6 < 0 then + r7 = r7 - 1 + r6 = r6 + m + end + if r7 < 0 then + r8 = r8 - 1 + r7 = r7 + m + end + if r8 < 0 then + r9 = r9 - 1 + r8 = r8 + m + end + if r9 < 0 then + r10 = r10 - 1 + r9 = r9 + m + end + if r10 < 0 then + r11 = r11 - 1 + r10 = r10 + m + end + if r11 < 0 then + r12 = r12 - 1 + r11 = r11 + m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} + + return result +end + +local function sub(a, b) + local r1 = a[1] - b[1] + local r2 = a[2] - b[2] + local r3 = a[3] - b[3] + local r4 = a[4] - b[4] + local r5 = a[5] - b[5] + local r6 = a[6] - b[6] + local r7 = a[7] - b[7] + local r8 = a[8] - b[8] + local r9 = a[9] - b[9] + local r10 = a[10] - b[10] + local r11 = a[11] - b[11] + local r12 = a[12] - b[12] + + if r1 < 0 then + r2 = r2 - 1 + r1 = r1 + m + end + if r2 < 0 then + r3 = r3 - 1 + r2 = r2 + m + end + if r3 < 0 then + r4 = r4 - 1 + r3 = r3 + m + end + if r4 < 0 then + r5 = r5 - 1 + r4 = r4 + m + end + if r5 < 0 then + r6 = r6 - 1 + r5 = r5 + m + end + if r6 < 0 then + r7 = r7 - 1 + r6 = r6 + m + end + if r7 < 0 then + r8 = r8 - 1 + r7 = r7 + m + end + if r8 < 0 then + r9 = r9 - 1 + r8 = r8 + m + end + if r9 < 0 then + r10 = r10 - 1 + r9 = r9 + m + end + if r10 < 0 then + r11 = r11 - 1 + r10 = r10 + m + end + if r11 < 0 then + r12 = r12 - 1 + r11 = r11 + m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} + + if r12 < 0 then + result = add(result, p) + end + + return result +end + +local function add384(a, b) + local r1 = a[1] + b[1] + local r2 = a[2] + b[2] + local r3 = a[3] + b[3] + local r4 = a[4] + b[4] + local r5 = a[5] + b[5] + local r6 = a[6] + b[6] + local r7 = a[7] + b[7] + local r8 = a[8] + b[8] + local r9 = a[9] + b[9] + local r10 = a[10] + b[10] + local r11 = a[11] + b[11] + local r12 = a[12] + b[12] + local r13 = a[13] + b[13] + local r14 = a[14] + b[14] + local r15 = a[15] + b[15] + local r16 = a[16] + b[16] + local r17 = a[17] + b[17] + local r18 = a[18] + b[18] + local r19 = a[19] + b[19] + local r20 = a[20] + b[20] + local r21 = a[21] + b[21] + local r22 = a[22] + b[22] + local r23 = a[23] + b[23] + local r24 = a[24] + b[24] + + if r1 > n then + r2 = r2 + 1 + r1 = r1 - m + end + if r2 > n then + r3 = r3 + 1 + r2 = r2 - m + end + if r3 > n then + r4 = r4 + 1 + r3 = r3 - m + end + if r4 > n then + r5 = r5 + 1 + r4 = r4 - m + end + if r5 > n then + r6 = r6 + 1 + r5 = r5 - m + end + if r6 > n then + r7 = r7 + 1 + r6 = r6 - m + end + if r7 > n then + r8 = r8 + 1 + r7 = r7 - m + end + if r8 > n then + r9 = r9 + 1 + r8 = r8 - m + end + if r9 > n then + r10 = r10 + 1 + r9 = r9 - m + end + if r10 > n then + r11 = r11 + 1 + r10 = r10 - m + end + if r11 > n then + r12 = r12 + 1 + r11 = r11 - m + end + if r12 > n then + r13 = r13 + 1 + r12 = r12 - m + end + if r13 > n then + r14 = r14 + 1 + r13 = r13 - m + end + if r14 > n then + r15 = r15 + 1 + r14 = r14 - m + end + if r15 > n then + r16 = r16 + 1 + r15 = r15 - m + end + if r16 > n then + r17 = r17 + 1 + r16 = r16 - m + end + if r17 > n then + r18 = r18 + 1 + r17 = r17 - m + end + if r18 > n then + r19 = r19 + 1 + r18 = r18 - m + end + if r19 > n then + r20 = r20 + 1 + r19 = r19 - m + end + if r20 > n then + r21 = r21 + 1 + r20 = r20 - m + end + if r21 > n then + r22 = r22 + 1 + r21 = r21 - m + end + if r22 > n then + r23 = r23 + 1 + r22 = r22 - m + end + if r23 > n then + r24 = r24 + 1 + r23 = r23 - m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24} + + return result +end + +local function mul384(a, b) + local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = unpack(a) + local b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12 = unpack(b) + + local r1 = a1 * b1 + + local r2 = a1 * b2 + r2 = r2 + a2 * b1 + + local r3 = a1 * b3 + r3 = r3 + a2 * b2 + r3 = r3 + a3 * b1 + + local r4 = a1 * b4 + r4 = r4 + a2 * b3 + r4 = r4 + a3 * b2 + r4 = r4 + a4 * b1 + + local r5 = a1 * b5 + r5 = r5 + a2 * b4 + r5 = r5 + a3 * b3 + r5 = r5 + a4 * b2 + r5 = r5 + a5 * b1 + + local r6 = a1 * b6 + r6 = r6 + a2 * b5 + r6 = r6 + a3 * b4 + r6 = r6 + a4 * b3 + r6 = r6 + a5 * b2 + r6 = r6 + a6 * b1 + + local r7 = a1 * b7 + r7 = r7 + a2 * b6 + r7 = r7 + a3 * b5 + r7 = r7 + a4 * b4 + r7 = r7 + a5 * b3 + r7 = r7 + a6 * b2 + r7 = r7 + a7 * b1 + + local r8 = a1 * b8 + r8 = r8 + a2 * b7 + r8 = r8 + a3 * b6 + r8 = r8 + a4 * b5 + r8 = r8 + a5 * b4 + r8 = r8 + a6 * b3 + r8 = r8 + a7 * b2 + r8 = r8 + a8 * b1 + + local r9 = a1 * b9 + r9 = r9 + a2 * b8 + r9 = r9 + a3 * b7 + r9 = r9 + a4 * b6 + r9 = r9 + a5 * b5 + r9 = r9 + a6 * b4 + r9 = r9 + a7 * b3 + r9 = r9 + a8 * b2 + r9 = r9 + a9 * b1 + + local r10 = a1 * b10 + r10 = r10 + a2 * b9 + r10 = r10 + a3 * b8 + r10 = r10 + a4 * b7 + r10 = r10 + a5 * b6 + r10 = r10 + a6 * b5 + r10 = r10 + a7 * b4 + r10 = r10 + a8 * b3 + r10 = r10 + a9 * b2 + r10 = r10 + a10 * b1 + + local r11 = a1 * b11 + r11 = r11 + a2 * b10 + r11 = r11 + a3 * b9 + r11 = r11 + a4 * b8 + r11 = r11 + a5 * b7 + r11 = r11 + a6 * b6 + r11 = r11 + a7 * b5 + r11 = r11 + a8 * b4 + r11 = r11 + a9 * b3 + r11 = r11 + a10 * b2 + r11 = r11 + a11 * b1 + + local r12 = a1 * b12 + r12 = r12 + a2 * b11 + r12 = r12 + a3 * b10 + r12 = r12 + a4 * b9 + r12 = r12 + a5 * b8 + r12 = r12 + a6 * b7 + r12 = r12 + a7 * b6 + r12 = r12 + a8 * b5 + r12 = r12 + a9 * b4 + r12 = r12 + a10 * b3 + r12 = r12 + a11 * b2 + r12 = r12 + a12 * b1 + + local r13 = a2 * b12 + r13 = r13 + a3 * b11 + r13 = r13 + a4 * b10 + r13 = r13 + a5 * b9 + r13 = r13 + a6 * b8 + r13 = r13 + a7 * b7 + r13 = r13 + a8 * b6 + r13 = r13 + a9 * b5 + r13 = r13 + a10 * b4 + r13 = r13 + a11 * b3 + r13 = r13 + a12 * b2 + + local r14 = a3 * b12 + r14 = r14 + a4 * b11 + r14 = r14 + a5 * b10 + r14 = r14 + a6 * b9 + r14 = r14 + a7 * b8 + r14 = r14 + a8 * b7 + r14 = r14 + a9 * b6 + r14 = r14 + a10 * b5 + r14 = r14 + a11 * b4 + r14 = r14 + a12 * b3 + + local r15 = a4 * b12 + r15 = r15 + a5 * b11 + r15 = r15 + a6 * b10 + r15 = r15 + a7 * b9 + r15 = r15 + a8 * b8 + r15 = r15 + a9 * b7 + r15 = r15 + a10 * b6 + r15 = r15 + a11 * b5 + r15 = r15 + a12 * b4 + + local r16 = a5 * b12 + r16 = r16 + a6 * b11 + r16 = r16 + a7 * b10 + r16 = r16 + a8 * b9 + r16 = r16 + a9 * b8 + r16 = r16 + a10 * b7 + r16 = r16 + a11 * b6 + r16 = r16 + a12 * b5 + + local r17 = a6 * b12 + r17 = r17 + a7 * b11 + r17 = r17 + a8 * b10 + r17 = r17 + a9 * b9 + r17 = r17 + a10 * b8 + r17 = r17 + a11 * b7 + r17 = r17 + a12 * b6 + + local r18 = a7 * b12 + r18 = r18 + a8 * b11 + r18 = r18 + a9 * b10 + r18 = r18 + a10 * b9 + r18 = r18 + a11 * b8 + r18 = r18 + a12 * b7 + + local r19 = a8 * b12 + r19 = r19 + a9 * b11 + r19 = r19 + a10 * b10 + r19 = r19 + a11 * b9 + r19 = r19 + a12 * b8 + + local r20 = a9 * b12 + r20 = r20 + a10 * b11 + r20 = r20 + a11 * b10 + r20 = r20 + a12 * b9 + + local r21 = a10 * b12 + r21 = r21 + a11 * b11 + r21 = r21 + a12 * b10 + + local r22 = a11 * b12 + r22 = r22 + a12 * b11 + + local r23 = a12 * b12 + + local r24 = 0 + + r2 = r2 + (r1 / m) + r2 = r2 - r2 % 1 + r1 = r1 % m + r3 = r3 + (r2 / m) + r3 = r3 - r3 % 1 + r2 = r2 % m + r4 = r4 + (r3 / m) + r4 = r4 - r4 % 1 + r3 = r3 % m + r5 = r5 + (r4 / m) + r5 = r5 - r5 % 1 + r4 = r4 % m + r6 = r6 + (r5 / m) + r6 = r6 - r6 % 1 + r5 = r5 % m + r7 = r7 + (r6 / m) + r7 = r7 - r7 % 1 + r6 = r6 % m + r8 = r8 + (r7 / m) + r8 = r8 - r8 % 1 + r7 = r7 % m + r9 = r9 + (r8 / m) + r9 = r9 - r9 % 1 + r8 = r8 % m + r10 = r10 + (r9 / m) + r10 = r10 - r10 % 1 + r9 = r9 % m + r11 = r11 + (r10 / m) + r11 = r11 - r11 % 1 + r10 = r10 % m + r12 = r12 + (r11 / m) + r12 = r12 - r12 % 1 + r11 = r11 % m + r13 = r13 + (r12 / m) + r13 = r13 - r13 % 1 + r12 = r12 % m + r14 = r14 + (r13 / m) + r14 = r14 - r14 % 1 + r13 = r13 % m + r15 = r15 + (r14 / m) + r15 = r15 - r15 % 1 + r14 = r14 % m + r16 = r16 + (r15 / m) + r16 = r16 - r16 % 1 + r15 = r15 % m + r17 = r17 + (r16 / m) + r17 = r17 - r17 % 1 + r16 = r16 % m + r18 = r18 + (r17 / m) + r18 = r18 - r18 % 1 + r17 = r17 % m + r19 = r19 + (r18 / m) + r19 = r19 - r19 % 1 + r18 = r18 % m + r20 = r20 + (r19 / m) + r20 = r20 - r20 % 1 + r19 = r19 % m + r21 = r21 + (r20 / m) + r21 = r21 - r21 % 1 + r20 = r20 % m + r22 = r22 + (r21 / m) + r22 = r22 - r22 % 1 + r21 = r21 % m + r23 = r23 + (r22 / m) + r23 = r23 - r23 % 1 + r22 = r22 % m + r24 = r24 + (r23 / m) + r24 = r24 - r24 % 1 + r23 = r23 % m + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24} + + return result +end + +local function REDC(T) + local m = {unpack(mul384({unpack(T, 1, 12)}, p2), 1, 12)} + local t = {unpack(add384(T, mul384(m, p)), 13, 24)} + + return reduce(t) +end + +local function mul(a, b) + return REDC(mul384(a, b)) +end + +local function sqr(a) + local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = unpack(a) + + local r1 = a1 * a1 + + local r2 = a1 * a2 * 2 + + local r3 = a1 * a3 * 2 + r3 = r3 + a2 * a2 + + local r4 = a1 * a4 * 2 + r4 = r4 + a2 * a3 * 2 + + local r5 = a1 * a5 * 2 + r5 = r5 + a2 * a4 * 2 + r5 = r5 + a3 * a3 + + local r6 = a1 * a6 * 2 + r6 = r6 + a2 * a5 * 2 + r6 = r6 + a3 * a4 * 2 + + local r7 = a1 * a7 * 2 + r7 = r7 + a2 * a6 * 2 + r7 = r7 + a3 * a5 * 2 + r7 = r7 + a4 * a4 + + local r8 = a1 * a8 * 2 + r8 = r8 + a2 * a7 * 2 + r8 = r8 + a3 * a6 * 2 + r8 = r8 + a4 * a5 * 2 + + local r9 = a1 * a9 * 2 + r9 = r9 + a2 * a8 * 2 + r9 = r9 + a3 * a7 * 2 + r9 = r9 + a4 * a6 * 2 + r9 = r9 + a5 * a5 + + local r10 = a1 * a10 * 2 + r10 = r10 + a2 * a9 * 2 + r10 = r10 + a3 * a8 * 2 + r10 = r10 + a4 * a7 * 2 + r10 = r10 + a5 * a6 * 2 + + local r11 = a1 * a11 * 2 + r11 = r11 + a2 * a10 * 2 + r11 = r11 + a3 * a9 * 2 + r11 = r11 + a4 * a8 * 2 + r11 = r11 + a5 * a7 * 2 + r11 = r11 + a6 * a6 + + local r12 = a1 * a12 * 2 + r12 = r12 + a2 * a11 * 2 + r12 = r12 + a3 * a10 * 2 + r12 = r12 + a4 * a9 * 2 + r12 = r12 + a5 * a8 * 2 + r12 = r12 + a6 * a7 * 2 + + local r13 = a2 * a12 * 2 + r13 = r13 + a3 * a11 * 2 + r13 = r13 + a4 * a10 * 2 + r13 = r13 + a5 * a9 * 2 + r13 = r13 + a6 * a8 * 2 + r13 = r13 + a7 * a7 + + local r14 = a3 * a12 * 2 + r14 = r14 + a4 * a11 * 2 + r14 = r14 + a5 * a10 * 2 + r14 = r14 + a6 * a9 * 2 + r14 = r14 + a7 * a8 * 2 + + local r15 = a4 * a12 * 2 + r15 = r15 + a5 * a11 * 2 + r15 = r15 + a6 * a10 * 2 + r15 = r15 + a7 * a9 * 2 + r15 = r15 + a8 * a8 + + local r16 = a5 * a12 * 2 + r16 = r16 + a6 * a11 * 2 + r16 = r16 + a7 * a10 * 2 + r16 = r16 + a8 * a9 * 2 + + local r17 = a6 * a12 * 2 + r17 = r17 + a7 * a11 * 2 + r17 = r17 + a8 * a10 * 2 + r17 = r17 + a9 * a9 + + local r18 = a7 * a12 * 2 + r18 = r18 + a8 * a11 * 2 + r18 = r18 + a9 * a10 * 2 + + local r19 = a8 * a12 * 2 + r19 = r19 + a9 * a11 * 2 + r19 = r19 + a10 * a10 + + local r20 = a9 * a12 * 2 + r20 = r20 + a10 * a11 * 2 + + local r21 = a10 * a12 * 2 + r21 = r21 + a11 * a11 + + local r22 = a11 * a12 * 2 + + local r23 = a12 * a12 + + local r24 = 0 + + r2 = r2 + (r1 / m) + r2 = r2 - r2 % 1 + r1 = r1 % m + r3 = r3 + (r2 / m) + r3 = r3 - r3 % 1 + r2 = r2 % m + r4 = r4 + (r3 / m) + r4 = r4 - r4 % 1 + r3 = r3 % m + r5 = r5 + (r4 / m) + r5 = r5 - r5 % 1 + r4 = r4 % m + r6 = r6 + (r5 / m) + r6 = r6 - r6 % 1 + r5 = r5 % m + r7 = r7 + (r6 / m) + r7 = r7 - r7 % 1 + r6 = r6 % m + r8 = r8 + (r7 / m) + r8 = r8 - r8 % 1 + r7 = r7 % m + r9 = r9 + (r8 / m) + r9 = r9 - r9 % 1 + r8 = r8 % m + r10 = r10 + (r9 / m) + r10 = r10 - r10 % 1 + r9 = r9 % m + r11 = r11 + (r10 / m) + r11 = r11 - r11 % 1 + r10 = r10 % m + r12 = r12 + (r11 / m) + r12 = r12 - r12 % 1 + r11 = r11 % m + r13 = r13 + (r12 / m) + r13 = r13 - r13 % 1 + r12 = r12 % m + r14 = r14 + (r13 / m) + r14 = r14 - r14 % 1 + r13 = r13 % m + r15 = r15 + (r14 / m) + r15 = r15 - r15 % 1 + r14 = r14 % m + r16 = r16 + (r15 / m) + r16 = r16 - r16 % 1 + r15 = r15 % m + r17 = r17 + (r16 / m) + r17 = r17 - r17 % 1 + r16 = r16 % m + r18 = r18 + (r17 / m) + r18 = r18 - r18 % 1 + r17 = r17 % m + r19 = r19 + (r18 / m) + r19 = r19 - r19 % 1 + r18 = r18 % m + r20 = r20 + (r19 / m) + r20 = r20 - r20 % 1 + r19 = r19 % m + r21 = r21 + (r20 / m) + r21 = r21 - r21 % 1 + r20 = r20 % m + r22 = r22 + (r21 / m) + r22 = r22 - r22 % 1 + r21 = r21 % m + r23 = r23 + (r22 / m) + r23 = r23 - r23 % 1 + r22 = r22 % m + r24 = r24 + (r23 / m) + r24 = r24 - r24 % 1 + r23 = r23 % m + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24} + + return REDC(result) +end + +local function mont(a) + return mul(a, r2) +end + +local function invMont(a) + local a = {unpack(a)} + + for i = 13, 24 do + a[i] = 0 + end + + return REDC(a) +end + +return { + eq = eq, + add = add, + shr = shr, + sub192 = sub192, + sub = sub, + mul = mul, + sqr = sqr, + mont = mont, + invMont = invMont, +} diff --git a/sys/apis/crypto/ecc/fq.lua b/sys/apis/crypto/ecc/fq.lua new file mode 100644 index 0000000..277f64d --- /dev/null +++ b/sys/apis/crypto/ecc/fq.lua @@ -0,0 +1,741 @@ +-- Fq Integer Arithmetic + +local n = 0xffff +local m = 0x10000 + +local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532} +local qn = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +local function eq(a, b) + for i = 1, 12 do + if a[i] ~= b[i] then + return false + end + end + + return true +end + +local function cmp(a, b) + for i = 12, 1, -1 do + if a[i] > b[i] then + return 1 + elseif a[i] < b[i] then + return -1 + end + end + + return 0 +end + +local function cmp384(a, b) + for i = 24, 1, -1 do + if a[i] > b[i] then + return 1 + elseif a[i] < b[i] then + return -1 + end + end + + return 0 +end + +local function bytes(x) + local result = {} + + for i = 0, 11 do + local m = x[i + 1] % 256 + result[2 * i + 1] = m + result[2 * i + 2] = (x[i + 1] - m) / 256 + end + + return result +end + +local function fromBytes(enc) + local result = {} + + for i = 0, 11 do + result[i + 1] = enc[2 * i + 1] % 256 + result[i + 1] = result[i + 1] + enc[2 * i + 2] * 256 + end + + return result +end + +local function sub192(a, b) + local r1 = a[1] - b[1] + local r2 = a[2] - b[2] + local r3 = a[3] - b[3] + local r4 = a[4] - b[4] + local r5 = a[5] - b[5] + local r6 = a[6] - b[6] + local r7 = a[7] - b[7] + local r8 = a[8] - b[8] + local r9 = a[9] - b[9] + local r10 = a[10] - b[10] + local r11 = a[11] - b[11] + local r12 = a[12] - b[12] + + if r1 < 0 then + r2 = r2 - 1 + r1 = r1 + m + end + if r2 < 0 then + r3 = r3 - 1 + r2 = r2 + m + end + if r3 < 0 then + r4 = r4 - 1 + r3 = r3 + m + end + if r4 < 0 then + r5 = r5 - 1 + r4 = r4 + m + end + if r5 < 0 then + r6 = r6 - 1 + r5 = r5 + m + end + if r6 < 0 then + r7 = r7 - 1 + r6 = r6 + m + end + if r7 < 0 then + r8 = r8 - 1 + r7 = r7 + m + end + if r8 < 0 then + r9 = r9 - 1 + r8 = r8 + m + end + if r9 < 0 then + r10 = r10 - 1 + r9 = r9 + m + end + if r10 < 0 then + r11 = r11 - 1 + r10 = r10 + m + end + if r11 < 0 then + r12 = r12 - 1 + r11 = r11 + m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} + + return result +end + +local function reduce(a) + local result = {unpack(a)} + + if cmp(result, q) >= 0 then + result = sub192(result, q) + end + + return result +end + +local function add(a, b) + local r1 = a[1] + b[1] + local r2 = a[2] + b[2] + local r3 = a[3] + b[3] + local r4 = a[4] + b[4] + local r5 = a[5] + b[5] + local r6 = a[6] + b[6] + local r7 = a[7] + b[7] + local r8 = a[8] + b[8] + local r9 = a[9] + b[9] + local r10 = a[10] + b[10] + local r11 = a[11] + b[11] + local r12 = a[12] + b[12] + + if r1 > n then + r2 = r2 + 1 + r1 = r1 - m + end + if r2 > n then + r3 = r3 + 1 + r2 = r2 - m + end + if r3 > n then + r4 = r4 + 1 + r3 = r3 - m + end + if r4 > n then + r5 = r5 + 1 + r4 = r4 - m + end + if r5 > n then + r6 = r6 + 1 + r5 = r5 - m + end + if r6 > n then + r7 = r7 + 1 + r6 = r6 - m + end + if r7 > n then + r8 = r8 + 1 + r7 = r7 - m + end + if r8 > n then + r9 = r9 + 1 + r8 = r8 - m + end + if r9 > n then + r10 = r10 + 1 + r9 = r9 - m + end + if r10 > n then + r11 = r11 + 1 + r10 = r10 - m + end + if r11 > n then + r12 = r12 + 1 + r11 = r11 - m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} + + return reduce(result) +end + +local function sub(a, b) + local result = sub192(a, b) + + if result[12] < 0 then + result = add(result, q) + end + + return result +end + +local function add384(a, b) + local r1 = a[1] + b[1] + local r2 = a[2] + b[2] + local r3 = a[3] + b[3] + local r4 = a[4] + b[4] + local r5 = a[5] + b[5] + local r6 = a[6] + b[6] + local r7 = a[7] + b[7] + local r8 = a[8] + b[8] + local r9 = a[9] + b[9] + local r10 = a[10] + b[10] + local r11 = a[11] + b[11] + local r12 = a[12] + b[12] + local r13 = a[13] + b[13] + local r14 = a[14] + b[14] + local r15 = a[15] + b[15] + local r16 = a[16] + b[16] + local r17 = a[17] + b[17] + local r18 = a[18] + b[18] + local r19 = a[19] + b[19] + local r20 = a[20] + b[20] + local r21 = a[21] + b[21] + local r22 = a[22] + b[22] + local r23 = a[23] + b[23] + local r24 = a[24] + b[24] + + if r1 > n then + r2 = r2 + 1 + r1 = r1 - m + end + if r2 > n then + r3 = r3 + 1 + r2 = r2 - m + end + if r3 > n then + r4 = r4 + 1 + r3 = r3 - m + end + if r4 > n then + r5 = r5 + 1 + r4 = r4 - m + end + if r5 > n then + r6 = r6 + 1 + r5 = r5 - m + end + if r6 > n then + r7 = r7 + 1 + r6 = r6 - m + end + if r7 > n then + r8 = r8 + 1 + r7 = r7 - m + end + if r8 > n then + r9 = r9 + 1 + r8 = r8 - m + end + if r9 > n then + r10 = r10 + 1 + r9 = r9 - m + end + if r10 > n then + r11 = r11 + 1 + r10 = r10 - m + end + if r11 > n then + r12 = r12 + 1 + r11 = r11 - m + end + if r12 > n then + r13 = r13 + 1 + r12 = r12 - m + end + if r13 > n then + r14 = r14 + 1 + r13 = r13 - m + end + if r14 > n then + r15 = r15 + 1 + r14 = r14 - m + end + if r15 > n then + r16 = r16 + 1 + r15 = r15 - m + end + if r16 > n then + r17 = r17 + 1 + r16 = r16 - m + end + if r17 > n then + r18 = r18 + 1 + r17 = r17 - m + end + if r18 > n then + r19 = r19 + 1 + r18 = r18 - m + end + if r19 > n then + r20 = r20 + 1 + r19 = r19 - m + end + if r20 > n then + r21 = r21 + 1 + r20 = r20 - m + end + if r21 > n then + r22 = r22 + 1 + r21 = r21 - m + end + if r22 > n then + r23 = r23 + 1 + r22 = r22 - m + end + if r23 > n then + r24 = r24 + 1 + r23 = r23 - m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24} + + return result +end + +local function sub384(a, b) + local r1 = a[1] - b[1] + local r2 = a[2] - b[2] + local r3 = a[3] - b[3] + local r4 = a[4] - b[4] + local r5 = a[5] - b[5] + local r6 = a[6] - b[6] + local r7 = a[7] - b[7] + local r8 = a[8] - b[8] + local r9 = a[9] - b[9] + local r10 = a[10] - b[10] + local r11 = a[11] - b[11] + local r12 = a[12] - b[12] + local r13 = a[13] - b[13] + local r14 = a[14] - b[14] + local r15 = a[15] - b[15] + local r16 = a[16] - b[16] + local r17 = a[17] - b[17] + local r18 = a[18] - b[18] + local r19 = a[19] - b[19] + local r20 = a[20] - b[20] + local r21 = a[21] - b[21] + local r22 = a[22] - b[22] + local r23 = a[23] - b[23] + local r24 = a[24] - b[24] + + if r1 < 0 then + r2 = r2 - 1 + r1 = r1 + m + end + if r2 < 0 then + r3 = r3 - 1 + r2 = r2 + m + end + if r3 < 0 then + r4 = r4 - 1 + r3 = r3 + m + end + if r4 < 0 then + r5 = r5 - 1 + r4 = r4 + m + end + if r5 < 0 then + r6 = r6 - 1 + r5 = r5 + m + end + if r6 < 0 then + r7 = r7 - 1 + r6 = r6 + m + end + if r7 < 0 then + r8 = r8 - 1 + r7 = r7 + m + end + if r8 < 0 then + r9 = r9 - 1 + r8 = r8 + m + end + if r9 < 0 then + r10 = r10 - 1 + r9 = r9 + m + end + if r10 < 0 then + r11 = r11 - 1 + r10 = r10 + m + end + if r11 < 0 then + r12 = r12 - 1 + r11 = r11 + m + end + if r12 < 0 then + r13 = r13 - 1 + r12 = r12 + m + end + if r13 < 0 then + r14 = r14 - 1 + r13 = r13 + m + end + if r14 < 0 then + r15 = r15 - 1 + r14 = r14 + m + end + if r15 < 0 then + r16 = r16 - 1 + r15 = r15 + m + end + if r16 < 0 then + r17 = r17 - 1 + r16 = r16 + m + end + if r17 < 0 then + r18 = r18 - 1 + r17 = r17 + m + end + if r18 < 0 then + r19 = r19 - 1 + r18 = r18 + m + end + if r19 < 0 then + r20 = r20 - 1 + r19 = r19 + m + end + if r20 < 0 then + r21 = r21 - 1 + r20 = r20 + m + end + if r21 < 0 then + r22 = r22 - 1 + r21 = r21 + m + end + if r22 < 0 then + r23 = r23 - 1 + r22 = r22 + m + end + if r23 < 0 then + r24 = r24 - 1 + r23 = r23 + m + end + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24} + + return result +end + +local function mul384(a, b) + local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = unpack(a) + local b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12 = unpack(b) + + local r1 = a1 * b1 + + local r2 = a1 * b2 + r2 = r2 + a2 * b1 + + local r3 = a1 * b3 + r3 = r3 + a2 * b2 + r3 = r3 + a3 * b1 + + local r4 = a1 * b4 + r4 = r4 + a2 * b3 + r4 = r4 + a3 * b2 + r4 = r4 + a4 * b1 + + local r5 = a1 * b5 + r5 = r5 + a2 * b4 + r5 = r5 + a3 * b3 + r5 = r5 + a4 * b2 + r5 = r5 + a5 * b1 + + local r6 = a1 * b6 + r6 = r6 + a2 * b5 + r6 = r6 + a3 * b4 + r6 = r6 + a4 * b3 + r6 = r6 + a5 * b2 + r6 = r6 + a6 * b1 + + local r7 = a1 * b7 + r7 = r7 + a2 * b6 + r7 = r7 + a3 * b5 + r7 = r7 + a4 * b4 + r7 = r7 + a5 * b3 + r7 = r7 + a6 * b2 + r7 = r7 + a7 * b1 + + local r8 = a1 * b8 + r8 = r8 + a2 * b7 + r8 = r8 + a3 * b6 + r8 = r8 + a4 * b5 + r8 = r8 + a5 * b4 + r8 = r8 + a6 * b3 + r8 = r8 + a7 * b2 + r8 = r8 + a8 * b1 + + local r9 = a1 * b9 + r9 = r9 + a2 * b8 + r9 = r9 + a3 * b7 + r9 = r9 + a4 * b6 + r9 = r9 + a5 * b5 + r9 = r9 + a6 * b4 + r9 = r9 + a7 * b3 + r9 = r9 + a8 * b2 + r9 = r9 + a9 * b1 + + local r10 = a1 * b10 + r10 = r10 + a2 * b9 + r10 = r10 + a3 * b8 + r10 = r10 + a4 * b7 + r10 = r10 + a5 * b6 + r10 = r10 + a6 * b5 + r10 = r10 + a7 * b4 + r10 = r10 + a8 * b3 + r10 = r10 + a9 * b2 + r10 = r10 + a10 * b1 + + local r11 = a1 * b11 + r11 = r11 + a2 * b10 + r11 = r11 + a3 * b9 + r11 = r11 + a4 * b8 + r11 = r11 + a5 * b7 + r11 = r11 + a6 * b6 + r11 = r11 + a7 * b5 + r11 = r11 + a8 * b4 + r11 = r11 + a9 * b3 + r11 = r11 + a10 * b2 + r11 = r11 + a11 * b1 + + local r12 = a1 * b12 + r12 = r12 + a2 * b11 + r12 = r12 + a3 * b10 + r12 = r12 + a4 * b9 + r12 = r12 + a5 * b8 + r12 = r12 + a6 * b7 + r12 = r12 + a7 * b6 + r12 = r12 + a8 * b5 + r12 = r12 + a9 * b4 + r12 = r12 + a10 * b3 + r12 = r12 + a11 * b2 + r12 = r12 + a12 * b1 + + local r13 = a2 * b12 + r13 = r13 + a3 * b11 + r13 = r13 + a4 * b10 + r13 = r13 + a5 * b9 + r13 = r13 + a6 * b8 + r13 = r13 + a7 * b7 + r13 = r13 + a8 * b6 + r13 = r13 + a9 * b5 + r13 = r13 + a10 * b4 + r13 = r13 + a11 * b3 + r13 = r13 + a12 * b2 + + local r14 = a3 * b12 + r14 = r14 + a4 * b11 + r14 = r14 + a5 * b10 + r14 = r14 + a6 * b9 + r14 = r14 + a7 * b8 + r14 = r14 + a8 * b7 + r14 = r14 + a9 * b6 + r14 = r14 + a10 * b5 + r14 = r14 + a11 * b4 + r14 = r14 + a12 * b3 + + local r15 = a4 * b12 + r15 = r15 + a5 * b11 + r15 = r15 + a6 * b10 + r15 = r15 + a7 * b9 + r15 = r15 + a8 * b8 + r15 = r15 + a9 * b7 + r15 = r15 + a10 * b6 + r15 = r15 + a11 * b5 + r15 = r15 + a12 * b4 + + local r16 = a5 * b12 + r16 = r16 + a6 * b11 + r16 = r16 + a7 * b10 + r16 = r16 + a8 * b9 + r16 = r16 + a9 * b8 + r16 = r16 + a10 * b7 + r16 = r16 + a11 * b6 + r16 = r16 + a12 * b5 + + local r17 = a6 * b12 + r17 = r17 + a7 * b11 + r17 = r17 + a8 * b10 + r17 = r17 + a9 * b9 + r17 = r17 + a10 * b8 + r17 = r17 + a11 * b7 + r17 = r17 + a12 * b6 + + local r18 = a7 * b12 + r18 = r18 + a8 * b11 + r18 = r18 + a9 * b10 + r18 = r18 + a10 * b9 + r18 = r18 + a11 * b8 + r18 = r18 + a12 * b7 + + local r19 = a8 * b12 + r19 = r19 + a9 * b11 + r19 = r19 + a10 * b10 + r19 = r19 + a11 * b9 + r19 = r19 + a12 * b8 + + local r20 = a9 * b12 + r20 = r20 + a10 * b11 + r20 = r20 + a11 * b10 + r20 = r20 + a12 * b9 + + local r21 = a10 * b12 + r21 = r21 + a11 * b11 + r21 = r21 + a12 * b10 + + local r22 = a11 * b12 + r22 = r22 + a12 * b11 + + local r23 = a12 * b12 + + local r24 = 0 + + r2 = r2 + (r1 / m) + r2 = r2 - r2 % 1 + r1 = r1 % m + r3 = r3 + (r2 / m) + r3 = r3 - r3 % 1 + r2 = r2 % m + r4 = r4 + (r3 / m) + r4 = r4 - r4 % 1 + r3 = r3 % m + r5 = r5 + (r4 / m) + r5 = r5 - r5 % 1 + r4 = r4 % m + r6 = r6 + (r5 / m) + r6 = r6 - r6 % 1 + r5 = r5 % m + r7 = r7 + (r6 / m) + r7 = r7 - r7 % 1 + r6 = r6 % m + r8 = r8 + (r7 / m) + r8 = r8 - r8 % 1 + r7 = r7 % m + r9 = r9 + (r8 / m) + r9 = r9 - r9 % 1 + r8 = r8 % m + r10 = r10 + (r9 / m) + r10 = r10 - r10 % 1 + r9 = r9 % m + r11 = r11 + (r10 / m) + r11 = r11 - r11 % 1 + r10 = r10 % m + r12 = r12 + (r11 / m) + r12 = r12 - r12 % 1 + r11 = r11 % m + r13 = r13 + (r12 / m) + r13 = r13 - r13 % 1 + r12 = r12 % m + r14 = r14 + (r13 / m) + r14 = r14 - r14 % 1 + r13 = r13 % m + r15 = r15 + (r14 / m) + r15 = r15 - r15 % 1 + r14 = r14 % m + r16 = r16 + (r15 / m) + r16 = r16 - r16 % 1 + r15 = r15 % m + r17 = r17 + (r16 / m) + r17 = r17 - r17 % 1 + r16 = r16 % m + r18 = r18 + (r17 / m) + r18 = r18 - r18 % 1 + r17 = r17 % m + r19 = r19 + (r18 / m) + r19 = r19 - r19 % 1 + r18 = r18 % m + r20 = r20 + (r19 / m) + r20 = r20 - r20 % 1 + r19 = r19 % m + r21 = r21 + (r20 / m) + r21 = r21 - r21 % 1 + r20 = r20 % m + r22 = r22 + (r21 / m) + r22 = r22 - r22 % 1 + r21 = r21 % m + r23 = r23 + (r22 / m) + r23 = r23 - r23 % 1 + r22 = r22 % m + r24 = r24 + (r23 / m) + r24 = r24 - r24 % 1 + r23 = r23 % m + + local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24} + + return result +end + +local function reduce384(a) + local result = {unpack(a)} + + while cmp384(result, qn) >= 0 do + local qn = {unpack(qn)} + local qn2 = add384(qn, qn) + while cmp384(result, qn2) > 0 do + qn = qn2 + qn2 = add384(qn2, qn2) + end + result = sub384(result, qn) + end + + result = {unpack(result, 1, 12)} + + return result +end + +local function mul(a, b) + return reduce384(mul384(a, b)) +end + +return { + eq = eq, + cmp = cmp, + bytes = bytes, + fromBytes = fromBytes, + reduce = reduce, + add = add, + sub = sub, + mul = mul, +} diff --git a/sys/apis/crypto/ecc/init.lua b/sys/apis/crypto/ecc/init.lua new file mode 100644 index 0000000..51e3b57 --- /dev/null +++ b/sys/apis/crypto/ecc/init.lua @@ -0,0 +1,87 @@ +local fq = require('crypto.ecc.fq') +local elliptic = require('crypto.ecc.elliptic') +local sha256 = require('crypto.sha2') + +local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532} + +local sLen = 24 +local eLen = 24 + +local function hashModQ(sk) + local hash = sha256.hmac({0x00}, sk) + local x + repeat + hash = sha256.digest(hash) + x = fq.fromBytes(hash) + until fq.cmp(x, q) <= 0 + + return x +end + +local function publicKey(sk) + local x = hashModQ(sk) + + local Y = elliptic.scalarMulG(x) + local pk = elliptic.pointEncode(Y) + + return pk +end + +local function exchange(sk, pk) + local Y = elliptic.pointDecode(pk) + local x = hashModQ(sk) + + local Z = elliptic.scalarMul(x, Y) + Z = elliptic.pointScale(Z) + + local ss = fq.bytes(Z[2]) + local ss = sha256.digest(ss) + + return ss +end + +local function sign(sk, message) + message = type(message) == "table" and string.char(unpack(message)) or message + sk = type(sk) == "table" and string.char(unpack(sk)) or sk + local epoch = tostring(os.epoch("utc")) + local x = hashModQ(sk) + local k = hashModQ(message .. epoch .. sk) + + local R = elliptic.scalarMulG(k) + R = string.char(unpack(elliptic.pointEncode(R))) + local e = hashModQ(R .. message) + local s = fq.sub(k, fq.mul(x, e)) + + e = fq.bytes(e) + s = fq.bytes(s) + + local sig = {unpack(e)} + + for i = 1, #s do + sig[#sig + 1] = s[i] + end + + return sig +end + +local function verify(pk, message, sig) + local Y = elliptic.pointDecode(pk) + local e = {unpack(sig, 1, eLen)} + local s = {unpack(sig, eLen + 1, eLen + sLen)} + + e = fq.fromBytes(e) + s = fq.fromBytes(s) + + local R = elliptic.pointAdd(elliptic.scalarMulG(s), elliptic.scalarMul(e, Y)) + R = string.char(unpack(elliptic.pointEncode(R))) + local e2 = hashModQ(R .. message) + + return fq.eq(e2, e) +end + +return { + publicKey = publicKey, + exchange = exchange, + sign = sign, + verify = verify, +} diff --git a/sys/apis/sha2.lua b/sys/apis/crypto/sha2.lua similarity index 92% rename from sys/apis/sha2.lua rename to sys/apis/crypto/sha2.lua index f7965bc..162f5cb 100644 --- a/sys/apis/sha2.lua +++ b/sys/apis/crypto/sha2.lua @@ -1,8 +1,6 @@ -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft -- By Anavrins -local bit = _G.bit - local mod32 = 2^32 local band = bit32 and bit32.band or bit.band local bnot = bit32 and bit32.bnot or bit.bnot @@ -40,7 +38,7 @@ local function counter(incr) local t1, t2 = 0, 0 if 0xFFFFFFFF - t1 < incr then t2 = t2 + 1 - t1 = incr - (0xFFFFFFFF - t1) - 1 + t1 = incr - (0xFFFFFFFF - t1) - 1 else t1 = t1 + incr end return t2, t1 @@ -68,7 +66,7 @@ end local function digestblock(w, C) for j = 17, 64 do - --local v = w[j-15] + local v = w[j-15] local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3)) local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10)) w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32 @@ -97,7 +95,7 @@ end local mt = { __tostring = function(a) return string.char(unpack(a)) end, __index = { - toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end, + toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end, isEqual = function(self, t) if type(t) ~= "table" then return false end if #self ~= #t then return false end @@ -122,7 +120,7 @@ local function toBytes(t, n) end local function digest(data) - data = data or "" + local data = data or "" data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} data = preprocess(data) @@ -132,8 +130,8 @@ local function digest(data) end local function hmac(data, key) - data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} - key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)} + local data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} + local key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)} local blocksize = 64 @@ -163,13 +161,12 @@ local function hmac(data, key) end local function pbkdf2(pass, salt, iter, dklen) + local salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} local hashlen = 32 + local dklen = dklen or 32 local block = 1 local out = {} - dklen = dklen or 32 - salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} - while dklen > 0 do local ikey = {} local isalt = {upack(salt)} @@ -197,4 +194,4 @@ return { digest = digest, hmac = hmac, pbkdf2 = pbkdf2, -} \ No newline at end of file +} diff --git a/sys/apis/injector.lua b/sys/apis/injector.lua index 5497b24..799cf0b 100644 --- a/sys/apis/injector.lua +++ b/sys/apis/injector.lua @@ -192,7 +192,7 @@ return function(env) error(msg, 2) end end - error('Unable to find module ' .. modname) + error('Unable to find module ' .. modname, 2) end return env.require -- backwards compatible diff --git a/sys/apis/security.lua b/sys/apis/security.lua index ab0fea8..691df97 100644 --- a/sys/apis/security.lua +++ b/sys/apis/security.lua @@ -1,4 +1,6 @@ local Config = require('config') +local Util = require('util') +local ECC = require('crypto.ecc') local Security = { } @@ -14,33 +16,18 @@ end function Security.getSecretKey() local config = Config.load('os') if not config.secretKey then - config.secretKey = math.random(100000, 999999) + config.secretKey = "" + for _ = 1, 32 do + config.secretKey = config.secretKey .. ("%02x"):format(math.random(0, 0xFF)) + end Config.update('os', config) end - return config.secretKey + return Util.hexToByteArray(config.secretKey) end function Security.getPublicKey() - local exchange = { - base = 11, - primeMod = 625210769 - } - - local function modexp(base, exponent, modulo) - local remainder = base - - for _ = 1, exponent-1 do - remainder = remainder * remainder - if remainder >= modulo then - remainder = remainder % modulo - end - end - - return remainder - end - local secretKey = Security.getSecretKey() - return modexp(exchange.base, secretKey, exchange.primeMod) + return ECC.publicKey(secretKey) end function Security.updatePassword(password) diff --git a/sys/apis/socket.lua b/sys/apis/socket.lua index 726b4d3..ae1bc60 100644 --- a/sys/apis/socket.lua +++ b/sys/apis/socket.lua @@ -1,4 +1,4 @@ -local Crypto = require('crypto') +local Crypto = require('crypto.chacha20') local Security = require('security') local Util = require('util') @@ -167,15 +167,16 @@ local function trusted(msg, port) local trustList = Util.readTable('usr/.known_hosts') or { } local pubKey = trustList[msg.shost] - if pubKey then - local data = Crypto.decrypt(msg.t or '', pubKey) + if pubKey and msg.t then + pubKey = Util.hexToByteArray(pubKey) + local data = Crypto.decrypt(msg.t, pubKey) - if data.nts then -- upgraded security + if data and data.nts then -- upgraded security return data.nts and tonumber(data.nts) and math.abs(os.epoch('utc') - data.nts) < 1024 end --local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod) - return data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 24 + return data and data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 24 end end diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 042ba84..271fcfd 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -10,6 +10,19 @@ local _sformat = string.format local _srep = string.rep local _ssub = string.sub +function Util.hexToByteArray(str) + local r = {} + str = tostring(str) + for b in str:gmatch("%x%x?") do + r[#r+1] = tonumber(b, 16) + end + return r +end + +function Util.byteArrayToHex(tbl) + return ("%02x"):rep(#tbl):format(unpack(tbl)) +end + function Util.tryTimed(timeout, f, ...) local c = os.clock() repeat diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 80d170e..8a4507b 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -1,7 +1,6 @@ local Ansi = require('ansi') -local Config = require('config') local Security = require('security') -local SHA1 = require('sha1') +local SHA2 = require('crypto.sha2') local UI = require('ui') local colors = _G.colors @@ -108,7 +107,7 @@ end function page.wizard.pages.password:validate() if #self.newPass.value > 0 then - Security.updatePassword(SHA1.sha1(self.newPass.value)) + Security.updatePassword(SHA2.digest(self.newPass.value):toHex()) end --[[ if #self.group.value > 0 then diff --git a/sys/apps/network/trust.lua b/sys/apps/network/trust.lua index 9d12c3a..b2e493f 100644 --- a/sys/apps/network/trust.lua +++ b/sys/apps/network/trust.lua @@ -1,4 +1,4 @@ -local Crypto = require('crypto') +local Crypto = require('crypto.chacha20') local Event = require('event') local Security = require('security') local Socket = require('socket') @@ -14,7 +14,7 @@ local function trustConnection(socket) data = Crypto.decrypt(data, password) if data and data.pk and data.dh == socket.dhost then local trustList = Util.readTable('usr/.known_hosts') or { } - trustList[data.dh] = data.pk + trustList[data.dh] = Util.byteArrayToHex(data.pk) Util.writeTable('usr/.known_hosts', trustList) socket:write({ success = true, msg = 'Trust accepted' }) @@ -26,8 +26,8 @@ local function trustConnection(socket) end Event.addRoutine(function() - print('trust: listening on port 19') + while true do local socket = Socket.server(19) diff --git a/sys/apps/password.lua b/sys/apps/password.lua index ca0f5b5..6beb700 100644 --- a/sys/apps/password.lua +++ b/sys/apps/password.lua @@ -1,10 +1,10 @@ local Security = require('security') -local SHA1 = require('sha1') +local SHA2 = require('crypto.sha2') local Terminal = require('terminal') local password = Terminal.readPassword('Enter new password: ') if password then - Security.updatePassword(SHA1.sha1(password)) + Security.updatePassword(SHA2.digest(password):toHex()) print('Password updated') end diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua index 5f705a6..7ad5769 100644 --- a/sys/apps/system/password.lua +++ b/sys/apps/system/password.lua @@ -1,5 +1,5 @@ local Security = require('security') -local SHA1 = require('sha1') +local SHA2 = require('crypto.sha2') local UI = require('ui') local colors = _G.colors @@ -40,11 +40,11 @@ function passwordTab:eventHandler(event) if #self.newPass.value == 0 then self:emit({ type = 'error_message', message = 'Invalid password' }) - elseif Security.getPassword() and not Security.verifyPassword(SHA1.sha1(self.oldPass.value)) then + elseif Security.getPassword() and not Security.verifyPassword(SHA2.digest(self.oldPass.value):toHex()) then self:emit({ type = 'error_message', message = 'Passwords do not match' }) else - Security.updatePassword(SHA1.sha1(self.newPass.value)) + Security.updatePassword(SHA2.digest(self.newPass.value):toHex()) self.oldPass.inactive = false self:emit({ type = 'success_message', message = 'Password updated' }) end diff --git a/sys/apps/trust.lua b/sys/apps/trust.lua index da8ff55..90c01d4 100644 --- a/sys/apps/trust.lua +++ b/sys/apps/trust.lua @@ -1,6 +1,6 @@ -local Crypto = require('crypto') +local Crypto = require('crypto.chacha20') local Security = require('security') -local SHA1 = require('sha1') +local SHA2 = require('crypto.sha2') local Socket = require('socket') local Terminal = require('terminal') @@ -35,7 +35,7 @@ end local publicKey = Security.getPublicKey() -socket:write(Crypto.encrypt({ pk = publicKey, dh = os.getComputerID() }, SHA1.sha1(password))) +socket:write(Crypto.encrypt({ pk = publicKey, dh = os.getComputerID() }, SHA2.digest(password):toHex())) local data = socket:read(2) socket:close() diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua index 2ecf6d8..e3a7b5a 100644 --- a/sys/autorun/welcome.lua +++ b/sys/autorun/welcome.lua @@ -1,11 +1,45 @@ local Config = require('config') +local Util = require('util') -local shell = _ENV.shell +local fs = _G.fs +local shell = _ENV.shell local config = Config.load('os') if not config.welcomed and shell.openForegroundTab then config.welcomed = true + config.securityUpdate = true + config.readNotes = 1 Config.update('os', config) shell.openForegroundTab('Welcome') end + +if not config.securityUpdate then + config.securityUpdate = true + config.secretKey = nil + config.password = nil + config.readNotes = 1 + Config.update('os', config) + + fs.delete('usr/.known_hosts') + + Util.writeFile('sys/notes_1.txt', [[ +An important security update has been applied. + +Unfortunately, this update has reset the +password on the system. You can set a new +password in System->System->Password. + +All computers that you connect to will also +need to be updated as well. + +Thanks for your patience. And... thanks to +Anavrins for the much improved security. + ]]) +end + +if fs.exists('sys/notes_1.txt') and shell.openForegroundTab then + shell.openForegroundTab('edit sys/notes_1.txt') + os.sleep(2) + fs.delete('sys/notes_1.txt') +end From c3d52c1aaba0681a911b4da42efc1f07bebfecb4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 28 Jun 2019 06:33:47 -0400 Subject: [PATCH 155/231] crypto cleanup --- sys/apis/crypto/chacha20.lua | 5 +- sys/apis/crypto/ecc/init.lua | 6 +- sys/apis/crypto/sha2.lua | 25 ++-- sys/apis/sha1.lua | 280 ----------------------------------- sys/apps/Overview.lua | 6 +- sys/apps/Welcome.lua | 4 +- sys/apps/password.lua | 4 +- sys/apps/system/password.lua | 6 +- sys/apps/trust.lua | 4 +- sys/autorun/welcome.lua | 1 + 10 files changed, 35 insertions(+), 306 deletions(-) delete mode 100644 sys/apis/sha1.lua diff --git a/sys/apis/crypto/chacha20.lua b/sys/apis/crypto/chacha20.lua index b0763dd..03386a4 100644 --- a/sys/apis/crypto/chacha20.lua +++ b/sys/apis/crypto/chacha20.lua @@ -10,6 +10,7 @@ local bxor = bit32.bxor local band = bit32.band local blshift = bit32.lshift local brshift = bit32.arshift +local os = _G.os local textutils = _G.textutils local mod = 2^32 @@ -91,7 +92,7 @@ end local mt = { __tostring = function(a) return string.char(unpack(a)) end, __index = { - toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end, + toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end, isEqual = function(self, t) if type(t) ~= "table" then return false end if #self ~= #t then return false end @@ -110,7 +111,7 @@ local function crypt(data, key, nonce, cntr, round) assert(#key == 16 or #key == 32, "ChaCha20: Invalid key length ("..#key.."), must be 16 or 32") assert(#nonce == 12, "ChaCha20: Invalid nonce length ("..#nonce.."), must be 12") - local data = type(data) == "table" and {unpack(data)} or {tostring(data):byte(1,-1)} + data = type(data) == "table" and {unpack(data)} or {tostring(data):byte(1,-1)} cntr = tonumber(cntr) or 1 round = tonumber(round) or 20 diff --git a/sys/apis/crypto/ecc/init.lua b/sys/apis/crypto/ecc/init.lua index 51e3b57..f765542 100644 --- a/sys/apis/crypto/ecc/init.lua +++ b/sys/apis/crypto/ecc/init.lua @@ -2,6 +2,8 @@ local fq = require('crypto.ecc.fq') local elliptic = require('crypto.ecc.elliptic') local sha256 = require('crypto.sha2') +local os = _G.os + local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532} local sLen = 24 @@ -35,9 +37,7 @@ local function exchange(sk, pk) Z = elliptic.pointScale(Z) local ss = fq.bytes(Z[2]) - local ss = sha256.digest(ss) - - return ss + return sha256.digest(ss) end local function sign(sk, message) diff --git a/sys/apis/crypto/sha2.lua b/sys/apis/crypto/sha2.lua index 162f5cb..a4f29f3 100644 --- a/sys/apis/crypto/sha2.lua +++ b/sys/apis/crypto/sha2.lua @@ -1,7 +1,9 @@ -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft -- By Anavrins -local mod32 = 2^32 +local bit = _G.bit +local os = _G.os +local mod32 = 2^32 local band = bit32 and bit32.band or bit.band local bnot = bit32 and bit32.bnot or bit.bnot local bxor = bit32 and bit32.bxor or bit.bxor @@ -38,7 +40,7 @@ local function counter(incr) local t1, t2 = 0, 0 if 0xFFFFFFFF - t1 < incr then t2 = t2 + 1 - t1 = incr - (0xFFFFFFFF - t1) - 1 + t1 = incr - (0xFFFFFFFF - t1) - 1 else t1 = t1 + incr end return t2, t1 @@ -66,7 +68,7 @@ end local function digestblock(w, C) for j = 17, 64 do - local v = w[j-15] + -- local v = w[j-15] local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3)) local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10)) w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32 @@ -95,7 +97,7 @@ end local mt = { __tostring = function(a) return string.char(unpack(a)) end, __index = { - toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end, + toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end, isEqual = function(self, t) if type(t) ~= "table" then return false end if #self ~= #t then return false end @@ -120,7 +122,7 @@ local function toBytes(t, n) end local function digest(data) - local data = data or "" + data = data or "" data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} data = preprocess(data) @@ -130,8 +132,8 @@ local function digest(data) end local function hmac(data, key) - local data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} - local key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)} + data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)} + key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)} local blocksize = 64 @@ -161,9 +163,9 @@ local function hmac(data, key) end local function pbkdf2(pass, salt, iter, dklen) - local salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} + salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} local hashlen = 32 - local dklen = dklen or 32 + dklen = dklen or 32 local block = 1 local out = {} @@ -190,8 +192,13 @@ local function pbkdf2(pass, salt, iter, dklen) return setmetatable(out, mt) end +local function compute(data) + return digest(data):toHex() +end + return { digest = digest, + compute = compute, hmac = hmac, pbkdf2 = pbkdf2, } diff --git a/sys/apis/sha1.lua b/sys/apis/sha1.lua deleted file mode 100644 index 0be5024..0000000 --- a/sys/apis/sha1.lua +++ /dev/null @@ -1,280 +0,0 @@ -local sha1 = { - _VERSION = "sha.lua 0.5.0", - _URL = "https://github.com/kikito/sha.lua", - _DESCRIPTION = [[ - SHA-1 secure hash computation, and HMAC-SHA1 signature computation in Lua (5.1) - Based on code originally by Jeffrey Friedl (http://regex.info/blog/lua/sha1) - And modified by Eike Decker - (http://cube3d.de/uploads/Main/sha1.txt) - ]], - _LICENSE = [[ - MIT LICENSE - - Copyright (c) 2013 Enrique Garcia Cota + Eike Decker + Jeffrey Friedl - - https://opensource.org/licenses/MIT - ]] -} - ------------------------------------------------------------------------------------ - --- loading this file (takes a while but grants a boost of factor 13) -local PRELOAD_CACHE = false - -local BLOCK_SIZE = 64 -- 512 bits - --- local storing of global functions (minor speedup) -local floor,modf = math.floor,math.modf -local char,format,rep = string.char,string.format,string.rep - --- merge 4 bytes to an 32 bit word -local function bytes_to_w32(a,b,c,d) return a*0x1000000+b*0x10000+c*0x100+d end --- split a 32 bit word into four 8 bit numbers -local function w32_to_bytes(i) - return floor(i/0x1000000)%0x100,floor(i/0x10000)%0x100,floor(i/0x100)%0x100,i%0x100 -end - --- shift the bits of a 32 bit word. Don't use negative values for "bits" -local function w32_rot(bits,a) - local b2 = 2^(32-bits) - local a,b = modf(a/b2) - return a+b*b2*(2^(bits)) -end - --- caching function for functions that accept 2 arguments, both of values between --- 0 and 255. The function to be cached is passed, all values are calculated --- during loading and a function is returned that returns the cached values (only) -local function cache2arg(fn) - if not PRELOAD_CACHE then return fn end - local lut = {} - for i=0,0xffff do - local a,b = floor(i/0x100),i%0x100 - lut[i] = fn(a,b) - end - return function(a,b) - return lut[a*0x100+b] - end -end - --- splits an 8-bit number into 8 bits, returning all 8 bits as booleans -local function byte_to_bits(b) - local b = function(n) - local b = floor(b/n) - return b%2==1 - end - return b(1),b(2),b(4),b(8),b(16),b(32),b(64),b(128) -end - --- builds an 8bit number from 8 booleans -local function bits_to_byte(a,b,c,d,e,f,g,h) - local function n(b,x) return b and x or 0 end - return n(a,1)+n(b,2)+n(c,4)+n(d,8)+n(e,16)+n(f,32)+n(g,64)+n(h,128) -end - --- bitwise "and" function for 2 8bit number -local band = cache2arg (function(a,b) - local A,B,C,D,E,F,G,H = byte_to_bits(b) - local a,b,c,d,e,f,g,h = byte_to_bits(a) - return bits_to_byte( - A and a, B and b, C and c, D and d, - E and e, F and f, G and g, H and h) -end) - --- bitwise "or" function for 2 8bit numbers -local bor = cache2arg(function(a,b) - local A,B,C,D,E,F,G,H = byte_to_bits(b) - local a,b,c,d,e,f,g,h = byte_to_bits(a) - return bits_to_byte( - A or a, B or b, C or c, D or d, - E or e, F or f, G or g, H or h) -end) - --- bitwise "xor" function for 2 8bit numbers -local bxor = cache2arg(function(a,b) - local A,B,C,D,E,F,G,H = byte_to_bits(b) - local a,b,c,d,e,f,g,h = byte_to_bits(a) - return bits_to_byte( - A ~= a, B ~= b, C ~= c, D ~= d, - E ~= e, F ~= f, G ~= g, H ~= h) -end) - --- bitwise complement for one 8bit number -local function bnot(x) - return 255-(x % 256) -end - --- creates a function to combine to 32bit numbers using an 8bit combination function -local function w32_comb(fn) - return function(a,b) - local aa,ab,ac,ad = w32_to_bytes(a) - local ba,bb,bc,bd = w32_to_bytes(b) - return bytes_to_w32(fn(aa,ba),fn(ab,bb),fn(ac,bc),fn(ad,bd)) - end -end - --- create functions for and, xor and or, all for 2 32bit numbers -local w32_and = w32_comb(band) -local w32_xor = w32_comb(bxor) -local w32_or = w32_comb(bor) - --- xor function that may receive a variable number of arguments -local function w32_xor_n(a,...) - local aa,ab,ac,ad = w32_to_bytes(a) - for i=1,select('#',...) do - local ba,bb,bc,bd = w32_to_bytes(select(i,...)) - aa,ab,ac,ad = bxor(aa,ba),bxor(ab,bb),bxor(ac,bc),bxor(ad,bd) - end - return bytes_to_w32(aa,ab,ac,ad) -end - --- combining 3 32bit numbers through binary "or" operation -local function w32_or3(a,b,c) - local aa,ab,ac,ad = w32_to_bytes(a) - local ba,bb,bc,bd = w32_to_bytes(b) - local ca,cb,cc,cd = w32_to_bytes(c) - return bytes_to_w32( - bor(aa,bor(ba,ca)), bor(ab,bor(bb,cb)), bor(ac,bor(bc,cc)), bor(ad,bor(bd,cd)) - ) -end - --- binary complement for 32bit numbers -local function w32_not(a) - return 4294967295-(a % 4294967296) -end - --- adding 2 32bit numbers, cutting off the remainder on 33th bit -local function w32_add(a,b) return (a+b) % 4294967296 end - --- adding n 32bit numbers, cutting off the remainder (again) -local function w32_add_n(a,...) - for i=1,select('#',...) do - a = (a+select(i,...)) % 4294967296 - end - return a -end --- converting the number to a hexadecimal string -local function w32_to_hexstring(w) return format("%08x",w) end - -local function hex_to_binary(hex) - return hex:gsub('..', function(hexval) - return string.char(tonumber(hexval, 16)) - end) -end - --- building the lookuptables ahead of time (instead of littering the source code --- with precalculated values) -local xor_with_0x5c = {} -local xor_with_0x36 = {} -for i=0,0xff do - xor_with_0x5c[char(i)] = char(bxor(i,0x5c)) - xor_with_0x36[char(i)] = char(bxor(i,0x36)) -end - ------------------------------------------------------------------------------ - --- calculating the SHA1 for some text -function sha1.sha1(msg) - local H0,H1,H2,H3,H4 = 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0 - local msg_len_in_bits = #msg * 8 - - local first_append = char(0x80) -- append a '1' bit plus seven '0' bits - - local non_zero_message_bytes = #msg +1 +8 -- the +1 is the appended bit 1, the +8 are for the final appended length - local current_mod = non_zero_message_bytes % 64 - local second_append = current_mod>0 and rep(char(0), 64 - current_mod) or "" - - -- now to append the length as a 64-bit number. - local B1, R1 = modf(msg_len_in_bits / 0x01000000) - local B2, R2 = modf( 0x01000000 * R1 / 0x00010000) - local B3, R3 = modf( 0x00010000 * R2 / 0x00000100) - local B4 = 0x00000100 * R3 - - local L64 = char( 0) .. char( 0) .. char( 0) .. char( 0) -- high 32 bits - .. char(B1) .. char(B2) .. char(B3) .. char(B4) -- low 32 bits - - msg = msg .. first_append .. second_append .. L64 - - assert(#msg % 64 == 0) - - local chunks = #msg / 64 - - local W = { } - local start, A, B, C, D, E, f, K, TEMP - local chunk = 0 - - while chunk < chunks do - -- - -- break chunk up into W[0] through W[15] - -- - start,chunk = chunk * 64 + 1,chunk + 1 - - for t = 0, 15 do - W[t] = bytes_to_w32(msg:byte(start, start + 3)) - start = start + 4 - end - - -- - -- build W[16] through W[79] - -- - for t = 16, 79 do - -- For t = 16 to 79 let Wt = S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16). - W[t] = w32_rot(1, w32_xor_n(W[t-3], W[t-8], W[t-14], W[t-16])) - end - - A,B,C,D,E = H0,H1,H2,H3,H4 - - for t = 0, 79 do - if t <= 19 then - -- (B AND C) OR ((NOT B) AND D) - f = w32_or(w32_and(B, C), w32_and(w32_not(B), D)) - K = 0x5A827999 - elseif t <= 39 then - -- B XOR C XOR D - f = w32_xor_n(B, C, D) - K = 0x6ED9EBA1 - elseif t <= 59 then - -- (B AND C) OR (B AND D) OR (C AND D - f = w32_or3(w32_and(B, C), w32_and(B, D), w32_and(C, D)) - K = 0x8F1BBCDC - else - -- B XOR C XOR D - f = w32_xor_n(B, C, D) - K = 0xCA62C1D6 - end - - -- TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt; - A,B,C,D,E = w32_add_n(w32_rot(5, A), f, E, W[t], K), - A, w32_rot(30, B), C, D - end - -- Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E. - H0,H1,H2,H3,H4 = w32_add(H0, A),w32_add(H1, B),w32_add(H2, C),w32_add(H3, D),w32_add(H4, E) - end - local f = w32_to_hexstring - return f(H0) .. f(H1) .. f(H2) .. f(H3) .. f(H4) -end - - -function sha1.binary(msg) - return hex_to_binary(sha1.sha1(msg)) -end - -function sha1.hmac(key, text) - assert(type(key) == 'string', "key passed to sha1.hmac should be a string") - assert(type(text) == 'string', "text passed to sha1.hmac should be a string") - - if #key > BLOCK_SIZE then - key = sha1.binary(key) - end - - local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. string.rep(string.char(0x36), BLOCK_SIZE - #key) - local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. string.rep(string.char(0x5c), BLOCK_SIZE - #key) - - return sha1.sha1(key_xord_with_0x5c .. sha1.binary(key_xord_with_0x36 .. text)) -end - -function sha1.hmac_binary(key, text) - return hex_to_binary(sha1.hmac(key, text)) -end - -setmetatable(sha1, {__call = function(_,msg) return sha1.sha1(msg) end }) - -return sha1 \ No newline at end of file diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 1c0fe01..a2692be 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -3,7 +3,7 @@ local Config = require('config') local Event = require('event') local NFT = require('nft') local Packages = require('packages') -local SHA1 = require('sha1') +local SHA = require('crypto.sha2') local Tween = require('ui.tween') local UI = require('ui') local Util = require('util') @@ -502,7 +502,7 @@ end function page.editor:updateApplications(app) if not app.key then - app.key = SHA1.sha1(app.title) + app.key = SHA.compute(app.title) end local filename = app.filename or fs.combine(REGISTRY_DIR, app.key) Util.writeTable(filename, app) @@ -571,7 +571,7 @@ end Event.on('overview_shortcut', function(_, app) if not app.key then - app.key = SHA1.sha1(app.title) + app.key = SHA.compute(app.title) end local filename = app.filename or fs.combine(REGISTRY_DIR, app.key) if not fs.exists(filename) then diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 8a4507b..399d0b2 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -1,6 +1,6 @@ local Ansi = require('ansi') local Security = require('security') -local SHA2 = require('crypto.sha2') +local SHA = require('crypto.sha2') local UI = require('ui') local colors = _G.colors @@ -107,7 +107,7 @@ end function page.wizard.pages.password:validate() if #self.newPass.value > 0 then - Security.updatePassword(SHA2.digest(self.newPass.value):toHex()) + Security.updatePassword(SHA.compute(self.newPass.value)) end --[[ if #self.group.value > 0 then diff --git a/sys/apps/password.lua b/sys/apps/password.lua index 6beb700..be64a0e 100644 --- a/sys/apps/password.lua +++ b/sys/apps/password.lua @@ -1,10 +1,10 @@ local Security = require('security') -local SHA2 = require('crypto.sha2') +local SHA = require('crypto.sha2') local Terminal = require('terminal') local password = Terminal.readPassword('Enter new password: ') if password then - Security.updatePassword(SHA2.digest(password):toHex()) + Security.updatePassword(SHA.compute(password)) print('Password updated') end diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua index 7ad5769..ecb7677 100644 --- a/sys/apps/system/password.lua +++ b/sys/apps/system/password.lua @@ -1,5 +1,5 @@ local Security = require('security') -local SHA2 = require('crypto.sha2') +local SHA = require('crypto.sha2') local UI = require('ui') local colors = _G.colors @@ -40,11 +40,11 @@ function passwordTab:eventHandler(event) if #self.newPass.value == 0 then self:emit({ type = 'error_message', message = 'Invalid password' }) - elseif Security.getPassword() and not Security.verifyPassword(SHA2.digest(self.oldPass.value):toHex()) then + elseif Security.getPassword() and not Security.verifyPassword(SHA.compute(self.oldPass.value)) then self:emit({ type = 'error_message', message = 'Passwords do not match' }) else - Security.updatePassword(SHA2.digest(self.newPass.value):toHex()) + Security.updatePassword(SHA.compute(self.newPass.value)) self.oldPass.inactive = false self:emit({ type = 'success_message', message = 'Password updated' }) end diff --git a/sys/apps/trust.lua b/sys/apps/trust.lua index 90c01d4..dbe0b33 100644 --- a/sys/apps/trust.lua +++ b/sys/apps/trust.lua @@ -1,6 +1,6 @@ local Crypto = require('crypto.chacha20') local Security = require('security') -local SHA2 = require('crypto.sha2') +local SHA = require('crypto.sha2') local Socket = require('socket') local Terminal = require('terminal') @@ -35,7 +35,7 @@ end local publicKey = Security.getPublicKey() -socket:write(Crypto.encrypt({ pk = publicKey, dh = os.getComputerID() }, SHA2.digest(password):toHex())) +socket:write(Crypto.encrypt({ pk = publicKey, dh = os.getComputerID() }, SHA.compute(password))) local data = socket:read(2) socket:close() diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua index e3a7b5a..0ee57d0 100644 --- a/sys/autorun/welcome.lua +++ b/sys/autorun/welcome.lua @@ -2,6 +2,7 @@ local Config = require('config') local Util = require('util') local fs = _G.fs +local os = _G.os local shell = _ENV.shell local config = Config.load('os') From 343ce7fdc2814c9de4786f68ed841b754681e46a Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 28 Jun 2019 13:50:02 -0400 Subject: [PATCH 156/231] move apis into rom/modules/main for shell compatibility --- sys/apps/Files.lua | 10 +++++----- sys/apps/Help.lua | 4 ++-- sys/apps/Lua.lua | 6 +++--- sys/apps/Network.lua | 10 +++++----- sys/apps/Overview.lua | 18 +++++++++--------- sys/apps/PackageManager.lua | 8 ++++---- sys/apps/System.lua | 4 ++-- sys/apps/Tasks.lua | 4 ++-- sys/apps/Welcome.lua | 8 ++++---- sys/apps/autorun.lua | 2 +- sys/apps/cedit.lua | 2 +- sys/apps/cshell.lua | 2 +- sys/apps/netdaemon.lua | 4 ++-- sys/apps/network/proxy.lua | 6 +++--- sys/apps/network/samba.lua | 4 ++-- sys/apps/network/snmp.lua | 8 ++++---- sys/apps/network/telnet.lua | 6 +++--- sys/apps/network/transport.lua | 2 +- sys/apps/network/trust.lua | 10 +++++----- sys/apps/network/vnc.lua | 6 +++--- sys/apps/package.lua | 8 ++++---- sys/apps/password.lua | 6 +++--- sys/apps/pastebin.lua | 2 +- sys/apps/shell.lua | 16 ++++++++-------- sys/apps/system/aliases.lua | 4 ++-- sys/apps/system/cloud.lua | 6 +++--- sys/apps/system/kiosk.lua | 2 +- sys/apps/system/label.lua | 4 ++-- sys/apps/system/launcher.lua | 4 ++-- sys/apps/system/network.lua | 6 +++--- sys/apps/system/password.lua | 6 +++--- sys/apps/system/path.lua | 6 +++--- sys/apps/system/requires.lua | 6 +++--- sys/apps/system/settings.lua | 2 +- sys/apps/system/shell.lua | 6 +++--- sys/apps/telnet.lua | 8 ++++---- sys/apps/trust.lua | 10 +++++----- sys/apps/vnc.lua | 8 ++++---- sys/autorun/clipboard.lua | 2 +- sys/autorun/hotkeys.lua | 2 +- sys/autorun/welcome.lua | 4 ++-- sys/boot/opus.boot | 10 +++++----- sys/init/1.device.lua | 6 +++--- sys/init/2.vfs.lua | 4 ++-- sys/init/3.modules.lua | 2 +- sys/init/4.user.lua | 6 +++--- sys/init/5.network.lua | 2 +- sys/init/6.packages.lua | 8 +++++--- sys/init/6.tl3.lua | 8 ++++---- sys/init/7.multishell.lua | 6 +++--- sys/kernel.lua | 4 ++-- sys/{apis => modules/opus}/ansi.lua | 0 sys/{apis => modules/opus}/array.lua | 0 sys/{apis => modules/opus}/bulkget.lua | 2 +- sys/{apis => modules/opus}/class.lua | 0 sys/{apis => modules/opus}/config.lua | 2 +- sys/{apis => modules/opus}/crypto/chacha20.lua | 4 ++-- .../opus}/crypto/ecc/elliptic.lua | 2 +- sys/{apis => modules/opus}/crypto/ecc/fp.lua | 0 sys/{apis => modules/opus}/crypto/ecc/fq.lua | 0 sys/{apis => modules/opus}/crypto/ecc/init.lua | 6 +++--- sys/{apis => modules/opus}/crypto/sha2.lua | 0 sys/{apis => modules/opus}/entry.lua | 2 +- sys/{apis => modules/opus}/event.lua | 0 sys/{apis => modules/opus}/fs/gitfs.lua | 2 +- sys/{apis => modules/opus}/fs/linkfs.lua | 0 sys/{apis => modules/opus}/fs/netfs.lua | 4 ++-- sys/{apis => modules/opus}/fs/ramfs.lua | 2 +- sys/{apis => modules/opus}/fs/urlfs.lua | 2 +- sys/{apis => modules/opus}/git.lua | 4 ++-- sys/{apis => modules/opus}/gps.lua | 0 sys/{apis => modules/opus}/history.lua | 2 +- sys/{apis => modules/opus}/http/pastebin.lua | 0 sys/{apis => modules/opus}/injector.lua | 14 ++++++++++---- sys/{apis => modules/opus}/input.lua | 4 ++-- sys/{apis => modules/opus}/json.lua | 0 .../opus}/jumper/core/bheap.lua | 0 .../opus}/jumper/core/node.lua | 0 .../opus}/jumper/core/path.lua | 0 .../opus}/jumper/core/utils.lua | 0 sys/{apis => modules/opus}/jumper/grid.lua | 0 .../opus}/jumper/pathfinder.lua | 0 .../opus}/jumper/search/astar.lua | 0 sys/{apis => modules/opus}/map.lua | 2 +- sys/{apis => modules/opus}/nft.lua | 2 +- sys/{apis => modules/opus}/packages.lua | 2 +- sys/{apis => modules/opus}/pathfind.lua | 8 ++++---- sys/{apis => modules/opus}/peripheral.lua | 4 ++-- sys/{apis => modules/opus}/point.lua | 2 +- sys/{apis => modules/opus}/security.lua | 6 +++--- sys/{apis => modules/opus}/socket.lua | 6 +++--- sys/{apis => modules/opus}/sound.lua | 0 sys/{apis => modules/opus}/sync.lua | 0 sys/{apis => modules/opus}/terminal.lua | 2 +- sys/{apis => modules/opus}/trace.lua | 0 sys/{apis => modules/opus}/ui.lua | 16 ++++++++-------- sys/{apis => modules/opus}/ui/canvas.lua | 6 +++--- .../opus}/ui/components/ActiveLayer.lua | 4 ++-- .../opus}/ui/components/Button.lua | 6 +++--- .../opus}/ui/components/Checkbox.lua | 4 ++-- .../opus}/ui/components/Chooser.lua | 6 +++--- .../opus}/ui/components/Dialog.lua | 8 ++++---- .../opus}/ui/components/DropMenu.lua | 6 +++--- .../opus}/ui/components/DropMenuItem.lua | 4 ++-- .../opus}/ui/components/Embedded.lua | 6 +++--- .../opus}/ui/components/Form.lua | 6 +++--- .../opus}/ui/components/Grid.lua | 6 +++--- .../opus}/ui/components/Image.lua | 4 ++-- .../opus}/ui/components/Menu.lua | 4 ++-- .../opus}/ui/components/MenuBar.lua | 4 ++-- .../opus}/ui/components/MenuItem.lua | 4 ++-- .../opus}/ui/components/NftImage.lua | 4 ++-- .../opus}/ui/components/Notification.lua | 10 +++++----- .../opus}/ui/components/ProgressBar.lua | 4 ++-- .../opus}/ui/components/ScrollBar.lua | 6 +++--- .../opus}/ui/components/ScrollingGrid.lua | 6 +++--- .../opus}/ui/components/SlideOut.lua | 4 ++-- .../opus}/ui/components/StatusBar.lua | 8 ++++---- .../opus}/ui/components/Tab.lua | 4 ++-- .../opus}/ui/components/TabBar.lua | 6 +++--- .../opus}/ui/components/TabBarMenuItem.lua | 4 ++-- .../opus}/ui/components/Tabs.lua | 6 +++--- .../opus}/ui/components/Text.lua | 6 +++--- .../opus}/ui/components/TextArea.lua | 4 ++-- .../opus}/ui/components/TextEntry.lua | 8 ++++---- .../opus}/ui/components/Throttle.lua | 4 ++-- .../opus}/ui/components/TitleBar.lua | 4 ++-- .../opus}/ui/components/VerticalMeter.lua | 4 ++-- .../opus}/ui/components/Viewport.lua | 4 ++-- .../opus}/ui/components/Wizard.lua | 6 +++--- .../opus}/ui/components/WizardPage.lua | 4 ++-- sys/{apis => modules/opus}/ui/region.lua | 0 sys/{apis => modules/opus}/ui/transition.lua | 2 +- sys/{apis => modules/opus}/ui/tween.lua | 0 sys/{apis => modules/opus}/util.lua | 0 135 files changed, 297 insertions(+), 289 deletions(-) rename sys/{apis => modules/opus}/ansi.lua (100%) rename sys/{apis => modules/opus}/array.lua (100%) rename sys/{apis => modules/opus}/bulkget.lua (93%) rename sys/{apis => modules/opus}/class.lua (100%) rename sys/{apis => modules/opus}/config.lua (96%) rename sys/{apis => modules/opus}/crypto/chacha20.lua (98%) rename sys/{apis => modules/opus}/crypto/ecc/elliptic.lua (99%) rename sys/{apis => modules/opus}/crypto/ecc/fp.lua (100%) rename sys/{apis => modules/opus}/crypto/ecc/fq.lua (100%) rename sys/{apis => modules/opus}/crypto/ecc/init.lua (92%) rename sys/{apis => modules/opus}/crypto/sha2.lua (100%) rename sys/{apis => modules/opus}/entry.lua (99%) rename sys/{apis => modules/opus}/event.lua (100%) rename sys/{apis => modules/opus}/fs/gitfs.lua (91%) rename sys/{apis => modules/opus}/fs/linkfs.lua (100%) rename sys/{apis => modules/opus}/fs/netfs.lua (97%) rename sys/{apis => modules/opus}/fs/ramfs.lua (98%) rename sys/{apis => modules/opus}/fs/urlfs.lua (97%) rename sys/{apis => modules/opus}/git.lua (95%) rename sys/{apis => modules/opus}/gps.lua (100%) rename sys/{apis => modules/opus}/history.lua (96%) rename sys/{apis => modules/opus}/http/pastebin.lua (100%) rename sys/{apis => modules/opus}/injector.lua (91%) rename sys/{apis => modules/opus}/input.lua (98%) rename sys/{apis => modules/opus}/json.lua (100%) rename sys/{apis => modules/opus}/jumper/core/bheap.lua (100%) rename sys/{apis => modules/opus}/jumper/core/node.lua (100%) rename sys/{apis => modules/opus}/jumper/core/path.lua (100%) rename sys/{apis => modules/opus}/jumper/core/utils.lua (100%) rename sys/{apis => modules/opus}/jumper/grid.lua (100%) rename sys/{apis => modules/opus}/jumper/pathfinder.lua (100%) rename sys/{apis => modules/opus}/jumper/search/astar.lua (100%) rename sys/{apis => modules/opus}/map.lua (96%) rename sys/{apis => modules/opus}/nft.lua (98%) rename sys/{apis => modules/opus}/packages.lua (97%) rename sys/{apis => modules/opus}/pathfind.lua (97%) rename sys/{apis => modules/opus}/peripheral.lua (97%) rename sys/{apis => modules/opus}/point.lua (99%) rename sys/{apis => modules/opus}/security.lua (88%) rename sys/{apis => modules/opus}/socket.lua (97%) rename sys/{apis => modules/opus}/sound.lua (100%) rename sys/{apis => modules/opus}/sync.lua (100%) rename sys/{apis => modules/opus}/terminal.lua (99%) rename sys/{apis => modules/opus}/trace.lua (100%) rename sys/{apis => modules/opus}/ui.lua (98%) rename sys/{apis => modules/opus}/ui/canvas.lua (98%) rename sys/{apis => modules/opus}/ui/components/ActiveLayer.lua (89%) rename sys/{apis => modules/opus}/ui/components/Button.lua (92%) rename sys/{apis => modules/opus}/ui/components/Checkbox.lua (95%) rename sys/{apis => modules/opus}/ui/components/Chooser.lua (95%) rename sys/{apis => modules/opus}/ui/components/Dialog.lua (87%) rename sys/{apis => modules/opus}/ui/components/DropMenu.lua (93%) rename sys/{apis => modules/opus}/ui/components/DropMenuItem.lua (87%) rename sys/{apis => modules/opus}/ui/components/Embedded.lua (93%) rename sys/{apis => modules/opus}/ui/components/Form.lua (96%) rename sys/{apis => modules/opus}/ui/components/Grid.lua (99%) rename sys/{apis => modules/opus}/ui/components/Image.lua (90%) rename sys/{apis => modules/opus}/ui/components/Menu.lua (94%) rename sys/{apis => modules/opus}/ui/components/MenuBar.lua (96%) rename sys/{apis => modules/opus}/ui/components/MenuItem.lua (79%) rename sys/{apis => modules/opus}/ui/components/NftImage.lua (89%) rename sys/{apis => modules/opus}/ui/components/Notification.lua (91%) rename sys/{apis => modules/opus}/ui/components/ProgressBar.lua (84%) rename sys/{apis => modules/opus}/ui/components/ScrollBar.lua (95%) rename sys/{apis => modules/opus}/ui/components/ScrollingGrid.lua (93%) rename sys/{apis => modules/opus}/ui/components/SlideOut.lua (92%) rename sys/{apis => modules/opus}/ui/components/StatusBar.lua (93%) rename sys/{apis => modules/opus}/ui/components/Tab.lua (69%) rename sys/{apis => modules/opus}/ui/components/TabBar.lua (90%) rename sys/{apis => modules/opus}/ui/components/TabBarMenuItem.lua (90%) rename sys/{apis => modules/opus}/ui/components/Tabs.lua (94%) rename sys/{apis => modules/opus}/ui/components/Text.lua (76%) rename sys/{apis => modules/opus}/ui/components/TextArea.lua (89%) rename sys/{apis => modules/opus}/ui/components/TextEntry.lua (94%) rename sys/{apis => modules/opus}/ui/components/Throttle.lua (95%) rename sys/{apis => modules/opus}/ui/components/TitleBar.lua (96%) rename sys/{apis => modules/opus}/ui/components/VerticalMeter.lua (85%) rename sys/{apis => modules/opus}/ui/components/Viewport.lua (97%) rename sys/{apis => modules/opus}/ui/components/Wizard.lua (96%) rename sys/{apis => modules/opus}/ui/components/WizardPage.lua (70%) rename sys/{apis => modules/opus}/ui/region.lua (100%) rename sys/{apis => modules/opus}/ui/transition.lua (96%) rename sys/{apis => modules/opus}/ui/tween.lua (100%) rename sys/{apis => modules/opus}/util.lua (100%) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index ea3126d..6c6b453 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -1,8 +1,8 @@ -local Config = require('config') -local Event = require('event') -local pastebin = require('http.pastebin') -local UI = require('ui') -local Util = require('util') +local Config = require('opus.config') +local Event = require('opus.event') +local pastebin = require('opus.http.pastebin') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local fs = _G.fs diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index d00c80b..b6e862c 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -1,5 +1,5 @@ -local UI = require('ui') -local Util = require('util') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local help = _G.help diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index bfc080b..a7442be 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -1,9 +1,9 @@ -- Lua may be called from outside of shell - inject a require _G.requireInjector(_ENV) -local History = require('history') -local UI = require('ui') -local Util = require('util') +local History = require('opus.history') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local os = _G.os diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index e6341eb..f9f4cc1 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -1,8 +1,8 @@ -local Config = require('config') -local Event = require('event') -local Socket = require('socket') -local UI = require('ui') -local Util = require('util') +local Config = require('opus.config') +local Event = require('opus.event') +local Socket = require('opus.socket') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local device = _G.device diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index a2692be..bfcbbb3 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -1,12 +1,12 @@ -local class = require('class') -local Config = require('config') -local Event = require('event') -local NFT = require('nft') -local Packages = require('packages') -local SHA = require('crypto.sha2') -local Tween = require('ui.tween') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local Config = require('opus.config') +local Event = require('opus.event') +local NFT = require('opus.nft') +local Packages = require('opus.packages') +local SHA = require('opus.crypto.sha2') +local Tween = require('opus.ui.tween') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local device = _G.device diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index 6ed2d41..de8af57 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -1,7 +1,7 @@ -local Ansi = require('ansi') -local Packages = require('packages') -local UI = require('ui') -local Util = require('util') +local Ansi = require('opus.ansi') +local Packages = require('opus.packages') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local term = _G.term diff --git a/sys/apps/System.lua b/sys/apps/System.lua index 5b1595a..b97d2e9 100644 --- a/sys/apps/System.lua +++ b/sys/apps/System.lua @@ -1,5 +1,5 @@ -local UI = require('ui') -local Util = require('util') +local UI = require('opus.ui') +local Util = require('opus.util') local fs = _G.fs local shell = _ENV.shell diff --git a/sys/apps/Tasks.lua b/sys/apps/Tasks.lua index 9b35be2..73ff93b 100644 --- a/sys/apps/Tasks.lua +++ b/sys/apps/Tasks.lua @@ -1,5 +1,5 @@ -local Event = require('event') -local UI = require('ui') +local Event = require('opus.event') +local UI = require('opus.ui') local kernel = _G.kernel local multishell = _ENV.multishell diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 399d0b2..76c4c7f 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -1,7 +1,7 @@ -local Ansi = require('ansi') -local Security = require('security') -local SHA = require('crypto.sha2') -local UI = require('ui') +local Ansi = require('opus.ansi') +local Security = require('opus.security') +local SHA = require('opus.crypto.sha2') +local UI = require('opus.ui') local colors = _G.colors local os = _G.os diff --git a/sys/apps/autorun.lua b/sys/apps/autorun.lua index 1d650da..e8b378f 100644 --- a/sys/apps/autorun.lua +++ b/sys/apps/autorun.lua @@ -1,4 +1,4 @@ -local Packages = require('packages') +local Packages = require('opus.packages') local colors = _G.colors local fs = _G.fs diff --git a/sys/apps/cedit.lua b/sys/apps/cedit.lua index 138f977..2231e73 100644 --- a/sys/apps/cedit.lua +++ b/sys/apps/cedit.lua @@ -1,4 +1,4 @@ -local Config = require('config') +local Config = require('opus.config') local multishell = _ENV.multishell local os = _G.os diff --git a/sys/apps/cshell.lua b/sys/apps/cshell.lua index 34e5c91..9a0e1af 100644 --- a/sys/apps/cshell.lua +++ b/sys/apps/cshell.lua @@ -1,4 +1,4 @@ -local Config = require('config') +local Config = require('opus.config') local read = _G.read local shell = _ENV.shell diff --git a/sys/apps/netdaemon.lua b/sys/apps/netdaemon.lua index cc14a7b..fb9e23e 100644 --- a/sys/apps/netdaemon.lua +++ b/sys/apps/netdaemon.lua @@ -1,7 +1,7 @@ _G.requireInjector(_ENV) -local Event = require('event') -local Util = require('util') +local Event = require('opus.event') +local Util = require('opus.util') local device = _G.device local fs = _G.fs diff --git a/sys/apps/network/proxy.lua b/sys/apps/network/proxy.lua index a90dcef..9e487b0 100644 --- a/sys/apps/network/proxy.lua +++ b/sys/apps/network/proxy.lua @@ -1,6 +1,6 @@ -local Event = require('event') -local Socket = require('socket') -local Util = require('util') +local Event = require('opus.event') +local Socket = require('opus.socket') +local Util = require('opus.util') local function getProxy(path) local x = Util.split(path, '(.-)/') diff --git a/sys/apps/network/samba.lua b/sys/apps/network/samba.lua index a1d5227..f679b4d 100644 --- a/sys/apps/network/samba.lua +++ b/sys/apps/network/samba.lua @@ -1,5 +1,5 @@ -local Event = require('event') -local Socket = require('socket') +local Event = require('opus.event') +local Socket = require('opus.socket') local fs = _G.fs diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index 11ed673..ff42b99 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -1,7 +1,7 @@ -local Event = require('event') -local GPS = require('gps') -local Socket = require('socket') -local Util = require('util') +local Event = require('opus.event') +local GPS = require('opus.gps') +local Socket = require('opus.socket') +local Util = require('opus.util') local device = _G.device local kernel = _G.kernel diff --git a/sys/apps/network/telnet.lua b/sys/apps/network/telnet.lua index a396570..dc2bda0 100644 --- a/sys/apps/network/telnet.lua +++ b/sys/apps/network/telnet.lua @@ -1,6 +1,6 @@ -local Event = require('event') -local Socket = require('socket') -local Util = require('util') +local Event = require('opus.event') +local Socket = require('opus.socket') +local Util = require('opus.util') local kernel = _G.kernel local term = _G.term diff --git a/sys/apps/network/transport.lua b/sys/apps/network/transport.lua index eccd9ef..fa1978c 100644 --- a/sys/apps/network/transport.lua +++ b/sys/apps/network/transport.lua @@ -5,7 +5,7 @@ * background read buffering ]]-- -local Event = require('event') +local Event = require('opus.event') local os = _G.os diff --git a/sys/apps/network/trust.lua b/sys/apps/network/trust.lua index b2e493f..b31acbc 100644 --- a/sys/apps/network/trust.lua +++ b/sys/apps/network/trust.lua @@ -1,8 +1,8 @@ -local Crypto = require('crypto.chacha20') -local Event = require('event') -local Security = require('security') -local Socket = require('socket') -local Util = require('util') +local Crypto = require('opus.crypto.chacha20') +local Event = require('opus.event') +local Security = require('opus.security') +local Socket = require('opus.socket') +local Util = require('opus.util') local function trustConnection(socket) local data = socket:read(2) diff --git a/sys/apps/network/vnc.lua b/sys/apps/network/vnc.lua index 779a75d..54ea8fc 100644 --- a/sys/apps/network/vnc.lua +++ b/sys/apps/network/vnc.lua @@ -1,6 +1,6 @@ -local Event = require('event') -local Socket = require('socket') -local Util = require('util') +local Event = require('opus.event') +local Socket = require('opus.socket') +local Util = require('opus.util') local os = _G.os local terminal = _G.device.terminal diff --git a/sys/apps/package.lua b/sys/apps/package.lua index d1e2071..864f4fd 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -1,7 +1,7 @@ -local BulkGet = require('bulkget') -local Git = require('git') -local Packages = require('packages') -local Util = require('util') +local BulkGet = require('opus.bulkget') +local Git = require('opus.git') +local Packages = require('opus.packages') +local Util = require('opus.util') local fs = _G.fs local term = _G.term diff --git a/sys/apps/password.lua b/sys/apps/password.lua index be64a0e..e1585b0 100644 --- a/sys/apps/password.lua +++ b/sys/apps/password.lua @@ -1,6 +1,6 @@ -local Security = require('security') -local SHA = require('crypto.sha2') -local Terminal = require('terminal') +local Security = require('opus.security') +local SHA = require('opus.crypto.sha2') +local Terminal = require('opus.terminal') local password = Terminal.readPassword('Enter new password: ') diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua index 4cdc80b..aaade9a 100644 --- a/sys/apps/pastebin.lua +++ b/sys/apps/pastebin.lua @@ -11,7 +11,7 @@ if not http then return end -local pastebin = require('http.pastebin') +local pastebin = require('opus.http.pastebin') local tArgs = { ... } local sCommand = tArgs[1] diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index a32676a..5d7f067 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -13,8 +13,8 @@ sandboxEnv.shell = shell _G.requireInjector(_ENV) -local trace = require('trace') -local Util = require('util') +local trace = require('opus.trace') +local Util = require('opus.util') local DIR = (parentShell and parentShell.dir()) or "" local PATH = (parentShell and parentShell.path()) or ".:/rom/programs" @@ -358,12 +358,12 @@ if #tArgs > 0 then return run(env, ...) end -local Config = require('config') -local Entry = require('entry') -local History = require('history') -local Input = require('input') -local Sound = require('sound') -local Terminal = require('terminal') +local Config = require('opus.config') +local Entry = require('opus.entry') +local History = require('opus.history') +local Input = require('opus.input') +local Sound = require('opus.sound') +local Terminal = require('opus.terminal') local colors = _G.colors local os = _G.os diff --git a/sys/apps/system/aliases.lua b/sys/apps/system/aliases.lua index 3a98bc6..6b04c5c 100644 --- a/sys/apps/system/aliases.lua +++ b/sys/apps/system/aliases.lua @@ -1,5 +1,5 @@ -local Config = require('config') -local UI = require('ui') +local Config = require('opus.config') +local UI = require('opus.ui') local kernel = _G.kernel diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua index 61d47f9..e40d924 100644 --- a/sys/apps/system/cloud.lua +++ b/sys/apps/system/cloud.lua @@ -1,6 +1,6 @@ -local Ansi = require('ansi') -local Config = require('config') -local UI = require('ui') +local Ansi = require('opus.ansi') +local Config = require('opus.config') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apps/system/kiosk.lua b/sys/apps/system/kiosk.lua index 1adb110..becee72 100644 --- a/sys/apps/system/kiosk.lua +++ b/sys/apps/system/kiosk.lua @@ -1,4 +1,4 @@ -local UI = require('ui') +local UI = require('opus.ui') local colors = _G.colors local peripheral = _G.peripheral diff --git a/sys/apps/system/label.lua b/sys/apps/system/label.lua index 7ed6f6f..e4a73f2 100644 --- a/sys/apps/system/label.lua +++ b/sys/apps/system/label.lua @@ -1,5 +1,5 @@ -local UI = require('ui') -local Util = require('util') +local UI = require('opus.ui') +local Util = require('opus.util') local fs = _G.fs local os = _G.os diff --git a/sys/apps/system/launcher.lua b/sys/apps/system/launcher.lua index cebd5b7..6bd290c 100644 --- a/sys/apps/system/launcher.lua +++ b/sys/apps/system/launcher.lua @@ -1,5 +1,5 @@ -local Config = require('config') -local UI = require('ui') +local Config = require('opus.config') +local UI = require('opus.ui') local colors = _G.colors local fs = _G.fs diff --git a/sys/apps/system/network.lua b/sys/apps/system/network.lua index 11f3c00..414c080 100644 --- a/sys/apps/system/network.lua +++ b/sys/apps/system/network.lua @@ -1,6 +1,6 @@ -local Ansi = require('ansi') -local Config = require('config') -local UI = require('ui') +local Ansi = require('opus.ansi') +local Config = require('opus.config') +local UI = require('opus.ui') local device = _G.device diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua index ecb7677..4340a73 100644 --- a/sys/apps/system/password.lua +++ b/sys/apps/system/password.lua @@ -1,6 +1,6 @@ -local Security = require('security') -local SHA = require('crypto.sha2') -local UI = require('ui') +local Security = require('opus.security') +local SHA = require('opus.crypto.sha2') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apps/system/path.lua b/sys/apps/system/path.lua index 803ed51..bf30f7e 100644 --- a/sys/apps/system/path.lua +++ b/sys/apps/system/path.lua @@ -1,6 +1,6 @@ -local Config = require('config') -local UI = require('ui') -local Util = require('util') +local Config = require('opus.config') +local UI = require('opus.ui') +local Util = require('opus.util') local tab = UI.Tab { tabTitle = 'Path', diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua index b98d93b..38acef9 100644 --- a/sys/apps/system/requires.lua +++ b/sys/apps/system/requires.lua @@ -1,6 +1,6 @@ -local Config = require('config') -local UI = require('ui') -local Util = require('util') +local Config = require('opus.config') +local UI = require('opus.ui') +local Util = require('opus.util') local tab = UI.Tab { tabTitle = 'Requires', diff --git a/sys/apps/system/settings.lua b/sys/apps/system/settings.lua index f5d35db..8e071ac 100644 --- a/sys/apps/system/settings.lua +++ b/sys/apps/system/settings.lua @@ -1,4 +1,4 @@ -local UI = require('ui') +local UI = require('opus.ui') local settings = _G.settings diff --git a/sys/apps/system/shell.lua b/sys/apps/system/shell.lua index 238a8d9..13dfda6 100644 --- a/sys/apps/system/shell.lua +++ b/sys/apps/system/shell.lua @@ -1,6 +1,6 @@ -local Config = require('config') -local UI = require('ui') -local Util = require('util') +local Config = require('opus.config') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local os = _G.os diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 40a1134..91b163e 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -1,7 +1,7 @@ -local Event = require('event') -local Socket = require('socket') -local Terminal = require('terminal') -local Util = require('util') +local Event = require('opus.event') +local Socket = require('opus.socket') +local Terminal = require('opus.terminal') +local Util = require('opus.util') local multishell = _ENV.multishell local os = _G.os diff --git a/sys/apps/trust.lua b/sys/apps/trust.lua index dbe0b33..b1283f8 100644 --- a/sys/apps/trust.lua +++ b/sys/apps/trust.lua @@ -1,8 +1,8 @@ -local Crypto = require('crypto.chacha20') -local Security = require('security') -local SHA = require('crypto.sha2') -local Socket = require('socket') -local Terminal = require('terminal') +local Crypto = require('opus.crypto.chacha20') +local Security = require('opus.security') +local SHA = require('opus.crypto.sha2') +local Socket = require('opus.socket') +local Terminal = require('opus.terminal') local os = _G.os diff --git a/sys/apps/vnc.lua b/sys/apps/vnc.lua index b57df3b..cb2d945 100644 --- a/sys/apps/vnc.lua +++ b/sys/apps/vnc.lua @@ -1,7 +1,7 @@ -local Event = require('event') -local Socket = require('socket') -local Terminal = require('terminal') -local Util = require('util') +local Event = require('opus.event') +local Socket = require('opus.socket') +local Terminal = require('opus.terminal') +local Util = require('opus.util') local colors = _G.colors local multishell = _ENV.multishell diff --git a/sys/autorun/clipboard.lua b/sys/autorun/clipboard.lua index ad3286f..72c9434 100644 --- a/sys/autorun/clipboard.lua +++ b/sys/autorun/clipboard.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local kernel = _G.kernel local keyboard = _G.device.keyboard diff --git a/sys/autorun/hotkeys.lua b/sys/autorun/hotkeys.lua index cf50efb..5c6b539 100644 --- a/sys/autorun/hotkeys.lua +++ b/sys/autorun/hotkeys.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local kernel = _G.kernel local keyboard = _G.device.keyboard diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua index 0ee57d0..b8d113b 100644 --- a/sys/autorun/welcome.lua +++ b/sys/autorun/welcome.lua @@ -1,5 +1,5 @@ -local Config = require('config') -local Util = require('util') +local Config = require('opus.config') +local Util = require('opus.util') local fs = _G.fs local os = _G.os diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index d139e37..f3b5ffb 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -44,19 +44,19 @@ local function runUrl(file, ...) end -- Install require shim -if fs.exists('sys/apis/injector.lua') then - _G.requireInjector = run('sys/apis/injector.lua') +if fs.exists('sys/modules/opus/injector.lua') then + _G.requireInjector = run('sys/modules/opus/injector.lua') else -- not local, run the file system directly from git if package and package.path then - package.path = package.path .. ';' .. BASE .. '/sys/apis' + package.path = package.path .. ';' .. BASE .. '/sys/modules/opus' else sandboxEnv.package = { - path = BASE .. '/sys/apis' + path = BASE .. '/sys/modules/opus' } end - _G.requireInjector = runUrl('sys/apis/injector.lua') + _G.requireInjector = runUrl('sys/modules/opus/injector.lua') runUrl('sys/init/2.vfs.lua') diff --git a/sys/init/1.device.lua b/sys/init/1.device.lua index 803898d..65b1e76 100644 --- a/sys/init/1.device.lua +++ b/sys/init/1.device.lua @@ -1,6 +1,6 @@ _G.requireInjector(_ENV) -local Peripheral = require('peripheral') +local Peripheral = require('opus.peripheral') _G.device = Peripheral.getList() @@ -24,8 +24,8 @@ _G.device.mouse = { state = { }, } -local Input = require('input') -local Util = require('util') +local Input = require('opus.input') +local Util = require('opus.util') local device = _G.device local kernel = _G.kernel diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index b32f6b4..0ddc672 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -3,7 +3,7 @@ if fs.native then end _G.requireInjector(_ENV) -local Util = require('util') +local Util = require('opus.util') -- TODO: support getDrive for virtual nodes @@ -256,7 +256,7 @@ end local function getfstype(fstype) local vfs = fstypes[fstype] if not vfs then - vfs = require('fs.' .. fstype) + vfs = require('opus.fs.' .. fstype) fs.registerType(fstype, vfs) end return vfs diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index 91a7159..8dd5fcb 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local device = _G.device local kernel = _G.kernel diff --git a/sys/init/4.user.lua b/sys/init/4.user.lua index e795997..0349808 100644 --- a/sys/init/4.user.lua +++ b/sys/init/4.user.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local fs = _G.fs local shell = _ENV.shell @@ -43,7 +43,7 @@ end shell.setPath(table.concat(path, ':')) -_G.LUA_PATH = config.lua_path -_G.settings.set('mbs.shell.require_path', config.lua_path) +--_G.LUA_PATH = config.lua_path +--_G.settings.set('mbs.shell.require_path', config.lua_path) fs.loadTab('usr/config/fstab') diff --git a/sys/init/5.network.lua b/sys/init/5.network.lua index bd97122..6526c5f 100644 --- a/sys/init/5.network.lua +++ b/sys/init/5.network.lua @@ -1,6 +1,6 @@ _G.requireInjector(_ENV) -local Config = require('config') +local Config = require('opus.config') local device = _G.device local kernel = _G.kernel diff --git a/sys/init/6.packages.lua b/sys/init/6.packages.lua index ba52af1..ad667cd 100644 --- a/sys/init/6.packages.lua +++ b/sys/init/6.packages.lua @@ -1,5 +1,5 @@ -local Packages = require('packages') -local Util = require('util') +local Packages = require('opus.packages') +local Util = require('opus.util') local fs = _G.fs local help = _G.help @@ -22,7 +22,7 @@ for name in pairs(Packages:installed()) do table.insert(appPaths, 1, packageDir) local apiPath = fs.combine(packageDir, 'apis') if fs.exists(apiPath) then - fs.mount(fs.combine('sys/apis', name), 'linkfs', apiPath) + fs.mount(fs.combine('rom/modules/main', name), 'linkfs', apiPath) end local helpPath = '/' .. fs.combine(packageDir, 'help') @@ -33,3 +33,5 @@ end help.setPath(table.concat(helpPaths, ':')) shell.setPath(table.concat(appPaths, ':')) + +fs.mount('rom/modules/main/opus', 'linkfs', 'sys/modules/opus') diff --git a/sys/init/6.tl3.lua b/sys/init/6.tl3.lua index 4e797e2..ee3f3aa 100644 --- a/sys/init/6.tl3.lua +++ b/sys/init/6.tl3.lua @@ -2,10 +2,10 @@ if not _G.turtle then return end -local Pathing = require('pathfind') -local Point = require('point') -local synchronized = require('sync').sync -local Util = require('util') +local Pathing = require('opus.pathfind') +local Point = require('opus.point') +local synchronized = require('opus.sync').sync +local Util = require('opus.util') local os = _G.os local peripheral = _G.peripheral diff --git a/sys/init/7.multishell.lua b/sys/init/7.multishell.lua index d9a2536..b6ada5d 100644 --- a/sys/init/7.multishell.lua +++ b/sys/init/7.multishell.lua @@ -1,8 +1,8 @@ _G.requireInjector(_ENV) -local Config = require('config') -local trace = require('trace') -local Util = require('util') +local Config = require('opus.config') +local trace = require('opus.trace') +local Util = require('opus.util') local colors = _G.colors local fs = _G.fs diff --git a/sys/kernel.lua b/sys/kernel.lua index 799164e..62ab6bc 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -1,7 +1,7 @@ _G.requireInjector(_ENV) -local Terminal = require('terminal') -local Util = require('util') +local Terminal = require('opus.terminal') +local Util = require('opus.util') _G.kernel = { UID = 0, diff --git a/sys/apis/ansi.lua b/sys/modules/opus/ansi.lua similarity index 100% rename from sys/apis/ansi.lua rename to sys/modules/opus/ansi.lua diff --git a/sys/apis/array.lua b/sys/modules/opus/array.lua similarity index 100% rename from sys/apis/array.lua rename to sys/modules/opus/array.lua diff --git a/sys/apis/bulkget.lua b/sys/modules/opus/bulkget.lua similarity index 93% rename from sys/apis/bulkget.lua rename to sys/modules/opus/bulkget.lua index a9679ef..29eadcf 100644 --- a/sys/apis/bulkget.lua +++ b/sys/modules/opus/bulkget.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local parallel = _G.parallel diff --git a/sys/apis/class.lua b/sys/modules/opus/class.lua similarity index 100% rename from sys/apis/class.lua rename to sys/modules/opus/class.lua diff --git a/sys/apis/config.lua b/sys/modules/opus/config.lua similarity index 96% rename from sys/apis/config.lua rename to sys/modules/opus/config.lua index 35f7310..3518ba2 100644 --- a/sys/apis/config.lua +++ b/sys/modules/opus/config.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local fs = _G.fs local shell = _ENV.shell diff --git a/sys/apis/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua similarity index 98% rename from sys/apis/crypto/chacha20.lua rename to sys/modules/opus/crypto/chacha20.lua index 03386a4..8302d1b 100644 --- a/sys/apis/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -1,8 +1,8 @@ -- Chacha20 cipher in ComputerCraft -- By Anavrins -local sha2 = require('crypto.sha2') -local util = require('util') +local sha2 = require('opus.crypto.sha2') +local util = require('opus.util') local ROUNDS = 20 -- Adjust this for speed tradeoff diff --git a/sys/apis/crypto/ecc/elliptic.lua b/sys/modules/opus/crypto/ecc/elliptic.lua similarity index 99% rename from sys/apis/crypto/ecc/elliptic.lua rename to sys/modules/opus/crypto/ecc/elliptic.lua index ca2b5b5..4177258 100644 --- a/sys/apis/crypto/ecc/elliptic.lua +++ b/sys/modules/opus/crypto/ecc/elliptic.lua @@ -21,7 +21,7 @@ -- Completeness? Yes: The curve is an Edwards Curve with non-square d and square a, so the curve is complete. -- Indistinguishability? No: The curve does not support indistinguishability maps. -local fp = require('crypto.ecc.fp') +local fp = require('opus.crypto.ecc.fp') local eq = fp.eq local mul = fp.mul local sqr = fp.sqr diff --git a/sys/apis/crypto/ecc/fp.lua b/sys/modules/opus/crypto/ecc/fp.lua similarity index 100% rename from sys/apis/crypto/ecc/fp.lua rename to sys/modules/opus/crypto/ecc/fp.lua diff --git a/sys/apis/crypto/ecc/fq.lua b/sys/modules/opus/crypto/ecc/fq.lua similarity index 100% rename from sys/apis/crypto/ecc/fq.lua rename to sys/modules/opus/crypto/ecc/fq.lua diff --git a/sys/apis/crypto/ecc/init.lua b/sys/modules/opus/crypto/ecc/init.lua similarity index 92% rename from sys/apis/crypto/ecc/init.lua rename to sys/modules/opus/crypto/ecc/init.lua index f765542..e1c1284 100644 --- a/sys/apis/crypto/ecc/init.lua +++ b/sys/modules/opus/crypto/ecc/init.lua @@ -1,6 +1,6 @@ -local fq = require('crypto.ecc.fq') -local elliptic = require('crypto.ecc.elliptic') -local sha256 = require('crypto.sha2') +local fq = require('opus.crypto.ecc.fq') +local elliptic = require('opus.crypto.ecc.elliptic') +local sha256 = require('opus.crypto.sha2') local os = _G.os diff --git a/sys/apis/crypto/sha2.lua b/sys/modules/opus/crypto/sha2.lua similarity index 100% rename from sys/apis/crypto/sha2.lua rename to sys/modules/opus/crypto/sha2.lua diff --git a/sys/apis/entry.lua b/sys/modules/opus/entry.lua similarity index 99% rename from sys/apis/entry.lua rename to sys/modules/opus/entry.lua index 5956762..0029ded 100644 --- a/sys/apis/entry.lua +++ b/sys/modules/opus/entry.lua @@ -1,4 +1,4 @@ -local class = require('class') +local class = require('opus.class') local os = _G.os diff --git a/sys/apis/event.lua b/sys/modules/opus/event.lua similarity index 100% rename from sys/apis/event.lua rename to sys/modules/opus/event.lua diff --git a/sys/apis/fs/gitfs.lua b/sys/modules/opus/fs/gitfs.lua similarity index 91% rename from sys/apis/fs/gitfs.lua rename to sys/modules/opus/fs/gitfs.lua index 026d9e8..21fe1d9 100644 --- a/sys/apis/fs/gitfs.lua +++ b/sys/modules/opus/fs/gitfs.lua @@ -1,4 +1,4 @@ -local git = require('git') +local git = require('opus.git') local fs = _G.fs diff --git a/sys/apis/fs/linkfs.lua b/sys/modules/opus/fs/linkfs.lua similarity index 100% rename from sys/apis/fs/linkfs.lua rename to sys/modules/opus/fs/linkfs.lua diff --git a/sys/apis/fs/netfs.lua b/sys/modules/opus/fs/netfs.lua similarity index 97% rename from sys/apis/fs/netfs.lua rename to sys/modules/opus/fs/netfs.lua index 77ec3b0..e36a1cc 100644 --- a/sys/apis/fs/netfs.lua +++ b/sys/modules/opus/fs/netfs.lua @@ -1,5 +1,5 @@ -local Socket = require('socket') -local synchronized = require('sync').sync +local Socket = require('opus.socket') +local synchronized = require('opus.sync').sync local fs = _G.fs diff --git a/sys/apis/fs/ramfs.lua b/sys/modules/opus/fs/ramfs.lua similarity index 98% rename from sys/apis/fs/ramfs.lua rename to sys/modules/opus/fs/ramfs.lua index 5dc7470..0d943a8 100644 --- a/sys/apis/fs/ramfs.lua +++ b/sys/modules/opus/fs/ramfs.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local fs = _G.fs diff --git a/sys/apis/fs/urlfs.lua b/sys/modules/opus/fs/urlfs.lua similarity index 97% rename from sys/apis/fs/urlfs.lua rename to sys/modules/opus/fs/urlfs.lua index fc3b655..960806e 100644 --- a/sys/apis/fs/urlfs.lua +++ b/sys/modules/opus/fs/urlfs.lua @@ -1,5 +1,5 @@ --local rttp = require('rttp') -local Util = require('util') +local Util = require('opus.util') local fs = _G.fs diff --git a/sys/apis/git.lua b/sys/modules/opus/git.lua similarity index 95% rename from sys/apis/git.lua rename to sys/modules/opus/git.lua index 058f202..49c42e4 100644 --- a/sys/apis/git.lua +++ b/sys/modules/opus/git.lua @@ -1,5 +1,5 @@ -local json = require('json') -local Util = require('util') +local json = require('opus.json') +local Util = require('opus.util') local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1' local FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s' diff --git a/sys/apis/gps.lua b/sys/modules/opus/gps.lua similarity index 100% rename from sys/apis/gps.lua rename to sys/modules/opus/gps.lua diff --git a/sys/apis/history.lua b/sys/modules/opus/history.lua similarity index 96% rename from sys/apis/history.lua rename to sys/modules/opus/history.lua index 7162a48..99cc060 100644 --- a/sys/apis/history.lua +++ b/sys/modules/opus/history.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local History = { } local History_mt = { __index = History } diff --git a/sys/apis/http/pastebin.lua b/sys/modules/opus/http/pastebin.lua similarity index 100% rename from sys/apis/http/pastebin.lua rename to sys/modules/opus/http/pastebin.lua diff --git a/sys/apis/injector.lua b/sys/modules/opus/injector.lua similarity index 91% rename from sys/apis/injector.lua rename to sys/modules/opus/injector.lua index 799cf0b..0835c6b 100644 --- a/sys/apis/injector.lua +++ b/sys/modules/opus/injector.lua @@ -8,21 +8,27 @@ local function split(str, pattern) return t end +local hasMain local luaPaths = package and package.path and split(package.path, '(.-);') or { } for i = 1, #luaPaths do if luaPaths[i] == '?' or luaPaths[i] == '?.lua' then luaPaths[i] = nil + elseif string.find(luaPaths[i], '/rom/modules/main') then + hasMain = true end end table.insert(luaPaths, 1, '?.lua') table.insert(luaPaths, 2, '?/init.lua') -table.insert(luaPaths, 3, '/usr/apis/?.lua') -table.insert(luaPaths, 4, '/usr/apis/?/init.lua') -table.insert(luaPaths, 5, '/sys/apis/?.lua') -table.insert(luaPaths, 6, '/sys/apis/?/init.lua') +table.insert(luaPaths, 3, '/usr/modules/?.lua') +table.insert(luaPaths, 4, '/usr/modules/?/init.lua') +table.insert(luaPaths, 5, '/sys/modules/?.lua') +table.insert(luaPaths, 6, '/sys/modules/?/init.lua') local DEFAULT_PATH = table.concat(luaPaths, ';') +if not hasMain then + DEFAULT_PATH = DEFAULT_PATH .. ';/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua' +end local fs = _G.fs local http = _G.http diff --git a/sys/apis/input.lua b/sys/modules/opus/input.lua similarity index 98% rename from sys/apis/input.lua rename to sys/modules/opus/input.lua index ee003a0..b7894d1 100644 --- a/sys/apis/input.lua +++ b/sys/modules/opus/input.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local keyboard = _G.device and _G.device.keyboard local keys = _G.keys @@ -203,4 +203,4 @@ function input:test() end end -return input \ No newline at end of file +return input diff --git a/sys/apis/json.lua b/sys/modules/opus/json.lua similarity index 100% rename from sys/apis/json.lua rename to sys/modules/opus/json.lua diff --git a/sys/apis/jumper/core/bheap.lua b/sys/modules/opus/jumper/core/bheap.lua similarity index 100% rename from sys/apis/jumper/core/bheap.lua rename to sys/modules/opus/jumper/core/bheap.lua diff --git a/sys/apis/jumper/core/node.lua b/sys/modules/opus/jumper/core/node.lua similarity index 100% rename from sys/apis/jumper/core/node.lua rename to sys/modules/opus/jumper/core/node.lua diff --git a/sys/apis/jumper/core/path.lua b/sys/modules/opus/jumper/core/path.lua similarity index 100% rename from sys/apis/jumper/core/path.lua rename to sys/modules/opus/jumper/core/path.lua diff --git a/sys/apis/jumper/core/utils.lua b/sys/modules/opus/jumper/core/utils.lua similarity index 100% rename from sys/apis/jumper/core/utils.lua rename to sys/modules/opus/jumper/core/utils.lua diff --git a/sys/apis/jumper/grid.lua b/sys/modules/opus/jumper/grid.lua similarity index 100% rename from sys/apis/jumper/grid.lua rename to sys/modules/opus/jumper/grid.lua diff --git a/sys/apis/jumper/pathfinder.lua b/sys/modules/opus/jumper/pathfinder.lua similarity index 100% rename from sys/apis/jumper/pathfinder.lua rename to sys/modules/opus/jumper/pathfinder.lua diff --git a/sys/apis/jumper/search/astar.lua b/sys/modules/opus/jumper/search/astar.lua similarity index 100% rename from sys/apis/jumper/search/astar.lua rename to sys/modules/opus/jumper/search/astar.lua diff --git a/sys/apis/map.lua b/sys/modules/opus/map.lua similarity index 96% rename from sys/apis/map.lua rename to sys/modules/opus/map.lua index 8380f38..bd576d3 100644 --- a/sys/apis/map.lua +++ b/sys/modules/opus/map.lua @@ -1,5 +1,5 @@ -- convience functions for tables with key/value pairs -local Util = require('util') +local Util = require('opus.util') local Map = { } diff --git a/sys/apis/nft.lua b/sys/modules/opus/nft.lua similarity index 98% rename from sys/apis/nft.lua rename to sys/modules/opus/nft.lua index 056961b..f6d5468 100644 --- a/sys/apis/nft.lua +++ b/sys/modules/opus/nft.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local NFT = { } diff --git a/sys/apis/packages.lua b/sys/modules/opus/packages.lua similarity index 97% rename from sys/apis/packages.lua rename to sys/modules/opus/packages.lua index 6148e28..c54bb65 100644 --- a/sys/apis/packages.lua +++ b/sys/modules/opus/packages.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local fs = _G.fs local textutils = _G.textutils diff --git a/sys/apis/pathfind.lua b/sys/modules/opus/pathfind.lua similarity index 97% rename from sys/apis/pathfind.lua rename to sys/modules/opus/pathfind.lua index f34c6ac..06c12f1 100644 --- a/sys/apis/pathfind.lua +++ b/sys/modules/opus/pathfind.lua @@ -1,7 +1,7 @@ -local Grid = require('jumper.grid') -local Pathfinder = require('jumper.pathfinder') -local Point = require('point') -local Util = require('util') +local Grid = require('opus.jumper.grid') +local Pathfinder = require('opus.jumper.pathfinder') +local Point = require('opus.point') +local Util = require('opus.util') local turtle = _G.turtle diff --git a/sys/apis/peripheral.lua b/sys/modules/opus/peripheral.lua similarity index 97% rename from sys/apis/peripheral.lua rename to sys/modules/opus/peripheral.lua index 1d84c8a..86d63fc 100644 --- a/sys/apis/peripheral.lua +++ b/sys/modules/opus/peripheral.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local Peripheral = Util.shallowCopy(_G.peripheral) @@ -123,4 +123,4 @@ function Peripheral.get(args) end end -return Peripheral \ No newline at end of file +return Peripheral diff --git a/sys/apis/point.lua b/sys/modules/opus/point.lua similarity index 99% rename from sys/apis/point.lua rename to sys/modules/opus/point.lua index da1d15b..a118df3 100644 --- a/sys/apis/point.lua +++ b/sys/modules/opus/point.lua @@ -1,4 +1,4 @@ -local Util = require('util') +local Util = require('opus.util') local Point = { } diff --git a/sys/apis/security.lua b/sys/modules/opus/security.lua similarity index 88% rename from sys/apis/security.lua rename to sys/modules/opus/security.lua index 691df97..725d864 100644 --- a/sys/apis/security.lua +++ b/sys/modules/opus/security.lua @@ -1,6 +1,6 @@ -local Config = require('config') -local Util = require('util') -local ECC = require('crypto.ecc') +local Config = require('opus.config') +local Util = require('opus.util') +local ECC = require('opus.crypto.ecc') local Security = { } diff --git a/sys/apis/socket.lua b/sys/modules/opus/socket.lua similarity index 97% rename from sys/apis/socket.lua rename to sys/modules/opus/socket.lua index ae1bc60..5e83424 100644 --- a/sys/apis/socket.lua +++ b/sys/modules/opus/socket.lua @@ -1,6 +1,6 @@ -local Crypto = require('crypto.chacha20') -local Security = require('security') -local Util = require('util') +local Crypto = require('opus.crypto.chacha20') +local Security = require('opus.security') +local Util = require('opus.util') local device = _G.device local os = _G.os diff --git a/sys/apis/sound.lua b/sys/modules/opus/sound.lua similarity index 100% rename from sys/apis/sound.lua rename to sys/modules/opus/sound.lua diff --git a/sys/apis/sync.lua b/sys/modules/opus/sync.lua similarity index 100% rename from sys/apis/sync.lua rename to sys/modules/opus/sync.lua diff --git a/sys/apis/terminal.lua b/sys/modules/opus/terminal.lua similarity index 99% rename from sys/apis/terminal.lua rename to sys/modules/opus/terminal.lua index e73d822..cb7df22 100644 --- a/sys/apis/terminal.lua +++ b/sys/modules/opus/terminal.lua @@ -1,4 +1,4 @@ -local Canvas = require('ui.canvas') +local Canvas = require('opus.ui.canvas') local colors = _G.colors local term = _G.term diff --git a/sys/apis/trace.lua b/sys/modules/opus/trace.lua similarity index 100% rename from sys/apis/trace.lua rename to sys/modules/opus/trace.lua diff --git a/sys/apis/ui.lua b/sys/modules/opus/ui.lua similarity index 98% rename from sys/apis/ui.lua rename to sys/modules/opus/ui.lua index 3b0c26b..87a6a67 100644 --- a/sys/apis/ui.lua +++ b/sys/modules/opus/ui.lua @@ -1,9 +1,9 @@ -local Canvas = require('ui.canvas') -local class = require('class') -local Event = require('event') -local Input = require('input') -local Transition = require('ui.transition') -local Util = require('util') +local Canvas = require('opus.ui.canvas') +local class = require('opus.class') +local Event = require('opus.event') +local Input = require('opus.input') +local Transition = require('opus.ui.transition') +local Util = require('opus.util') local _rep = string.rep local _sub = string.sub @@ -1168,7 +1168,7 @@ end local function loadComponents() local function load(name) - local s, m = Util.run(_ENV, 'sys/apis/ui/components/' .. name .. '.lua') + local s, m = Util.run(_ENV, 'sys/modules/opus/ui/components/' .. name .. '.lua') if not s then error(m) end @@ -1181,7 +1181,7 @@ local function loadComponents() return UI[name] end - local components = fs.list('sys/apis/ui/components') + local components = fs.list('sys/modules/opus/ui/components') for _, f in pairs(components) do local name = f:match('(.+)%.') diff --git a/sys/apis/ui/canvas.lua b/sys/modules/opus/ui/canvas.lua similarity index 98% rename from sys/apis/ui/canvas.lua rename to sys/modules/opus/ui/canvas.lua index b7969b0..260ad89 100644 --- a/sys/apis/ui/canvas.lua +++ b/sys/modules/opus/ui/canvas.lua @@ -1,6 +1,6 @@ -local class = require('class') -local Region = require('ui.region') -local Util = require('util') +local class = require('opus.class') +local Region = require('opus.ui.region') +local Util = require('opus.util') local _rep = string.rep local _sub = string.sub diff --git a/sys/apis/ui/components/ActiveLayer.lua b/sys/modules/opus/ui/components/ActiveLayer.lua similarity index 89% rename from sys/apis/ui/components/ActiveLayer.lua rename to sys/modules/opus/ui/components/ActiveLayer.lua index 94354fe..dcbb499 100644 --- a/sys/apis/ui/components/ActiveLayer.lua +++ b/sys/modules/opus/ui/components/ActiveLayer.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') UI.ActiveLayer = class(UI.Window) UI.ActiveLayer.defaults = { diff --git a/sys/apis/ui/components/Button.lua b/sys/modules/opus/ui/components/Button.lua similarity index 92% rename from sys/apis/ui/components/Button.lua rename to sys/modules/opus/ui/components/Button.lua index be31cad..c6ea3bf 100644 --- a/sys/apis/ui/components/Button.lua +++ b/sys/modules/opus/ui/components/Button.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/Checkbox.lua b/sys/modules/opus/ui/components/Checkbox.lua similarity index 95% rename from sys/apis/ui/components/Checkbox.lua rename to sys/modules/opus/ui/components/Checkbox.lua index 6356ebf..a90e911 100644 --- a/sys/apis/ui/components/Checkbox.lua +++ b/sys/modules/opus/ui/components/Checkbox.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Chooser.lua b/sys/modules/opus/ui/components/Chooser.lua similarity index 95% rename from sys/apis/ui/components/Chooser.lua rename to sys/modules/opus/ui/components/Chooser.lua index 0284fbf..e4d41fa 100644 --- a/sys/apis/ui/components/Chooser.lua +++ b/sys/modules/opus/ui/components/Chooser.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/Dialog.lua b/sys/modules/opus/ui/components/Dialog.lua similarity index 87% rename from sys/apis/ui/components/Dialog.lua rename to sys/modules/opus/ui/components/Dialog.lua index a293052..dd9de1a 100644 --- a/sys/apis/ui/components/Dialog.lua +++ b/sys/modules/opus/ui/components/Dialog.lua @@ -1,6 +1,6 @@ -local Canvas = require('ui.canvas') -local class = require('class') -local UI = require('ui') +local Canvas = require('opus.ui.canvas') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors @@ -36,4 +36,4 @@ function UI.Dialog:eventHandler(event) self:hide() end return UI.SlideOut.eventHandler(self, event) -end \ No newline at end of file +end diff --git a/sys/apis/ui/components/DropMenu.lua b/sys/modules/opus/ui/components/DropMenu.lua similarity index 93% rename from sys/apis/ui/components/DropMenu.lua rename to sys/modules/opus/ui/components/DropMenu.lua index 10ad096..5cce43a 100644 --- a/sys/apis/ui/components/DropMenu.lua +++ b/sys/modules/opus/ui/components/DropMenu.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/DropMenuItem.lua b/sys/modules/opus/ui/components/DropMenuItem.lua similarity index 87% rename from sys/apis/ui/components/DropMenuItem.lua rename to sys/modules/opus/ui/components/DropMenuItem.lua index a08f505..09263da 100644 --- a/sys/apis/ui/components/DropMenuItem.lua +++ b/sys/modules/opus/ui/components/DropMenuItem.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Embedded.lua b/sys/modules/opus/ui/components/Embedded.lua similarity index 93% rename from sys/apis/ui/components/Embedded.lua rename to sys/modules/opus/ui/components/Embedded.lua index ad4db59..fcdee82 100644 --- a/sys/apis/ui/components/Embedded.lua +++ b/sys/modules/opus/ui/components/Embedded.lua @@ -1,6 +1,6 @@ -local class = require('class') -local Terminal = require('terminal') -local UI = require('ui') +local class = require('opus.class') +local Terminal = require('opus.terminal') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Form.lua b/sys/modules/opus/ui/components/Form.lua similarity index 96% rename from sys/apis/ui/components/Form.lua rename to sys/modules/opus/ui/components/Form.lua index 8ba925e..f1eb6f3 100644 --- a/sys/apis/ui/components/Form.lua +++ b/sys/modules/opus/ui/components/Form.lua @@ -1,6 +1,6 @@ -local class = require('class') -local Sound = require('sound') -local UI = require('ui') +local class = require('opus.class') +local Sound = require('opus.sound') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Grid.lua b/sys/modules/opus/ui/components/Grid.lua similarity index 99% rename from sys/apis/ui/components/Grid.lua rename to sys/modules/opus/ui/components/Grid.lua index 21069ee..a1dc638 100644 --- a/sys/apis/ui/components/Grid.lua +++ b/sys/modules/opus/ui/components/Grid.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local os = _G.os diff --git a/sys/apis/ui/components/Image.lua b/sys/modules/opus/ui/components/Image.lua similarity index 90% rename from sys/apis/ui/components/Image.lua rename to sys/modules/opus/ui/components/Image.lua index 630cf3c..787d813 100644 --- a/sys/apis/ui/components/Image.lua +++ b/sys/modules/opus/ui/components/Image.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') UI.Image = class(UI.Window) UI.Image.defaults = { diff --git a/sys/apis/ui/components/Menu.lua b/sys/modules/opus/ui/components/Menu.lua similarity index 94% rename from sys/apis/ui/components/Menu.lua rename to sys/modules/opus/ui/components/Menu.lua index 3377a0e..f581874 100644 --- a/sys/apis/ui/components/Menu.lua +++ b/sys/modules/opus/ui/components/Menu.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') --[[-- Menu --]]-- UI.Menu = class(UI.Grid) diff --git a/sys/apis/ui/components/MenuBar.lua b/sys/modules/opus/ui/components/MenuBar.lua similarity index 96% rename from sys/apis/ui/components/MenuBar.lua rename to sys/modules/opus/ui/components/MenuBar.lua index 4c239c0..bccb9be 100644 --- a/sys/apis/ui/components/MenuBar.lua +++ b/sys/modules/opus/ui/components/MenuBar.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/MenuItem.lua b/sys/modules/opus/ui/components/MenuItem.lua similarity index 79% rename from sys/apis/ui/components/MenuItem.lua rename to sys/modules/opus/ui/components/MenuItem.lua index c4dbc7a..2f0efe8 100644 --- a/sys/apis/ui/components/MenuItem.lua +++ b/sys/modules/opus/ui/components/MenuItem.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/NftImage.lua b/sys/modules/opus/ui/components/NftImage.lua similarity index 89% rename from sys/apis/ui/components/NftImage.lua rename to sys/modules/opus/ui/components/NftImage.lua index 37740c5..b932dfb 100644 --- a/sys/apis/ui/components/NftImage.lua +++ b/sys/modules/opus/ui/components/NftImage.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') UI.NftImage = class(UI.Window) UI.NftImage.defaults = { diff --git a/sys/apis/ui/components/Notification.lua b/sys/modules/opus/ui/components/Notification.lua similarity index 91% rename from sys/apis/ui/components/Notification.lua rename to sys/modules/opus/ui/components/Notification.lua index 33a5745..f1b38f6 100644 --- a/sys/apis/ui/components/Notification.lua +++ b/sys/modules/opus/ui/components/Notification.lua @@ -1,8 +1,8 @@ -local class = require('class') -local Event = require('event') -local Sound = require('sound') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local Event = require('opus.event') +local Sound = require('opus.sound') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/ProgressBar.lua b/sys/modules/opus/ui/components/ProgressBar.lua similarity index 84% rename from sys/apis/ui/components/ProgressBar.lua rename to sys/modules/opus/ui/components/ProgressBar.lua index 2a78c5f..56d6156 100644 --- a/sys/apis/ui/components/ProgressBar.lua +++ b/sys/modules/opus/ui/components/ProgressBar.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/ScrollBar.lua b/sys/modules/opus/ui/components/ScrollBar.lua similarity index 95% rename from sys/apis/ui/components/ScrollBar.lua rename to sys/modules/opus/ui/components/ScrollBar.lua index 2299502..d4bef52 100644 --- a/sys/apis/ui/components/ScrollBar.lua +++ b/sys/modules/opus/ui/components/ScrollBar.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/ScrollingGrid.lua b/sys/modules/opus/ui/components/ScrollingGrid.lua similarity index 93% rename from sys/apis/ui/components/ScrollingGrid.lua rename to sys/modules/opus/ui/components/ScrollingGrid.lua index c29fe74..93a35e6 100644 --- a/sys/apis/ui/components/ScrollingGrid.lua +++ b/sys/modules/opus/ui/components/ScrollingGrid.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') --[[-- ScrollingGrid --]]-- UI.ScrollingGrid = class(UI.Grid) diff --git a/sys/apis/ui/components/SlideOut.lua b/sys/modules/opus/ui/components/SlideOut.lua similarity index 92% rename from sys/apis/ui/components/SlideOut.lua rename to sys/modules/opus/ui/components/SlideOut.lua index 9e85251..37f5e37 100644 --- a/sys/apis/ui/components/SlideOut.lua +++ b/sys/modules/opus/ui/components/SlideOut.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') --[[-- SlideOut --]]-- UI.SlideOut = class(UI.Window) diff --git a/sys/apis/ui/components/StatusBar.lua b/sys/modules/opus/ui/components/StatusBar.lua similarity index 93% rename from sys/apis/ui/components/StatusBar.lua rename to sys/modules/opus/ui/components/StatusBar.lua index af1d2c4..a92c0c2 100644 --- a/sys/apis/ui/components/StatusBar.lua +++ b/sys/modules/opus/ui/components/StatusBar.lua @@ -1,7 +1,7 @@ -local class = require('class') -local Event = require('event') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local Event = require('opus.event') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/Tab.lua b/sys/modules/opus/ui/components/Tab.lua similarity index 69% rename from sys/apis/ui/components/Tab.lua rename to sys/modules/opus/ui/components/Tab.lua index d564c86..2f86b2f 100644 --- a/sys/apis/ui/components/Tab.lua +++ b/sys/modules/opus/ui/components/Tab.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/TabBar.lua b/sys/modules/opus/ui/components/TabBar.lua similarity index 90% rename from sys/apis/ui/components/TabBar.lua rename to sys/modules/opus/ui/components/TabBar.lua index 1431314..72e07f6 100644 --- a/sys/apis/ui/components/TabBar.lua +++ b/sys/modules/opus/ui/components/TabBar.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors diff --git a/sys/apis/ui/components/TabBarMenuItem.lua b/sys/modules/opus/ui/components/TabBarMenuItem.lua similarity index 90% rename from sys/apis/ui/components/TabBarMenuItem.lua rename to sys/modules/opus/ui/components/TabBarMenuItem.lua index 28e585b..0a7799c 100644 --- a/sys/apis/ui/components/TabBarMenuItem.lua +++ b/sys/modules/opus/ui/components/TabBarMenuItem.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Tabs.lua b/sys/modules/opus/ui/components/Tabs.lua similarity index 94% rename from sys/apis/ui/components/Tabs.lua rename to sys/modules/opus/ui/components/Tabs.lua index 7c2d967..46f87d1 100644 --- a/sys/apis/ui/components/Tabs.lua +++ b/sys/modules/opus/ui/components/Tabs.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') UI.Tabs = class(UI.Window) UI.Tabs.defaults = { diff --git a/sys/apis/ui/components/Text.lua b/sys/modules/opus/ui/components/Text.lua similarity index 76% rename from sys/apis/ui/components/Text.lua rename to sys/modules/opus/ui/components/Text.lua index 68926d2..0250a48 100644 --- a/sys/apis/ui/components/Text.lua +++ b/sys/modules/opus/ui/components/Text.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') UI.Text = class(UI.Window) UI.Text.defaults = { diff --git a/sys/apis/ui/components/TextArea.lua b/sys/modules/opus/ui/components/TextArea.lua similarity index 89% rename from sys/apis/ui/components/TextArea.lua rename to sys/modules/opus/ui/components/TextArea.lua index 8602866..51b8972 100644 --- a/sys/apis/ui/components/TextArea.lua +++ b/sys/modules/opus/ui/components/TextArea.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') --[[-- TextArea --]]-- UI.TextArea = class(UI.Viewport) diff --git a/sys/apis/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua similarity index 94% rename from sys/apis/ui/components/TextEntry.lua rename to sys/modules/opus/ui/components/TextEntry.lua index 69566c6..512f668 100644 --- a/sys/apis/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -1,7 +1,7 @@ -local class = require('class') -local entry = require('entry') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local entry = require('opus.entry') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local _rep = string.rep diff --git a/sys/apis/ui/components/Throttle.lua b/sys/modules/opus/ui/components/Throttle.lua similarity index 95% rename from sys/apis/ui/components/Throttle.lua rename to sys/modules/opus/ui/components/Throttle.lua index 1e2dc02..0466486 100644 --- a/sys/apis/ui/components/Throttle.lua +++ b/sys/modules/opus/ui/components/Throttle.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors local os = _G.os diff --git a/sys/apis/ui/components/TitleBar.lua b/sys/modules/opus/ui/components/TitleBar.lua similarity index 96% rename from sys/apis/ui/components/TitleBar.lua rename to sys/modules/opus/ui/components/TitleBar.lua index 872d78b..ce7fdd4 100644 --- a/sys/apis/ui/components/TitleBar.lua +++ b/sys/modules/opus/ui/components/TitleBar.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors local _rep = string.rep diff --git a/sys/apis/ui/components/VerticalMeter.lua b/sys/modules/opus/ui/components/VerticalMeter.lua similarity index 85% rename from sys/apis/ui/components/VerticalMeter.lua rename to sys/modules/opus/ui/components/VerticalMeter.lua index e4f1e7b..012d0e5 100644 --- a/sys/apis/ui/components/VerticalMeter.lua +++ b/sys/modules/opus/ui/components/VerticalMeter.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Viewport.lua b/sys/modules/opus/ui/components/Viewport.lua similarity index 97% rename from sys/apis/ui/components/Viewport.lua rename to sys/modules/opus/ui/components/Viewport.lua index b0e2a30..acb84cd 100644 --- a/sys/apis/ui/components/Viewport.lua +++ b/sys/modules/opus/ui/components/Viewport.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/components/Wizard.lua b/sys/modules/opus/ui/components/Wizard.lua similarity index 96% rename from sys/apis/ui/components/Wizard.lua rename to sys/modules/opus/ui/components/Wizard.lua index 67dcc2b..e6bce7e 100644 --- a/sys/apis/ui/components/Wizard.lua +++ b/sys/modules/opus/ui/components/Wizard.lua @@ -1,6 +1,6 @@ -local class = require('class') -local UI = require('ui') -local Util = require('util') +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') UI.Wizard = class(UI.Window) UI.Wizard.defaults = { diff --git a/sys/apis/ui/components/WizardPage.lua b/sys/modules/opus/ui/components/WizardPage.lua similarity index 70% rename from sys/apis/ui/components/WizardPage.lua rename to sys/modules/opus/ui/components/WizardPage.lua index dae4e9a..cb2c2de 100644 --- a/sys/apis/ui/components/WizardPage.lua +++ b/sys/modules/opus/ui/components/WizardPage.lua @@ -1,5 +1,5 @@ -local class = require('class') -local UI = require('ui') +local class = require('opus.class') +local UI = require('opus.ui') local colors = _G.colors diff --git a/sys/apis/ui/region.lua b/sys/modules/opus/ui/region.lua similarity index 100% rename from sys/apis/ui/region.lua rename to sys/modules/opus/ui/region.lua diff --git a/sys/apis/ui/transition.lua b/sys/modules/opus/ui/transition.lua similarity index 96% rename from sys/apis/ui/transition.lua rename to sys/modules/opus/ui/transition.lua index 90db9ee..4448760 100644 --- a/sys/apis/ui/transition.lua +++ b/sys/modules/opus/ui/transition.lua @@ -1,4 +1,4 @@ -local Tween = require('ui.tween') +local Tween = require('opus.ui.tween') local Transition = { } diff --git a/sys/apis/ui/tween.lua b/sys/modules/opus/ui/tween.lua similarity index 100% rename from sys/apis/ui/tween.lua rename to sys/modules/opus/ui/tween.lua diff --git a/sys/apis/util.lua b/sys/modules/opus/util.lua similarity index 100% rename from sys/apis/util.lua rename to sys/modules/opus/util.lua From d90aa0e2fd0bf27224998f789dd60e150ace7087 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 28 Jun 2019 14:22:03 -0400 Subject: [PATCH 157/231] cleanup --- sys/autorun/upgraded.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index 5c947c5..f988ba1 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -5,3 +5,7 @@ if fs.exists('sys/etc/app.db') then fs.delete('sys/etc/app.db') end if fs.exists('sys/extensions') then fs.delete('sys/extensions') end if fs.exists('sys/network') then fs.delete('sys/network') end if fs.exists('startup') then fs.delete('startup') end + +if fs.exists('sys/autorun/gps.lua') then fs.delete('sys/autorun/gps.lua') end +if fs.exists('sys/apps/network/redserver.lua') then fs.delete('sys/apps/network/redserver.lua') end +if fs.exists('sys/apis') then fs.delete('sys/apis') end From 00293033c8fef3aaeb627d84960038e1423c94e7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Jun 2019 02:44:30 -0400 Subject: [PATCH 158/231] security update round 2 --- sys/apps/shell.lua | 1 + sys/autorun/upgraded.lua | 1 + sys/boot/opus.boot | 52 ++---------- sys/modules/opus/crypto/chacha20.lua | 6 +- sys/modules/opus/crypto/sha2.lua | 18 ++++- sys/modules/opus/injector.lua | 114 ++++----------------------- sys/modules/opus/security.lua | 23 +++++- sys/modules/opus/socket.lua | 35 ++++++-- 8 files changed, 91 insertions(+), 159 deletions(-) diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index 5d7f067..c5dbf28 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -71,6 +71,7 @@ local function run(env, ...) tProgramStack[#tProgramStack + 1] = path end + env[ "arg" ] = { [0] = path, table.unpack(args) } local r = { fn(table.unpack(args)) } tProgramStack[#tProgramStack] = nil diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index f988ba1..d3a2737 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -7,5 +7,6 @@ if fs.exists('sys/network') then fs.delete('sys/network') end if fs.exists('startup') then fs.delete('startup') end if fs.exists('sys/autorun/gps.lua') then fs.delete('sys/autorun/gps.lua') end +if fs.exists('sys/autorun/gpsHost.lua') then fs.delete('sys/autorun/gpsHost.lua') end if fs.exists('sys/apps/network/redserver.lua') then fs.delete('sys/apps/network/redserver.lua') end if fs.exists('sys/apis') then fs.delete('sys/apis') end diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index f3b5ffb..2a02d14 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -1,68 +1,28 @@ --- Loads the Opus environment regardless if the file system is local or not -local fs = _G.fs -local http = _G.http - -_G.OPUS_BRANCH = 'develop-1.8' -local GIT_REPO = 'kepler155c/opus/' .. _G.OPUS_BRANCH -local BASE = 'https://raw.githubusercontent.com/' .. GIT_REPO +local fs = _G.fs local sandboxEnv = setmetatable({ }, { __index = _G }) for k,v in pairs(_ENV) do sandboxEnv[k] = v end -_G._syslog = function() end - -local function makeEnv() +local function run(file, ...) local env = setmetatable({ }, { __index = _G }) for k,v in pairs(sandboxEnv) do env[k] = v end - return env -end -local function run(file, ...) - local s, m = loadfile(file, makeEnv()) + local s, m = loadfile(file, env) if s then return s(...) end error('Error loading ' .. file .. '\n' .. m) end -local function runUrl(file, ...) - local url = BASE .. '/' .. file - - local u = http.get(url) - if u then - local fn = load(u.readAll(), url, nil, makeEnv()) - u.close() - if fn then - return fn(...) - end - end - error('Failed to download ' .. url) -end +_G._syslog = function() end +_G.OPUS_BRANCH = 'develop-1.8' -- Install require shim -if fs.exists('sys/modules/opus/injector.lua') then - _G.requireInjector = run('sys/modules/opus/injector.lua') -else - -- not local, run the file system directly from git - if package and package.path then - package.path = package.path .. ';' .. BASE .. '/sys/modules/opus' - else - sandboxEnv.package = { - path = BASE .. '/sys/modules/opus' - } - end - - _G.requireInjector = runUrl('sys/modules/opus/injector.lua') - - runUrl('sys/init/2.vfs.lua') - - -- install file system - fs.mount('', 'gitfs', GIT_REPO) -end +_G.requireInjector = run('sys/modules/opus/injector.lua') local s, m = pcall(run, 'sys/apps/shell.lua', 'sys/kernel.lua', ...) diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index 8302d1b..b08d09a 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -115,6 +115,7 @@ local function crypt(data, key, nonce, cntr, round) cntr = tonumber(cntr) or 1 round = tonumber(round) or 20 + local throttle = util.throttle() local out = {} local state = initState(key, nonce, cntr) local blockAmt = math.floor(#data/64) @@ -131,8 +132,9 @@ local function crypt(data, key, nonce, cntr, round) end if i % 1000 == 0 then - os.queueEvent("") - os.pullEvent("") + throttle() + --os.queueEvent("") + --os.pullEvent("") end end return setmetatable(out, mt) diff --git a/sys/modules/opus/crypto/sha2.lua b/sys/modules/opus/crypto/sha2.lua index a4f29f3..631488a 100644 --- a/sys/modules/opus/crypto/sha2.lua +++ b/sys/modules/opus/crypto/sha2.lua @@ -162,12 +162,25 @@ local function hmac(data, key) return digest(padded_key) end +local function throttler() + local ts = os.clock() + local timeout = .095 + return function() + local nts = os.clock() + if nts > ts + timeout then + os.sleep(0) + ts = os.clock() + end + end +end + local function pbkdf2(pass, salt, iter, dklen) salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} local hashlen = 32 dklen = dklen or 32 local block = 1 local out = {} + local throttle = throttler() while dklen > 0 do local ikey = {} @@ -182,7 +195,10 @@ local function pbkdf2(pass, salt, iter, dklen) for j = 1, iter do isalt = hmac(isalt, pass) for k = 1, clen do ikey[k] = bxor(isalt[k], ikey[k] or 0) end - if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end + if j % 200 == 0 then + throttle() + --os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") + end end dklen = dklen - clen block = block+1 diff --git a/sys/modules/opus/injector.lua b/sys/modules/opus/injector.lua index 0835c6b..e93e5d1 100644 --- a/sys/modules/opus/injector.lua +++ b/sys/modules/opus/injector.lua @@ -1,6 +1,3 @@ -local PASTEBIN_URL = 'http://pastebin.com/raw' -local GIT_URL = 'https://raw.githubusercontent.com' - local function split(str, pattern) local t = { } local function helper(line) table.insert(t, line) return "" end @@ -11,7 +8,7 @@ end local hasMain local luaPaths = package and package.path and split(package.path, '(.-);') or { } for i = 1, #luaPaths do - if luaPaths[i] == '?' or luaPaths[i] == '?.lua' then + if luaPaths[i] == '?' or luaPaths[i] == '?.lua' or luaPaths[i] == '?/init.lua' then luaPaths[i] = nil elseif string.find(luaPaths[i], '/rom/modules/main') then hasMain = true @@ -22,70 +19,20 @@ table.insert(luaPaths, 1, '?.lua') table.insert(luaPaths, 2, '?/init.lua') table.insert(luaPaths, 3, '/usr/modules/?.lua') table.insert(luaPaths, 4, '/usr/modules/?/init.lua') -table.insert(luaPaths, 5, '/sys/modules/?.lua') -table.insert(luaPaths, 6, '/sys/modules/?/init.lua') +if not hasMain then + table.insert(luaPaths, 5, '/rom/modules/main/?') + table.insert(luaPaths, 6, '/rom/modules/main/?.lua') + table.insert(luaPaths, 7, '/rom/modules/main/?/init.lua') +end +table.insert(luaPaths, '/sys/modules/?.lua') +table.insert(luaPaths, '/sys/modules/?/init.lua') local DEFAULT_PATH = table.concat(luaPaths, ';') -if not hasMain then - DEFAULT_PATH = DEFAULT_PATH .. ';/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua' -end local fs = _G.fs -local http = _G.http local os = _G.os local string = _G.string ---[[ -if not http._patched then - -- fix broken http get (http.get is not coroutine safe) - local syncLocks = { } - - local function sync(obj, fn) - local key = tostring(obj) - if syncLocks[key] then - local cos = tostring(coroutine.running()) - table.insert(syncLocks[key], cos) - repeat - local _, co = os.pullEvent('sync_lock') - until co == cos - else - syncLocks[key] = { } - end - fn() - local co = table.remove(syncLocks[key], 1) - if co then - os.queueEvent('sync_lock', co) - else - syncLocks[key] = nil - end - end - - -- todo -- completely replace http.get with function that - -- checks for success on permanent redirects (minecraft 1.75 bug) - - http._patched = http.get - function http.get(url, headers) - local s, m - sync(url, function() - s, m = http._patched(url, headers) - end) - return s, m - end -end ---]] - -local function loadUrl(url) - local c - local h = http.get(url) - if h then - c = h.readAll() - h.close() - end - if c and #c > 0 then - return c - end -end - -- Add require and package to the environment return function(env) local function preloadSearcher(modname) @@ -118,45 +65,14 @@ return function(env) local sPath = string.gsub(pattern, "%?", fname) -- TODO: if there's no shell, we should not be checking relative paths below -- as they will resolve to root directory - if sPath:match("^(https?:)") then - local c = loadUrl(sPath) - if c then - return load(c, modname, nil, env) - end - else - if env.shell and - type(env.shell.getRunningProgram) == 'function' and - sPath:sub(1, 1) ~= "/" then + if env.shell and + type(env.shell.getRunningProgram) == 'function' and + sPath:sub(1, 1) ~= "/" then - sPath = fs.combine(fs.getDir(env.shell.getRunningProgram() or ''), sPath) - end - if fs.exists(sPath) and not fs.isDir(sPath) then - return loadfile(sPath, env) - end + sPath = fs.combine(fs.getDir(env.shell.getRunningProgram() or ''), sPath) end - end - end - - -- require('BniCQPVf') - local function pastebinSearcher(modname) - if #modname == 8 and not modname:match('%W') then - local url = PASTEBIN_URL .. '/' .. modname - local c = loadUrl(url) - if c then - return load(c, modname, nil, env) - end - end - end - - -- require('kepler155c.opus.master.sys.apis.util') - local function gitSearcher(modname) - local fname = modname:gsub('%.', '/') .. '.lua' - local _, count = fname:gsub("/", "") - if count >= 3 then - local url = GIT_URL .. '/' .. fname - local c = loadUrl(url) - if c then - return load(c, modname, nil, env) + if fs.exists(sPath) and not fs.isDir(sPath) then + return loadfile(sPath, env) end end end @@ -178,8 +94,6 @@ return function(env) preloadSearcher, loadedSearcher, pathSearcher, - pastebinSearcher, - gitSearcher, } } diff --git a/sys/modules/opus/security.lua b/sys/modules/opus/security.lua index 725d864..ce194f9 100644 --- a/sys/modules/opus/security.lua +++ b/sys/modules/opus/security.lua @@ -13,13 +13,28 @@ function Security.hasPassword() return not not Security.getPassword() end +local function genKey() + local key = { } + for _ = 1, 32 do + table.insert(key, ("%02x"):format(math.random(0, 0xFF))) + end + return table.concat(key) +end + +function Security.generateKeyPair() + local privateKey = Util.hexToByteArray(genKey()) + return privateKey, ECC.publicKey(privateKey) +end + +function Security.getIdentifier() + return Security.geetPublicKey() +end + +-- deprecate - will use getIdentifier function Security.getSecretKey() local config = Config.load('os') if not config.secretKey then - config.secretKey = "" - for _ = 1, 32 do - config.secretKey = config.secretKey .. ("%02x"):format(math.random(0, 0xFF)) - end + config.secretKey = genKey() Config.update('os', config) end return Util.hexToByteArray(config.secretKey) diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index 5e83424..da8ceff 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -1,5 +1,7 @@ local Crypto = require('opus.crypto.chacha20') +local ECC = require('opus.crypto.ecc') local Security = require('opus.security') +local SHA = require('opus.crypto.sha2') local Util = require('opus.util') local device = _G.device @@ -60,6 +62,14 @@ function socketClass:ping() end end +function socketClass:setupEncryption() + self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey) + self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) + self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) + self.rseed = SHA.pbkdf2(self.sharedKey, "3rseed", 1) + self.wseed = SHA.pbkdf2(self.sharedKey, "4sseed", 1) +end + function socketClass:close() if self.connected then self.transmit(self.dport, self.dhost, { @@ -110,14 +120,20 @@ function Socket.connect(host, port) local socket = newSocket(host == os.getComputerID()) socket.dhost = tonumber(host) + socket.privKey, socket.pubKey = Security.generateKeyPair() socket.transmit(port, socket.sport, { type = 'OPEN', shost = socket.shost, dhost = socket.dhost, - t = Crypto.encrypt({ ts = os.time(), seq = socket.seq, nts = os.epoch('utc') }, Security.getPublicKey()), rseq = socket.wseq, wseq = socket.rseq, + t = Crypto.encrypt({ + ts = os.time(), + seq = socket.seq, + nts = os.epoch('utc'), + pk = Util.byteArrayToHex(socket.pubKey), + }, Security.getPublicKey()), }) local timerId = os.startTimer(3) @@ -133,6 +149,8 @@ function Socket.connect(host, port) if msg.type == 'CONN' then socket.dport = dport socket.connected = true + socket.remotePubKey = Util.hexToByteArray(msg.pk) + socket:setupEncryption() -- Logger.log('socket', 'connection established to %d %d->%d', -- host, socket.sport, socket.dport) _G.transport.open(socket) @@ -153,7 +171,7 @@ function Socket.connect(host, port) return false, 'Connection timed out', 'TIMEOUT' end -local function trusted(msg, port) +local function trusted(socket, msg, port) if port == 19 or msg.shost == os.getComputerID() then -- no auth for trust server or loopback return true @@ -168,11 +186,12 @@ local function trusted(msg, port) local pubKey = trustList[msg.shost] if pubKey and msg.t then - pubKey = Util.hexToByteArray(pubKey) - local data = Crypto.decrypt(msg.t, pubKey) + local data = Crypto.decrypt(msg.t, Util.hexToByteArray(pubKey)) if data and data.nts then -- upgraded security - return data.nts and tonumber(data.nts) and math.abs(os.epoch('utc') - data.nts) < 1024 + if data.nts and tonumber(data.nts) and math.abs(os.epoch('utc') - data.nts) < 1024 then + socket.remotePubKey = Util.hexToByteArray(data.pk) + end end --local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod) @@ -207,13 +226,17 @@ function Socket.server(port) }) socket:close() - elseif trusted(msg, port) then + elseif trusted(socket, msg, port) then socket.connected = true + socket.privKey, socket.pubKey = Security.generateKeyPair() + socket:setupEncryption() socket.transmit(socket.dport, socket.sport, { type = 'CONN', dhost = socket.dhost, shost = socket.shost, + pk = Util.byteArrayToHex(socket.pubKey), }) + -- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport) _G.transport.open(socket) From 5283de18ed918a3160fb81f99e746bc6bec92e35 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Jun 2019 04:04:51 -0400 Subject: [PATCH 159/231] oops --- sys/modules/opus/security.lua | 2 +- sys/modules/opus/socket.lua | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/modules/opus/security.lua b/sys/modules/opus/security.lua index ce194f9..a44605c 100644 --- a/sys/modules/opus/security.lua +++ b/sys/modules/opus/security.lua @@ -27,7 +27,7 @@ function Security.generateKeyPair() end function Security.getIdentifier() - return Security.geetPublicKey() + return Security.getPublicKey() end -- deprecate - will use getIdentifier diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index da8ceff..bb3b6ef 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -63,11 +63,13 @@ function socketClass:ping() end function socketClass:setupEncryption() + if false then self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey) self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) self.rseed = SHA.pbkdf2(self.sharedKey, "3rseed", 1) self.wseed = SHA.pbkdf2(self.sharedKey, "4sseed", 1) + end end function socketClass:close() From 69522e61d44bdae66716d055d7960743fbc3aab9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Jun 2019 08:50:11 -0400 Subject: [PATCH 160/231] better info on upgrade --- sys/autorun/welcome.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sys/autorun/welcome.lua b/sys/autorun/welcome.lua index b8d113b..b7fc3cc 100644 --- a/sys/autorun/welcome.lua +++ b/sys/autorun/welcome.lua @@ -6,13 +6,14 @@ local os = _G.os local shell = _ENV.shell local config = Config.load('os') -if not config.welcomed and shell.openForegroundTab then +if not config.welcomed then config.welcomed = true config.securityUpdate = true config.readNotes = 1 Config.update('os', config) - - shell.openForegroundTab('Welcome') + if shell.openForegroundTab then + shell.openForegroundTab('Welcome') + end end if not config.securityUpdate then @@ -34,9 +35,13 @@ password in System->System->Password. All computers that you connect to will also need to be updated as well. +Also, I have changed the location for apis. +This will require you to update all installed +packages. Sorry ! + Thanks for your patience. And... thanks to Anavrins for the much improved security. - ]]) +]]) end if fs.exists('sys/notes_1.txt') and shell.openForegroundTab then From e75a357209174ece39d1c5fc49e41a08de2949d7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Jun 2019 16:35:33 -0400 Subject: [PATCH 161/231] security updates --- sys/apps/Network.lua | 10 ++- sys/apps/netdaemon.lua | 1 + sys/apps/network/keygen.lua | 39 +++++++++++ sys/apps/network/transport.lua | 47 +++++-------- sys/apps/network/trust.lua | 6 +- sys/apps/trust.lua | 7 +- sys/modules/opus/crypto/chacha20.lua | 8 +-- sys/modules/opus/crypto/ecc/elliptic.lua | 16 +++-- sys/modules/opus/crypto/ecc/fp.lua | 2 + sys/modules/opus/crypto/ecc/fq.lua | 2 + sys/modules/opus/crypto/ecc/init.lua | 1 + sys/modules/opus/crypto/sha2.lua | 16 +---- sys/modules/opus/security.lua | 26 ++++---- sys/modules/opus/socket.lua | 84 +++++++++++------------- sys/modules/opus/util.lua | 1 + 15 files changed, 147 insertions(+), 119 deletions(-) create mode 100644 sys/apps/network/keygen.lua diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index f9f4cc1..1c8405d 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -137,10 +137,14 @@ end ]] function page.ports.grid:update() + local transport = network:getTransport() + local function findConnection(port) - for _,socket in pairs(_G.transport.sockets) do - if socket.sport == port then - return socket + if transport then + for _,socket in pairs(transport.sockets) do + if socket.sport == port then + return socket + end end end end diff --git a/sys/apps/netdaemon.lua b/sys/apps/netdaemon.lua index fb9e23e..2457a49 100644 --- a/sys/apps/netdaemon.lua +++ b/sys/apps/netdaemon.lua @@ -14,6 +14,7 @@ if not device.wireless_modem then end print('Net daemon starting') +device.wireless_modem.closeAll() for _,file in pairs(fs.list('sys/apps/network')) do local fn, msg = Util.run(_ENV, 'sys/apps/network/' .. file) diff --git a/sys/apps/network/keygen.lua b/sys/apps/network/keygen.lua new file mode 100644 index 0000000..65f04b8 --- /dev/null +++ b/sys/apps/network/keygen.lua @@ -0,0 +1,39 @@ +local ECC = require('opus.crypto.ecc') +local Event = require('opus.event') +local Util = require('opus.util') + +local network = _G.network +local os = _G.os + +local keyPairs = { } + +local function generateKeyPair() + local key = { } + for _ = 1, 32 do + table.insert(key, ("%02x"):format(math.random(0, 0xFF))) + end + local privateKey = Util.hexToByteArray(table.concat(key)) + return privateKey, ECC.publicKey(privateKey) +end + +getmetatable(network).__index.getKeyPair = function() + local keys = table.remove(keyPairs) + os.queueEvent('generate_keypair') + if not keys then + return generateKeyPair() + end + return table.unpack(keys) +end + +-- Generate key pairs in the background as this is a time-consuming process +Event.on('generate_keypair', function() + while true do + os.sleep(5) + local timer = Util.timer() + table.insert(keyPairs, { generateKeyPair() }) + _G._syslog('Generated keypair in ' .. timer()) + if #keyPairs >= 3 then + break + end + end +end) diff --git a/sys/apps/network/transport.lua b/sys/apps/network/transport.lua index fa1978c..316f46a 100644 --- a/sys/apps/network/transport.lua +++ b/sys/apps/network/transport.lua @@ -6,7 +6,9 @@ ]]-- local Event = require('opus.event') +local SHA = require('opus.crypto.sha2') +local network = _G.network local os = _G.os local computerId = os.getComputerID() @@ -15,7 +17,10 @@ local transport = { sockets = { }, UID = 0, } -_G.transport = transport + +getmetatable(network).__index.getTransport = function() + return transport +end function transport.open(socket) transport.UID = transport.UID + 1 @@ -33,19 +38,11 @@ function transport.read(socket) end function transport.write(socket, data) - --_syslog('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq })) socket.transmit(socket.dport, socket.dhost, data) - - --local timerId = os.startTimer(3) - - --transport.timers[timerId] = socket - --socket.timers[socket.wseq] = timerId - - socket.wseq = socket.wseq + 1 + socket.wseq = SHA.digest(socket.wseq):toHex() end function transport.ping(socket) - --_syslog('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq })) if os.clock() - socket.activityTimer > 10 then socket.activityTimer = os.clock() socket.transmit(socket.dport, socket.dhost, { @@ -53,7 +50,7 @@ function transport.ping(socket) seq = -1, }) - local timerId = os.startTimer(5) + local timerId = os.startTimer(3) transport.timers[timerId] = socket socket.timers[-1] = timerId end @@ -78,18 +75,19 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) local socket = transport.sockets[dport] if socket and socket.connected then - --if msg.type then _syslog('<< ' .. Util.tostring(msg)) end if socket.co and coroutine.status(socket.co) == 'dead' then _G._syslog('socket coroutine dead') socket:close() elseif msg.type == 'DISC' then -- received disconnect from other end - if socket.connected then - os.queueEvent('transport_' .. socket.uid) + if msg.seq == socket.rseq then + if socket.connected then + os.queueEvent('transport_' .. socket.uid) + end + socket.connected = false + socket:close() end - socket.connected = false - socket:close() elseif msg.type == 'ACK' then local ackTimerId = socket.timers[msg.seq] @@ -108,28 +106,19 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) }) elseif msg.type == 'DATA' and msg.data then - socket.activityTimer = os.clock() if msg.seq ~= socket.rseq then print('transport seq error - closing socket ' .. socket.sport) _syslog(msg.data) - _syslog('current ' .. socket.rseq) - _syslog('expected ' .. msg.seq) --- socket:close() --- os.queueEvent('transport_' .. socket.uid) + _syslog('expected ' .. socket.rseq) + _syslog('got ' .. msg.seq) else - socket.rseq = socket.rseq + 1 + socket.activityTimer = os.clock() + socket.rseq = SHA.digest(socket.rseq):toHex() table.insert(socket.messages, { msg.data, distance }) - -- use resume instead ?? if not socket.messages[2] then -- table size is 1 os.queueEvent('transport_' .. socket.uid) end - - --_syslog('>> ' .. Util.tostring({ type = 'ACK', seq = msg.seq })) - --socket.transmit(socket.dport, socket.dhost, { - -- type = 'ACK', - -- seq = msg.seq, - --}) end end end diff --git a/sys/apps/network/trust.lua b/sys/apps/network/trust.lua index b31acbc..58d3847 100644 --- a/sys/apps/network/trust.lua +++ b/sys/apps/network/trust.lua @@ -4,6 +4,8 @@ local Security = require('opus.security') local Socket = require('opus.socket') local Util = require('opus.util') +local trustId = '01c3ba27fe01383a03a1785276d99df27c3edcef68fbf231ca' + local function trustConnection(socket) local data = socket:read(2) if data then @@ -14,7 +16,7 @@ local function trustConnection(socket) data = Crypto.decrypt(data, password) if data and data.pk and data.dh == socket.dhost then local trustList = Util.readTable('usr/.known_hosts') or { } - trustList[data.dh] = Util.byteArrayToHex(data.pk) + trustList[data.dh] = data.pk Util.writeTable('usr/.known_hosts', trustList) socket:write({ success = true, msg = 'Trust accepted' }) @@ -29,7 +31,7 @@ Event.addRoutine(function() print('trust: listening on port 19') while true do - local socket = Socket.server(19) + local socket = Socket.server(19, { identifier = trustId }) print('trust: connection from ' .. socket.dhost) diff --git a/sys/apps/trust.lua b/sys/apps/trust.lua index b1283f8..9d036c9 100644 --- a/sys/apps/trust.lua +++ b/sys/apps/trust.lua @@ -27,15 +27,16 @@ if not password then end print('connecting...') -local socket, msg = Socket.connect(remoteId, 19) +local trustId = '01c3ba27fe01383a03a1785276d99df27c3edcef68fbf231ca' +local socket, msg = Socket.connect(remoteId, 19, { identifier = trustId }) if not socket then error(msg) end -local publicKey = Security.getPublicKey() +local identifier = Security.getIdentifier() -socket:write(Crypto.encrypt({ pk = publicKey, dh = os.getComputerID() }, SHA.compute(password))) +socket:write(Crypto.encrypt({ pk = identifier, dh = os.getComputerID() }, SHA.compute(password))) local data = socket:read(2) socket:close() diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index b08d09a..3b3569a 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -2,7 +2,7 @@ -- By Anavrins local sha2 = require('opus.crypto.sha2') -local util = require('opus.util') +local Util = require('opus.util') local ROUNDS = 20 -- Adjust this for speed tradeoff @@ -115,7 +115,7 @@ local function crypt(data, key, nonce, cntr, round) cntr = tonumber(cntr) or 1 round = tonumber(round) or 20 - local throttle = util.throttle() + local throttle = Util.throttle() local out = {} local state = initState(key, nonce, cntr) local blockAmt = math.floor(#data/64) @@ -157,8 +157,8 @@ local function encrypt(data, key) end local function decrypt(data, key) - local nonce = util.hexToByteArray(data[1]) - data = util.hexToByteArray(data[2]) + local nonce = Util.hexToByteArray(data[1]) + data = Util.hexToByteArray(data[2]) key = sha2.digest(key) local ptx = crypt(data, key, nonce, 1, ROUNDS) return textutils.unserialise(tostring(ptx)) diff --git a/sys/modules/opus/crypto/ecc/elliptic.lua b/sys/modules/opus/crypto/ecc/elliptic.lua index 4177258..9af2683 100644 --- a/sys/modules/opus/crypto/ecc/elliptic.lua +++ b/sys/modules/opus/crypto/ecc/elliptic.lua @@ -22,6 +22,8 @@ -- Indistinguishability? No: The curve does not support indistinguishability maps. local fp = require('opus.crypto.ecc.fp') +local Util = require('opus.util') + local eq = fp.eq local mul = fp.mul local sqr = fp.sqr @@ -31,6 +33,7 @@ local shr = fp.shr local mont = fp.mont local invMont = fp.invMont local sub192 = fp.sub192 +local unpack = table.unpack local bits = 192 local pMinusTwoBinary = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} @@ -203,20 +206,23 @@ local function scalarMul(s, P1) end local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}} - for i = #naf, 1, -1 do + for i = #naf, 1, -1 do -- can this loop be optimized ? + local n = naf[i] Q = pointDouble(Q) - if naf[i] > 0 then - Q = pointAdd(Q, PTable[naf[i]]) - elseif naf[i] < 0 then - Q = pointSub(Q, PTable[-naf[i]]) + if n > 0 then + Q = pointAdd(Q, PTable[n]) + elseif n < 0 then + Q = pointSub(Q, PTable[-n]) end end return Q end +local throttle = Util.throttle() for i = 2, 196 do GTable[i] = pointDouble(GTable[i - 1]) + throttle() end local function scalarMulG(s) diff --git a/sys/modules/opus/crypto/ecc/fp.lua b/sys/modules/opus/crypto/ecc/fp.lua index 3a8c4c6..9e791bd 100644 --- a/sys/modules/opus/crypto/ecc/fp.lua +++ b/sys/modules/opus/crypto/ecc/fp.lua @@ -1,5 +1,7 @@ -- Fp Integer Arithmetic +local unpack = table.unpack + local n = 0xffff local m = 0x10000 diff --git a/sys/modules/opus/crypto/ecc/fq.lua b/sys/modules/opus/crypto/ecc/fq.lua index 277f64d..c552688 100644 --- a/sys/modules/opus/crypto/ecc/fq.lua +++ b/sys/modules/opus/crypto/ecc/fq.lua @@ -1,5 +1,7 @@ -- Fq Integer Arithmetic +local unpack = table.unpack + local n = 0xffff local m = 0x10000 diff --git a/sys/modules/opus/crypto/ecc/init.lua b/sys/modules/opus/crypto/ecc/init.lua index e1c1284..980f699 100644 --- a/sys/modules/opus/crypto/ecc/init.lua +++ b/sys/modules/opus/crypto/ecc/init.lua @@ -3,6 +3,7 @@ local elliptic = require('opus.crypto.ecc.elliptic') local sha256 = require('opus.crypto.sha2') local os = _G.os +local unpack = table.unpack local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532} diff --git a/sys/modules/opus/crypto/sha2.lua b/sys/modules/opus/crypto/sha2.lua index 631488a..2754ee7 100644 --- a/sys/modules/opus/crypto/sha2.lua +++ b/sys/modules/opus/crypto/sha2.lua @@ -1,8 +1,8 @@ -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft -- By Anavrins +local Util = require('opus.util') local bit = _G.bit -local os = _G.os local mod32 = 2^32 local band = bit32 and bit32.band or bit.band local bnot = bit32 and bit32.bnot or bit.bnot @@ -162,25 +162,13 @@ local function hmac(data, key) return digest(padded_key) end -local function throttler() - local ts = os.clock() - local timeout = .095 - return function() - local nts = os.clock() - if nts > ts + timeout then - os.sleep(0) - ts = os.clock() - end - end -end - local function pbkdf2(pass, salt, iter, dklen) salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)} local hashlen = 32 dklen = dklen or 32 local block = 1 local out = {} - local throttle = throttler() + local throttle = Util.throttle() while dklen > 0 do local ikey = {} diff --git a/sys/modules/opus/security.lua b/sys/modules/opus/security.lua index a44605c..599f793 100644 --- a/sys/modules/opus/security.lua +++ b/sys/modules/opus/security.lua @@ -1,6 +1,6 @@ local Config = require('opus.config') -local Util = require('opus.util') local ECC = require('opus.crypto.ecc') +local Util = require('opus.util') local Security = { } @@ -21,16 +21,6 @@ local function genKey() return table.concat(key) end -function Security.generateKeyPair() - local privateKey = Util.hexToByteArray(genKey()) - return privateKey, ECC.publicKey(privateKey) -end - -function Security.getIdentifier() - return Security.getPublicKey() -end - --- deprecate - will use getIdentifier function Security.getSecretKey() local config = Config.load('os') if not config.secretKey then @@ -40,9 +30,17 @@ function Security.getSecretKey() return Util.hexToByteArray(config.secretKey) end -function Security.getPublicKey() - local secretKey = Security.getSecretKey() - return ECC.publicKey(secretKey) +function Security.getIdentifier() + local config = Config.load('os') + if config.identifier then + return config.identifier + end + -- preserve the hash the user generated + local identifier = ECC.publicKey(Security.getSecretKey()) + config.identifier = Util.byteArrayToHex(identifier) + Config.update('os', config) + + return config.identifier end function Security.updatePassword(password) diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index bb3b6ef..721f8e4 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -6,11 +6,12 @@ local Util = require('opus.util') local device = _G.device local os = _G.os +local network = _G.network local socketClass = { } function socketClass:read(timeout) - local data, distance = _G.transport.read(self) + local data, distance = network.getTransport().read(self) if data then return data, distance end @@ -25,7 +26,7 @@ function socketClass:read(timeout) local e, id = os.pullEvent() if e == 'transport_' .. self.uid then - data, distance = _G.transport.read(self) + data, distance = network.getTransport().read(self) if data then os.cancelTimer(timerId) return data, distance @@ -46,7 +47,7 @@ end function socketClass:write(data) if self.connected then - _G.transport.write(self, { + network.getTransport().write(self, { type = 'DATA', seq = self.wseq, data = data, @@ -57,30 +58,31 @@ end function socketClass:ping() if self.connected then - _G.transport.ping(self) + network.getTransport().ping(self) return true end end -function socketClass:setupEncryption() - if false then +function socketClass:setupEncryption(x) +local timer = Util.timer() self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey) self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) - self.rseed = SHA.pbkdf2(self.sharedKey, "3rseed", 1) - self.wseed = SHA.pbkdf2(self.sharedKey, "4sseed", 1) - end + self.rseq = SHA.pbkdf2(self.sharedKey, x and "3rseed" or "4sseed", 1):toHex() + self.wseq = SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1):toHex() +_syslog('shared in ' .. timer()) end function socketClass:close() if self.connected then self.transmit(self.dport, self.dhost, { type = 'DISC', + seq = self.wseq, }) self.connected = false end device.wireless_modem.close(self.sport) - _G.transport.close(self) + network.getTransport().close(self) end local Socket = { } @@ -115,27 +117,24 @@ local function newSocket(isLoopback) error('No ports available') end -function Socket.connect(host, port) +function Socket.connect(host, port, options) if not device.wireless_modem then return false, 'Wireless modem not found', 'NOMODEM' end - +local timer = Util.timer() local socket = newSocket(host == os.getComputerID()) socket.dhost = tonumber(host) - socket.privKey, socket.pubKey = Security.generateKeyPair() + socket.privKey, socket.pubKey = network.getKeyPair() + local identifier = options and options.identifier or Security.getIdentifier() socket.transmit(port, socket.sport, { type = 'OPEN', shost = socket.shost, dhost = socket.dhost, - rseq = socket.wseq, - wseq = socket.rseq, - t = Crypto.encrypt({ - ts = os.time(), - seq = socket.seq, - nts = os.epoch('utc'), + t = Crypto.encrypt({ -- this is not that much data... + ts = os.epoch('utc'), pk = Util.byteArrayToHex(socket.pubKey), - }, Security.getPublicKey()), + }, Util.hexToByteArray(identifier)), }) local timerId = os.startTimer(3) @@ -152,10 +151,11 @@ function Socket.connect(host, port) socket.dport = dport socket.connected = true socket.remotePubKey = Util.hexToByteArray(msg.pk) - socket:setupEncryption() + socket:setupEncryption(true) -- Logger.log('socket', 'connection established to %d %d->%d', -- host, socket.sport, socket.dport) - _G.transport.open(socket) + network.getTransport().open(socket) +_syslog('connection in ' .. timer()) return socket elseif msg.type == 'NOPASS' then @@ -173,35 +173,30 @@ function Socket.connect(host, port) return false, 'Connection timed out', 'TIMEOUT' end -local function trusted(socket, msg, port) - if port == 19 or msg.shost == os.getComputerID() then - -- no auth for trust server or loopback - return true +local function trusted(socket, msg, options) + local function getIdentifier() + local trustList = Util.readTable('usr/.known_hosts') or { } + return trustList[msg.shost] end - if not Security.hasPassword() then - -- no password has been set on this computer - --return true - end + local identifier = options and options.identifier or getIdentifier() - local trustList = Util.readTable('usr/.known_hosts') or { } - local pubKey = trustList[msg.shost] + if identifier and msg.t and type(msg.t) == 'table' then + local data = Crypto.decrypt(msg.t, Util.hexToByteArray(identifier)) - if pubKey and msg.t then - local data = Crypto.decrypt(msg.t, Util.hexToByteArray(pubKey)) - - if data and data.nts then -- upgraded security - if data.nts and tonumber(data.nts) and math.abs(os.epoch('utc') - data.nts) < 1024 then + if data and data.ts and tonumber(data.ts) then +_G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts)) + if math.abs(os.epoch('utc') - data.ts) < 4096 then socket.remotePubKey = Util.hexToByteArray(data.pk) + socket.privKey, socket.pubKey = network.getKeyPair() + socket:setupEncryption() + return true end end - - --local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod) - return data and data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 24 end end -function Socket.server(port) +function Socket.server(port, options) device.wireless_modem.open(port) -- Logger.log('socket', 'Waiting for connections on port ' .. port) @@ -219,6 +214,7 @@ function Socket.server(port) socket.dhost = msg.shost socket.wseq = msg.wseq socket.rseq = msg.rseq + socket.options = options if not Security.hasPassword() then socket.transmit(socket.dport, socket.sport, { @@ -228,10 +224,8 @@ function Socket.server(port) }) socket:close() - elseif trusted(socket, msg, port) then + elseif trusted(socket, msg, options) then socket.connected = true - socket.privKey, socket.pubKey = Security.generateKeyPair() - socket:setupEncryption() socket.transmit(socket.dport, socket.sport, { type = 'CONN', dhost = socket.dhost, @@ -241,7 +235,7 @@ function Socket.server(port) -- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport) - _G.transport.open(socket) + network.getTransport().open(socket) return socket else diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index 271fcfd..9e2d63d 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -20,6 +20,7 @@ function Util.hexToByteArray(str) end function Util.byteArrayToHex(tbl) + if not tbl then error('byteArrayToHex: invalid table', 2) end return ("%02x"):rep(#tbl):format(unpack(tbl)) end From 1c291979835ab976298c3d9f41dcffc2f4a317a2 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Jun 2019 22:02:00 -0400 Subject: [PATCH 162/231] security - final round? --- sys/apps/network/transport.lua | 6 ++--- sys/modules/opus/crypto/chacha20.lua | 31 ++++++++++++++++++++++++- sys/modules/opus/socket.lua | 34 ++++++++++++---------------- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/sys/apps/network/transport.lua b/sys/apps/network/transport.lua index 316f46a..3858383 100644 --- a/sys/apps/network/transport.lua +++ b/sys/apps/network/transport.lua @@ -6,7 +6,6 @@ ]]-- local Event = require('opus.event') -local SHA = require('opus.crypto.sha2') local network = _G.network local os = _G.os @@ -39,7 +38,7 @@ end function transport.write(socket, data) socket.transmit(socket.dport, socket.dhost, data) - socket.wseq = SHA.digest(socket.wseq):toHex() + socket.wseq = socket.wrng:nextInt(5) end function transport.ping(socket) @@ -113,7 +112,8 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) _syslog('got ' .. msg.seq) else socket.activityTimer = os.clock() - socket.rseq = SHA.digest(socket.rseq):toHex() + socket.rseq = socket.rrng:nextInt(5) + table.insert(socket.messages, { msg.data, distance }) if not socket.messages[2] then -- table size is 1 diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index 3b3569a..c99a854 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -10,12 +10,13 @@ local bxor = bit32.bxor local band = bit32.band local blshift = bit32.lshift local brshift = bit32.arshift -local os = _G.os local textutils = _G.textutils local mod = 2^32 local tau = {("expand 16-byte k"):byte(1,-1)} local sigma = {("expand 32-byte k"):byte(1,-1)} +local null32 = {("A"):rep(32):byte(1,-1)} +local null12 = {("A"):rep(12):byte(1,-1)} local function rotl(n, b) local s = n/(2^(32-b)) @@ -164,7 +165,35 @@ local function decrypt(data, key) return textutils.unserialise(tostring(ptx)) end +local obj = {} +local mt = {['__index'] = obj} + +function obj:nextInt(byte) + if byte < 1 or byte > 6 then error("Can only return 1-6 bytes", 2) end + local output = 0 + for i = 0, byte-1 do + if #self.block == 0 then + self.cnt = self.cnt + 1 + self.block = crypt(null32, self.seed, null12, self.cnt) + end + + local newByte = table.remove(self.block) + output = output + (newByte * (2^(8*i))) + end + return output +end + +local function newRNG(seed) + local o = {} + o.seed = seed + o.cnt = 0 + o.block = {} + + return setmetatable(o, mt) +end + return { encrypt = encrypt, decrypt = decrypt, + newRNG = newRNG, } diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index 721f8e4..c1518fb 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -64,13 +64,16 @@ function socketClass:ping() end function socketClass:setupEncryption(x) -local timer = Util.timer() + self.rrng = Crypto.newRNG( + SHA.pbkdf2(self.sharedKey, x and "3rseed" or "4sseed", 1)) + self.wrng = Crypto.newRNG( + SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1)) + self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey) - self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) - self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) - self.rseq = SHA.pbkdf2(self.sharedKey, x and "3rseed" or "4sseed", 1):toHex() - self.wseq = SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1):toHex() -_syslog('shared in ' .. timer()) + --self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) + --self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) + self.rseq = self.rrng:nextInt(5) + self.wseq = self.wrng:nextInt(5) end function socketClass:close() @@ -99,8 +102,6 @@ local function newSocket(isLoopback) shost = os.getComputerID(), sport = i, transmit = device.wireless_modem.transmit, - wseq = math.random(100, 100000), - rseq = math.random(100, 100000), timers = { }, messages = { }, } @@ -121,7 +122,7 @@ function Socket.connect(host, port, options) if not device.wireless_modem then return false, 'Wireless modem not found', 'NOMODEM' end -local timer = Util.timer() + local socket = newSocket(host == os.getComputerID()) socket.dhost = tonumber(host) socket.privKey, socket.pubKey = network.getKeyPair() @@ -143,7 +144,8 @@ local timer = Util.timer() if e == 'modem_message' and sport == socket.sport and type(msg) == 'table' and - msg.dhost == socket.shost then + msg.dhost == socket.shost and + type(msg.pk) == 'string' then os.cancelTimer(timerId) @@ -152,10 +154,7 @@ local timer = Util.timer() socket.connected = true socket.remotePubKey = Util.hexToByteArray(msg.pk) socket:setupEncryption(true) - -- Logger.log('socket', 'connection established to %d %d->%d', - -- host, socket.sport, socket.dport) network.getTransport().open(socket) -_syslog('connection in ' .. timer()) return socket elseif msg.type == 'NOPASS' then @@ -181,24 +180,23 @@ local function trusted(socket, msg, options) local identifier = options and options.identifier or getIdentifier() - if identifier and msg.t and type(msg.t) == 'table' then + if identifier and type(msg.t) == 'table' then local data = Crypto.decrypt(msg.t, Util.hexToByteArray(identifier)) if data and data.ts and tonumber(data.ts) then -_G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts)) if math.abs(os.epoch('utc') - data.ts) < 4096 then socket.remotePubKey = Util.hexToByteArray(data.pk) socket.privKey, socket.pubKey = network.getKeyPair() socket:setupEncryption() return true end + _G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts)) end end end function Socket.server(port, options) device.wireless_modem.open(port) - -- Logger.log('socket', 'Waiting for connections on port ' .. port) while true do local _, _, sport, dport, msg = os.pullEvent('modem_message') @@ -212,8 +210,6 @@ function Socket.server(port, options) local socket = newSocket(msg.shost == os.getComputerID()) socket.dport = dport socket.dhost = msg.shost - socket.wseq = msg.wseq - socket.rseq = msg.rseq socket.options = options if not Security.hasPassword() then @@ -233,8 +229,6 @@ function Socket.server(port, options) pk = Util.byteArrayToHex(socket.pubKey), }) - -- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport) - network.getTransport().open(socket) return socket From 67779ab81409ed7054bb31461e7a3361e40d71c0 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 29 Jun 2019 23:43:21 -0400 Subject: [PATCH 163/231] secure telnet --- sys/apps/network/telnet.lua | 23 ++++++++++++++++--- sys/apps/network/transport.lua | 8 +++++-- sys/apps/telnet.lua | 7 +++--- sys/modules/opus/crypto/chacha20.lua | 6 ++--- sys/modules/opus/security.lua | 34 ++++++++-------------------- sys/modules/opus/socket.lua | 14 ++++++++---- 6 files changed, 51 insertions(+), 41 deletions(-) diff --git a/sys/apps/network/telnet.lua b/sys/apps/network/telnet.lua index dc2bda0..8bd11de 100644 --- a/sys/apps/network/telnet.lua +++ b/sys/apps/network/telnet.lua @@ -6,7 +6,7 @@ local kernel = _G.kernel local term = _G.term local window = _G.window -local function telnetHost(socket) +local function telnetHost(socket, mode) local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit', 'setTextColor', 'setTextColour', 'setBackgroundColor', 'setBackgroundColour', 'scroll', 'setCursorBlink', } @@ -43,7 +43,7 @@ local function telnetHost(socket) local shellThread = kernel.run({ terminal = win, window = win, - title = 'Telnet client', + title = mode .. ' client', hidden = true, co = coroutine.create(function() Util.run(_ENV, 'sys/apps/shell.lua', table.unpack(termInfo.program)) @@ -68,6 +68,23 @@ local function telnetHost(socket) end) end +Event.addRoutine(function() + print('ssh: listening on port 22') + while true do + local socket = Socket.server(22, { ENCRYPT = true }) + + print('ssh: connection from ' .. socket.dhost) + + Event.addRoutine(function() + local s, m = pcall(telnetHost, socket, 'SSH') + if not s and m then + print('ssh error') + _G.printError(m) + end + end) + end +end) + Event.addRoutine(function() print('telnet: listening on port 23') while true do @@ -76,7 +93,7 @@ Event.addRoutine(function() print('telnet: connection from ' .. socket.dhost) Event.addRoutine(function() - local s, m = pcall(telnetHost, socket) + local s, m = pcall(telnetHost, socket, 'Telnet') if not s and m then print('Telnet error') _G.printError(m) diff --git a/sys/apps/network/transport.lua b/sys/apps/network/transport.lua index 3858383..9717e4e 100644 --- a/sys/apps/network/transport.lua +++ b/sys/apps/network/transport.lua @@ -5,7 +5,8 @@ * background read buffering ]]-- -local Event = require('opus.event') +local Crypto = require('opus.crypto.chacha20') +local Event = require('opus.event') local network = _G.network local os = _G.os @@ -32,7 +33,10 @@ end function transport.read(socket) local data = table.remove(socket.messages, 1) if data then - return unpack(data) + if socket.options.ENCRYPT then + return table.unpack(Crypto.decrypt(data[1], socket.enckey)), data[2] + end + return table.unpack(data) end end diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 91b163e..ab9f024 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -9,7 +9,7 @@ local read = _G.read local shell = _ENV.shell local term = _G.term -local args = { ... } +local args, options = Util.parse(...) local remoteId = tonumber(table.remove(args, 1) or '') if not remoteId then @@ -22,13 +22,14 @@ if not remoteId then end if multishell then - multishell.setTitle(multishell.getCurrent(), 'Telnet ' .. remoteId) + multishell.setTitle(multishell.getCurrent(), + (options.s and 'Secure ' or 'Telnet ') .. remoteId) end local socket, msg, reason while true do - socket, msg, reason = Socket.connect(remoteId, 23) + socket, msg, reason = Socket.connect(remoteId, options.s and 22 or 23) if socket then break diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index c99a854..f28f8dc 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -166,10 +166,10 @@ local function decrypt(data, key) end local obj = {} -local mt = {['__index'] = obj} +local rng_mt = {['__index'] = obj} function obj:nextInt(byte) - if byte < 1 or byte > 6 then error("Can only return 1-6 bytes", 2) end + if not byte or byte < 1 or byte > 6 then error("Can only return 1-6 bytes", 2) end local output = 0 for i = 0, byte-1 do if #self.block == 0 then @@ -189,7 +189,7 @@ local function newRNG(seed) o.cnt = 0 o.block = {} - return setmetatable(o, mt) + return setmetatable(o, rng_mt) end return { diff --git a/sys/modules/opus/security.lua b/sys/modules/opus/security.lua index 599f793..4fb6f8d 100644 --- a/sys/modules/opus/security.lua +++ b/sys/modules/opus/security.lua @@ -1,6 +1,4 @@ local Config = require('opus.config') -local ECC = require('opus.crypto.ecc') -local Util = require('opus.util') local Security = { } @@ -13,32 +11,18 @@ function Security.hasPassword() return not not Security.getPassword() end -local function genKey() - local key = { } - for _ = 1, 32 do - table.insert(key, ("%02x"):format(math.random(0, 0xFF))) - end - return table.concat(key) -end - -function Security.getSecretKey() - local config = Config.load('os') - if not config.secretKey then - config.secretKey = genKey() - Config.update('os', config) - end - return Util.hexToByteArray(config.secretKey) -end - function Security.getIdentifier() local config = Config.load('os') - if config.identifier then - return config.identifier + + if not config.identifier then + local key = { } + for _ = 1, 32 do + table.insert(key, ("%02x"):format(math.random(0, 0xFF))) + end + config.identifier = table.concat(key) + + Config.update('os', config) end - -- preserve the hash the user generated - local identifier = ECC.publicKey(Security.getSecretKey()) - config.identifier = Util.byteArrayToHex(identifier) - Config.update('os', config) return config.identifier end diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index c1518fb..9f77f99 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -47,6 +47,9 @@ end function socketClass:write(data) if self.connected then + if self.options.ENCRYPT then + data = Crypto.encrypt({ data }, self.enckey) + end network.getTransport().write(self, { type = 'DATA', seq = self.wseq, @@ -70,7 +73,7 @@ function socketClass:setupEncryption(x) SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1)) self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey) - --self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) + self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) --self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) self.rseq = self.rrng:nextInt(5) self.wseq = self.wrng:nextInt(5) @@ -144,15 +147,15 @@ function Socket.connect(host, port, options) if e == 'modem_message' and sport == socket.sport and type(msg) == 'table' and - msg.dhost == socket.shost and - type(msg.pk) == 'string' then + msg.dhost == socket.shost then os.cancelTimer(timerId) - if msg.type == 'CONN' then + if msg.type == 'CONN' and type(msg.pk) == 'string' then socket.dport = dport socket.connected = true socket.remotePubKey = Util.hexToByteArray(msg.pk) + socket.options = msg.options or { } socket:setupEncryption(true) network.getTransport().open(socket) return socket @@ -210,7 +213,7 @@ function Socket.server(port, options) local socket = newSocket(msg.shost == os.getComputerID()) socket.dport = dport socket.dhost = msg.shost - socket.options = options + socket.options = options or { } if not Security.hasPassword() then socket.transmit(socket.dport, socket.sport, { @@ -227,6 +230,7 @@ function Socket.server(port, options) dhost = socket.dhost, shost = socket.shost, pk = Util.byteArrayToHex(socket.pubKey), + options = socket.options.ENCRYPT and { ENCRYPT = true }, }) network.getTransport().open(socket) From 721cd840b36bc6f8d60736b4975e23717c3532eb Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Jun 2019 14:47:45 -0400 Subject: [PATCH 164/231] encrypt improvements --- sys/apps/network/transport.lua | 27 +++- sys/modules/opus/crypto/chacha20.lua | 13 +- sys/modules/opus/crypto/lualzw.lua | 164 +++++++++++++++++++++++++ sys/modules/opus/crypto/serializer.lua | 50 ++++++++ sys/modules/opus/socket.lua | 33 +++-- sys/modules/opus/util.lua | 2 +- 6 files changed, 262 insertions(+), 27 deletions(-) create mode 100644 sys/modules/opus/crypto/lualzw.lua create mode 100644 sys/modules/opus/crypto/serializer.lua diff --git a/sys/apps/network/transport.lua b/sys/apps/network/transport.lua index 9717e4e..2732d12 100644 --- a/sys/apps/network/transport.lua +++ b/sys/apps/network/transport.lua @@ -15,6 +15,7 @@ local computerId = os.getComputerID() local transport = { timers = { }, sockets = { }, + encryptQueue = { }, UID = 0, } @@ -40,8 +41,15 @@ function transport.read(socket) end end -function transport.write(socket, data) - socket.transmit(socket.dport, socket.dhost, data) +function transport.write(socket, msg) + if socket.options.ENCRYPT then + if #transport.encryptQueue == 0 then + os.queueEvent('transport_encrypt') + end + table.insert(transport.encryptQueue, { socket.sport, msg }) + else + socket.transmit(socket.dport, socket.dhost, msg) + end socket.wseq = socket.wrng:nextInt(5) end @@ -63,6 +71,19 @@ function transport.close(socket) transport.sockets[socket.sport] = nil end +Event.on('transport_encrypt', function() + while #transport.encryptQueue > 0 do + local entry = table.remove(transport.encryptQueue, 1) + local socket = transport.sockets[entry[1]] + + if socket and socket.connected then + local msg = entry[2] + msg.data = Crypto.encrypt({ msg.data }, socket.enckey) + socket.transmit(socket.dport, socket.dhost, msg) + end + end +end) + Event.on('timer', function(_, timerId) local socket = transport.timers[timerId] @@ -110,7 +131,7 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance) elseif msg.type == 'DATA' and msg.data then if msg.seq ~= socket.rseq then - print('transport seq error - closing socket ' .. socket.sport) + print('transport seq error ' .. socket.sport) _syslog(msg.data) _syslog('expected ' .. socket.rseq) _syslog('got ' .. msg.seq) diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index f28f8dc..c82763f 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -1,7 +1,9 @@ -- Chacha20 cipher in ComputerCraft -- By Anavrins +local LZW = require('opus.crypto.lualzw') local sha2 = require('opus.crypto.sha2') +local Serializer = require('opus.crypto.serializer') local Util = require('opus.util') local ROUNDS = 20 -- Adjust this for speed tradeoff @@ -116,7 +118,7 @@ local function crypt(data, key, nonce, cntr, round) cntr = tonumber(cntr) or 1 round = tonumber(round) or 20 - local throttle = Util.throttle() + local throttle = Util.throttle(function() _syslog('throttle') end) local out = {} local state = initState(key, nonce, cntr) local blockAmt = math.floor(#data/64) @@ -132,11 +134,11 @@ local function crypt(data, key, nonce, cntr, round) out[#out+1] = bxor(block[j], ks[j]) end - if i % 1000 == 0 then + --if i % 1000 == 0 then throttle() --os.queueEvent("") --os.pullEvent("") - end + --end end return setmetatable(out, mt) end @@ -151,7 +153,8 @@ end local function encrypt(data, key) local nonce = genNonce(12) - data = textutils.serialise(data) + data = Serializer.serialize(data) + data = LZW.compress(data) key = sha2.digest(key) local ctx = crypt(data, key, nonce, 1, ROUNDS) return { nonce:toHex(), ctx:toHex() } @@ -162,7 +165,7 @@ local function decrypt(data, key) data = Util.hexToByteArray(data[2]) key = sha2.digest(key) local ptx = crypt(data, key, nonce, 1, ROUNDS) - return textutils.unserialise(tostring(ptx)) + return textutils.unserialise(LZW.decompress(tostring(ptx))) end local obj = {} diff --git a/sys/modules/opus/crypto/lualzw.lua b/sys/modules/opus/crypto/lualzw.lua new file mode 100644 index 0000000..7bdfa21 --- /dev/null +++ b/sys/modules/opus/crypto/lualzw.lua @@ -0,0 +1,164 @@ +-- see: https://github.com/Rochet2/lualzw +--[[ +MIT License + +Copyright (c) 2016 Rochet2 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] + +local char = string.char +local type = type +local sub = string.sub +local tconcat = table.concat + +local basedictcompress = {} +local basedictdecompress = {} +for i = 0, 255 do + local ic, iic = char(i), char(i, 0) + basedictcompress[ic] = iic + basedictdecompress[iic] = ic +end + +local function dictAddA(str, dict, a, b) + if a >= 256 then + a, b = 0, b+1 + if b >= 256 then + dict = {} + b = 1 + end + end + dict[str] = char(a,b) + a = a+1 + return dict, a, b +end + +local function compress(input) + if type(input) ~= "string" then + error ("string expected, got "..type(input)) + end + local len = #input + if len <= 1 then + return "u"..input + end + + local dict = {} + local a, b = 0, 1 + + local result = {"c"} + local resultlen = 1 + local n = 2 + local word = "" + for i = 1, len do + local c = sub(input, i, i) + local wc = word..c + if not (basedictcompress[wc] or dict[wc]) then + local write = basedictcompress[word] or dict[word] + if not write then + error "algorithm error, could not fetch word" + end + result[n] = write + resultlen = resultlen + #write + n = n+1 + if len <= resultlen then + return "u"..input + end + dict, a, b = dictAddA(wc, dict, a, b) + word = c + else + word = wc + end + end + result[n] = basedictcompress[word] or dict[word] + resultlen = resultlen+#result[n] + if len <= resultlen then + return "u"..input + end + return tconcat(result) +end + +local function dictAddB(str, dict, a, b) + if a >= 256 then + a, b = 0, b+1 + if b >= 256 then + dict = {} + b = 1 + end + end + dict[char(a,b)] = str + a = a+1 + return dict, a, b +end + +local function decompress(input) + if type(input) ~= "string" then + error( "string expected, got "..type(input)) + end + + if #input < 1 then + error("invalid input - not a compressed string") + end + + local control = sub(input, 1, 1) + if control == "u" then + return sub(input, 2) + elseif control ~= "c" then + error( "invalid input - not a compressed string") + end + input = sub(input, 2) + local len = #input + + if len < 2 then + error( "invalid input - not a compressed string") + end + + local dict = {} + local a, b = 0, 1 + + local result = {} + local n = 1 + local last = sub(input, 1, 2) + result[n] = basedictdecompress[last] or dict[last] + n = n+1 + for i = 3, len, 2 do + local code = sub(input, i, i+1) + local lastStr = basedictdecompress[last] or dict[last] + if not lastStr then + error( "could not find last from dict. Invalid input?") + end + local toAdd = basedictdecompress[code] or dict[code] + if toAdd then + result[n] = toAdd + n = n+1 + dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) + else + local tmp = lastStr..sub(lastStr, 1, 1) + result[n] = tmp + n = n+1 + dict, a, b = dictAddB(tmp, dict, a, b) + end + last = code + end + return tconcat(result) +end + +return { + compress = compress, + decompress = decompress, +} \ No newline at end of file diff --git a/sys/modules/opus/crypto/serializer.lua b/sys/modules/opus/crypto/serializer.lua new file mode 100644 index 0000000..db19336 --- /dev/null +++ b/sys/modules/opus/crypto/serializer.lua @@ -0,0 +1,50 @@ +local Serializer = { } + +local insert = table.insert +local format = string.format + +function Serializer.serialize(tbl) + local output = { } + + local function recurse(t) + local sType = type(t) + if sType == 'table' then + if next(t) == nil then + insert(output, '{}') + else + insert(output, '{') + local tSeen = {} + for k, v in ipairs(t) do + tSeen[k] = true + recurse(v) + insert(output, ',') + end + for k, v in pairs(t) do + if not tSeen[k] then + if type(k) == 'string' and string.match(k, '^[%a_][%a%d_]*$') then + insert(output, k .. '=') + recurse(v) + insert(output, ',') + else + insert(output, '[') + recurse(k) + insert(output, ']=') + recurse(v) + insert(output, ',') + end + end + end + insert(output, '}') + end + elseif sType == 'string' then + insert(output, format('%q', t)) + else + insert(output, tostring(t)) + end + end + + recurse(tbl) + return table.concat(output) +end + +return Serializer diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index 9f77f99..3eadac7 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -47,9 +47,6 @@ end function socketClass:write(data) if self.connected then - if self.options.ENCRYPT then - data = Crypto.encrypt({ data }, self.enckey) - end network.getTransport().write(self, { type = 'DATA', seq = self.wseq, @@ -66,19 +63,6 @@ function socketClass:ping() end end -function socketClass:setupEncryption(x) - self.rrng = Crypto.newRNG( - SHA.pbkdf2(self.sharedKey, x and "3rseed" or "4sseed", 1)) - self.wrng = Crypto.newRNG( - SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1)) - - self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey) - self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1) - --self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) - self.rseq = self.rrng:nextInt(5) - self.wseq = self.wrng:nextInt(5) -end - function socketClass:close() if self.connected then self.transmit(self.dport, self.dhost, { @@ -121,6 +105,19 @@ local function newSocket(isLoopback) error('No ports available') end +local function setupCrypto(socket, isClient) + socket.rrng = Crypto.newRNG( + SHA.pbkdf2(socket.sharedKey, isClient and "3rseed" or "4sseed", 1)) + socket.wrng = Crypto.newRNG( + SHA.pbkdf2(socket.sharedKey, isClient and "4sseed" or "3rseed", 1)) + + socket.sharedKey = ECC.exchange(socket.privKey, socket.remotePubKey) + socket.enckey = SHA.pbkdf2(socket.sharedKey, "1enc", 1) + --self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) + socket.rseq = socket.rrng:nextInt(5) + socket.wseq = socket.wrng:nextInt(5) +end + function Socket.connect(host, port, options) if not device.wireless_modem then return false, 'Wireless modem not found', 'NOMODEM' @@ -156,7 +153,7 @@ function Socket.connect(host, port, options) socket.connected = true socket.remotePubKey = Util.hexToByteArray(msg.pk) socket.options = msg.options or { } - socket:setupEncryption(true) + setupCrypto(socket, true) network.getTransport().open(socket) return socket @@ -190,7 +187,7 @@ local function trusted(socket, msg, options) if math.abs(os.epoch('utc') - data.ts) < 4096 then socket.remotePubKey = Util.hexToByteArray(data.pk) socket.privKey, socket.pubKey = network.getKeyPair() - socket:setupEncryption() + setupCrypto(socket) return true end _G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts)) diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index 9e2d63d..e670857 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -56,7 +56,7 @@ Util.Timer = Util.timer -- deprecate function Util.throttle(fn) local ts = os.clock() - local timeout = .095 + local timeout = .295 return function(...) local nts = os.clock() if nts > ts + timeout then From 86e918667cfdcbc5ee062307a773673e1b6a18d8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Jun 2019 17:20:55 -0400 Subject: [PATCH 165/231] encrypt optimization --- sys/modules/opus/crypto/cbor.lua | 581 +++++++++++++++++++++++++++ sys/modules/opus/crypto/chacha20.lua | 2 +- 2 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 sys/modules/opus/crypto/cbor.lua diff --git a/sys/modules/opus/crypto/cbor.lua b/sys/modules/opus/crypto/cbor.lua new file mode 100644 index 0000000..a55df44 --- /dev/null +++ b/sys/modules/opus/crypto/cbor.lua @@ -0,0 +1,581 @@ +-- Concise Binary Object Representation (CBOR) +-- RFC 7049 + +local function softreq(pkg, field) + local ok, mod = pcall(require, pkg); + if not ok then return end + if field then return mod[field]; end + return mod; +end +local dostring = function (s) + local ok, f = pcall(loadstring or load, s); -- luacheck: read globals loadstring + if ok and f then return f(); end +end + +local setmetatable = setmetatable; +local getmetatable = getmetatable; +local dbg_getmetatable = debug.getmetatable; +local assert = assert; +local error = error; +local type = type; +local pairs = pairs; +local ipairs = ipairs; +local tostring = tostring; +local s_char = string.char; +local t_concat = table.concat; +local t_sort = table.sort; +local m_floor = math.floor; +local m_abs = math.abs; +local m_huge = math.huge; +local m_max = math.max; +local maxint = math.maxinteger or 9007199254740992; +local minint = math.mininteger or -9007199254740992; +local NaN = 0/0; +local m_frexp = math.frexp; +local m_ldexp = math.ldexp or function (x, exp) return x * 2.0 ^ exp; end; +local m_type = math.type or function (n) return n % 1 == 0 and n <= maxint and n >= minint and "integer" or "float" end; +local s_pack = string.pack or softreq("struct", "pack"); +local s_unpack = string.unpack or softreq("struct", "unpack"); +local b_rshift = softreq("bit32", "rshift") or softreq("bit", "rshift") or + dostring "return function(a,b) return a >> b end" or + function (a, b) return m_max(0, m_floor(a / (2 ^ b))); end; + +-- sanity check +if s_pack and s_pack(">I2", 0) ~= "\0\0" then + s_pack = nil; +end +if s_unpack and s_unpack(">I2", "\1\2\3\4") ~= 0x102 then + s_unpack = nil; +end + +local _ENV = nil; -- luacheck: ignore 211 + +local encoder = {}; + +local function encode(obj, opts) + return encoder[type(obj)](obj, opts); +end + +-- Major types 0, 1 and length encoding for others +local function integer(num, m) + if m == 0 and num < 0 then + -- negative integer, major type 1 + num, m = - num - 1, 32; + end + if num < 24 then + return s_char(m + num); + elseif num < 2 ^ 8 then + return s_char(m + 24, num); + elseif num < 2 ^ 16 then + return s_char(m + 25, b_rshift(num, 8), num % 0x100); + elseif num < 2 ^ 32 then + return s_char(m + 26, + b_rshift(num, 24) % 0x100, + b_rshift(num, 16) % 0x100, + b_rshift(num, 8) % 0x100, + num % 0x100); + elseif num < 2 ^ 64 then + local high = m_floor(num / 2 ^ 32); + num = num % 2 ^ 32; + return s_char(m + 27, + b_rshift(high, 24) % 0x100, + b_rshift(high, 16) % 0x100, + b_rshift(high, 8) % 0x100, + high % 0x100, + b_rshift(num, 24) % 0x100, + b_rshift(num, 16) % 0x100, + b_rshift(num, 8) % 0x100, + num % 0x100); + end + error "int too large"; +end + +if s_pack then + function integer(num, m) + local fmt; + m = m or 0; + if num < 24 then + fmt, m = ">B", m + num; + elseif num < 256 then + fmt, m = ">BB", m + 24; + elseif num < 65536 then + fmt, m = ">BI2", m + 25; + elseif num < 4294967296 then + fmt, m = ">BI4", m + 26; + else + fmt, m = ">BI8", m + 27; + end + return s_pack(fmt, m, num); + end +end + +local simple_mt = {}; +function simple_mt:__tostring() return self.name or ("simple(%d)"):format(self.value); end +function simple_mt:__tocbor() return self.cbor or integer(self.value, 224); end + +local function simple(value, name, cbor) + assert(value >= 0 and value <= 255, "bad argument #1 to 'simple' (integer in range 0..255 expected)"); + return setmetatable({ value = value, name = name, cbor = cbor }, simple_mt); +end + +local tagged_mt = {}; +function tagged_mt:__tostring() return ("%d(%s)"):format(self.tag, tostring(self.value)); end +function tagged_mt:__tocbor() return integer(self.tag, 192) .. encode(self.value); end + +local function tagged(tag, value) + assert(tag >= 0, "bad argument #1 to 'tagged' (positive integer expected)"); + return setmetatable({ tag = tag, value = value }, tagged_mt); +end + +local null = simple(22, "null"); -- explicit null +local undefined = simple(23, "undefined"); -- undefined or nil +local BREAK = simple(31, "break", "\255"); + +-- Number types dispatch +function encoder.number(num) + return encoder[m_type(num)](num); +end + +-- Major types 0, 1 +function encoder.integer(num) + if num < 0 then + return integer(-1 - num, 32); + end + return integer(num, 0); +end + +-- Major type 7 +function encoder.float(num) + if num ~= num then -- NaN shortcut + return "\251\127\255\255\255\255\255\255\255"; + end + local sign = (num > 0 or 1 / num > 0) and 0 or 1; + num = m_abs(num) + if num == m_huge then + return s_char(251, sign * 128 + 128 - 1) .. "\240\0\0\0\0\0\0"; + end + local fraction, exponent = m_frexp(num) + if fraction == 0 then + return s_char(251, sign * 128) .. "\0\0\0\0\0\0\0"; + end + fraction = fraction * 2; + exponent = exponent + 1024 - 2; + if exponent <= 0 then + fraction = fraction * 2 ^ (exponent - 1) + exponent = 0; + else + fraction = fraction - 1; + end + return s_char(251, + sign * 2 ^ 7 + m_floor(exponent / 2 ^ 4) % 2 ^ 7, + exponent % 2 ^ 4 * 2 ^ 4 + + m_floor(fraction * 2 ^ 4 % 0x100), + m_floor(fraction * 2 ^ 12 % 0x100), + m_floor(fraction * 2 ^ 20 % 0x100), + m_floor(fraction * 2 ^ 28 % 0x100), + m_floor(fraction * 2 ^ 36 % 0x100), + m_floor(fraction * 2 ^ 44 % 0x100), + m_floor(fraction * 2 ^ 52 % 0x100) + ) +end + +if s_pack then + function encoder.float(num) + return s_pack(">Bd", 251, num); + end +end + + +-- Major type 2 - byte strings +function encoder.bytestring(s) + return integer(#s, 64) .. s; +end + +-- Major type 3 - UTF-8 strings +function encoder.utf8string(s) + return integer(#s, 96) .. s; +end + +-- Lua strings are byte strings +encoder.string = encoder.bytestring; + +function encoder.boolean(bool) + return bool and "\245" or "\244"; +end + +encoder["nil"] = function() return "\246"; end + +function encoder.userdata(ud, opts) + local mt = dbg_getmetatable(ud); + if mt then + local encode_ud = opts and opts[mt] or mt.__tocbor; + if encode_ud then + return encode_ud(ud, opts); + end + end + error "can't encode userdata"; +end + +function encoder.table(t, opts) + local mt = getmetatable(t); + if mt then + local encode_t = opts and opts[mt] or mt.__tocbor; + if encode_t then + return encode_t(t, opts); + end + end + -- the table is encoded as an array iff when we iterate over it, + -- we see successive integer keys starting from 1. The lua + -- language doesn't actually guarantee that this will be the case + -- when we iterate over a table with successive integer keys, but + -- due an implementation detail in PUC Rio Lua, this is what we + -- usually observe. See the Lua manual regarding the # (length) + -- operator. In the case that this does not happen, we will fall + -- back to a map with integer keys, which becomes a bit larger. + local array, map, i, p = { integer(#t, 128) }, { "\191" }, 1, 2; + local is_array = true; + for k, v in pairs(t) do + is_array = is_array and i == k; + i = i + 1; + + local encoded_v = encode(v, opts); + array[i] = encoded_v; + + map[p], p = encode(k, opts), p + 1; + map[p], p = encoded_v, p + 1; + end + -- map[p] = "\255"; + map[1] = integer(i - 1, 160); + return t_concat(is_array and array or map); +end + +-- Array or dict-only encoders, which can be set as __tocbor metamethod +function encoder.array(t, opts) + local array = { }; + for i, v in ipairs(t) do + array[i] = encode(v, opts); + end + return integer(#array, 128) .. t_concat(array); +end + +function encoder.map(t, opts) + local map, p, len = { "\191" }, 2, 0; + for k, v in pairs(t) do + map[p], p = encode(k, opts), p + 1; + map[p], p = encode(v, opts), p + 1; + len = len + 1; + end + -- map[p] = "\255"; + map[1] = integer(len, 160); + return t_concat(map); +end +encoder.dict = encoder.map; -- COMPAT + +function encoder.ordered_map(t, opts) + local map = {}; + if not t[1] then -- no predefined order + local i = 0; + for k in pairs(t) do + i = i + 1; + map[i] = k; + end + t_sort(map); + end + for i, k in ipairs(t[1] and t or map) do + map[i] = encode(k, opts) .. encode(t[k], opts); + end + return integer(#map, 160) .. t_concat(map); +end + +encoder["function"] = function () + error "can't encode function"; +end + +-- Decoder +-- Reads from a file-handle like object +local function read_bytes(fh, len) + return fh:read(len); +end + +local function read_byte(fh) + return fh:read(1):byte(); +end + +local function read_length(fh, mintyp) + if mintyp < 24 then + return mintyp; + elseif mintyp < 28 then + local out = 0; + for _ = 1, 2 ^ (mintyp - 24) do + out = out * 256 + read_byte(fh); + end + return out; + else + error "invalid length"; + end +end + +local decoder = {}; + +local function read_type(fh) + local byte = read_byte(fh); + return b_rshift(byte, 5), byte % 32; +end + +local function read_object(fh, opts) + local typ, mintyp = read_type(fh); + return decoder[typ](fh, mintyp, opts); +end + +local function read_integer(fh, mintyp) + return read_length(fh, mintyp); +end + +local function read_negative_integer(fh, mintyp) + return -1 - read_length(fh, mintyp); +end + +local function read_string(fh, mintyp) + if mintyp ~= 31 then + return read_bytes(fh, read_length(fh, mintyp)); + end + local out = {}; + local i = 1; + local v = read_object(fh); + while v ~= BREAK do + out[i], i = v, i + 1; + v = read_object(fh); + end + return t_concat(out); +end + +local function read_unicode_string(fh, mintyp) + return read_string(fh, mintyp); + -- local str = read_string(fh, mintyp); + -- if have_utf8 and not utf8.len(str) then + -- TODO How to handle this? + -- end + -- return str; +end + +local function read_array(fh, mintyp, opts) + local out = {}; + if mintyp == 31 then + local i = 1; + local v = read_object(fh, opts); + while v ~= BREAK do + out[i], i = v, i + 1; + v = read_object(fh, opts); + end + else + local len = read_length(fh, mintyp); + for i = 1, len do + out[i] = read_object(fh, opts); + end + end + return out; +end + +local function read_map(fh, mintyp, opts) + local out = {}; + local k; + if mintyp == 31 then + local i = 1; + k = read_object(fh, opts); + while k ~= BREAK do + out[k], i = read_object(fh, opts), i + 1; + k = read_object(fh, opts); + end + else + local len = read_length(fh, mintyp); + for _ = 1, len do + k = read_object(fh, opts); + out[k] = read_object(fh, opts); + end + end + return out; +end + +local tagged_decoders = {}; + +local function read_semantic(fh, mintyp, opts) + local tag = read_length(fh, mintyp); + local value = read_object(fh, opts); + local postproc = opts and opts[tag] or tagged_decoders[tag]; + if postproc then + return postproc(value); + end + return tagged(tag, value); +end + +local function read_half_float(fh) + local exponent = read_byte(fh); + local fraction = read_byte(fh); + local sign = exponent < 128 and 1 or -1; -- sign is highest bit + + fraction = fraction + (exponent * 256) % 1024; -- copy two(?) bits from exponent to fraction + exponent = b_rshift(exponent, 2) % 32; -- remove sign bit and two low bits from fraction; + + if exponent == 0 then + return sign * m_ldexp(fraction, -24); + elseif exponent ~= 31 then + return sign * m_ldexp(fraction + 1024, exponent - 25); + elseif fraction == 0 then + return sign * m_huge; + else + return NaN; + end +end + +local function read_float(fh) + local exponent = read_byte(fh); + local fraction = read_byte(fh); + local sign = exponent < 128 and 1 or -1; -- sign is highest bit + exponent = exponent * 2 % 256 + b_rshift(fraction, 7); + fraction = fraction % 128; + fraction = fraction * 256 + read_byte(fh); + fraction = fraction * 256 + read_byte(fh); + + if exponent == 0 then + return sign * m_ldexp(exponent, -149); + elseif exponent ~= 0xff then + return sign * m_ldexp(fraction + 2 ^ 23, exponent - 150); + elseif fraction == 0 then + return sign * m_huge; + else + return NaN; + end +end + +local function read_double(fh) + local exponent = read_byte(fh); + local fraction = read_byte(fh); + local sign = exponent < 128 and 1 or -1; -- sign is highest bit + + exponent = exponent % 128 * 16 + b_rshift(fraction, 4); + fraction = fraction % 16; + fraction = fraction * 256 + read_byte(fh); + fraction = fraction * 256 + read_byte(fh); + fraction = fraction * 256 + read_byte(fh); + fraction = fraction * 256 + read_byte(fh); + fraction = fraction * 256 + read_byte(fh); + fraction = fraction * 256 + read_byte(fh); + + if exponent == 0 then + return sign * m_ldexp(exponent, -149); + elseif exponent ~= 0xff then + return sign * m_ldexp(fraction + 2 ^ 52, exponent - 1075); + elseif fraction == 0 then + return sign * m_huge; + else + return NaN; + end +end + + +if s_unpack then + function read_float(fh) return s_unpack(">f", read_bytes(fh, 4)) end + function read_double(fh) return s_unpack(">d", read_bytes(fh, 8)) end +end + +local function read_simple(fh, value, opts) + if value == 24 then + value = read_byte(fh); + end + if value == 20 then + return false; + elseif value == 21 then + return true; + elseif value == 22 then + return null; + elseif value == 23 then + return undefined; + elseif value == 25 then + return read_half_float(fh); + elseif value == 26 then + return read_float(fh); + elseif value == 27 then + return read_double(fh); + elseif value == 31 then + return BREAK; + end + if opts and opts.simple then + return opts.simple(value); + end + return simple(value); +end + +decoder[0] = read_integer; +decoder[1] = read_negative_integer; +decoder[2] = read_string; +decoder[3] = read_unicode_string; +decoder[4] = read_array; +decoder[5] = read_map; +decoder[6] = read_semantic; +decoder[7] = read_simple; + +-- opts.more(n) -> want more data +-- opts.simple -> decode simple value +-- opts[int] -> tagged decoder +local function decode(s, opts) + local fh = {}; + local pos = 1; + + local more; + if type(opts) == "function" then + more = opts; + elseif type(opts) == "table" then + more = opts.more; + elseif opts ~= nil then + error(("bad argument #2 to 'decode' (function or table expected, got %s)"):format(type(opts))); + end + if type(more) ~= "function" then + function more() + error "input too short"; + end + end + + function fh:read(bytes) + local ret = s:sub(pos, pos + bytes - 1); + if #ret < bytes then + ret = more(bytes - #ret, fh, opts); + if ret then self:write(ret); end + return self:read(bytes); + end + pos = pos + bytes; + return ret; + end + + function fh:write(bytes) -- luacheck: no self + s = s .. bytes; + if pos > 256 then + s = s:sub(pos + 1); + pos = 1; + end + return #bytes; + end + + return read_object(fh, opts); +end + +return { + -- en-/decoder functions + encode = encode; + decode = decode; + decode_file = read_object; + + -- tables of per-type en-/decoders + type_encoders = encoder; + type_decoders = decoder; + + -- special treatment for tagged values + tagged_decoders = tagged_decoders; + + -- constructors for annotated types + simple = simple; + tagged = tagged; + + -- pre-defined simple values + null = null; + undefined = undefined; +} diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index c82763f..ba1afa7 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -6,7 +6,7 @@ local sha2 = require('opus.crypto.sha2') local Serializer = require('opus.crypto.serializer') local Util = require('opus.util') -local ROUNDS = 20 -- Adjust this for speed tradeoff +local ROUNDS = 8 -- Adjust this for speed tradeoff local bxor = bit32.bxor local band = bit32.band From 159dc622fd175e608289683211b0bc98046cda90 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Jun 2019 17:40:57 -0400 Subject: [PATCH 166/231] oops --- sys/modules/opus/socket.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index 3eadac7..d56ea38 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -106,14 +106,15 @@ local function newSocket(isLoopback) end local function setupCrypto(socket, isClient) + socket.sharedKey = ECC.exchange(socket.privKey, socket.remotePubKey) + socket.enckey = SHA.pbkdf2(socket.sharedKey, "1enc", 1) + --self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) + socket.rrng = Crypto.newRNG( SHA.pbkdf2(socket.sharedKey, isClient and "3rseed" or "4sseed", 1)) socket.wrng = Crypto.newRNG( SHA.pbkdf2(socket.sharedKey, isClient and "4sseed" or "3rseed", 1)) - socket.sharedKey = ECC.exchange(socket.privKey, socket.remotePubKey) - socket.enckey = SHA.pbkdf2(socket.sharedKey, "1enc", 1) - --self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1) socket.rseq = socket.rrng:nextInt(5) socket.wseq = socket.wrng:nextInt(5) end From 61a26d7c55bdbf706a2dd4b2e79dde90f0950132 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 30 Jun 2019 19:53:26 -0400 Subject: [PATCH 167/231] encryption perf --- sys/apps/network/vnc.lua | 20 +++ sys/apps/vnc.lua | 7 +- sys/modules/opus/{crypto => }/cbor.lua | 0 sys/modules/opus/crypto/chacha20.lua | 9 +- sys/modules/opus/crypto/lualzw.lua | 164 ------------------------- sys/modules/opus/crypto/serializer.lua | 50 -------- 6 files changed, 28 insertions(+), 222 deletions(-) rename sys/modules/opus/{crypto => }/cbor.lua (100%) delete mode 100644 sys/modules/opus/crypto/lualzw.lua delete mode 100644 sys/modules/opus/crypto/serializer.lua diff --git a/sys/apps/network/vnc.lua b/sys/apps/network/vnc.lua index 54ea8fc..c833ead 100644 --- a/sys/apps/network/vnc.lua +++ b/sys/apps/network/vnc.lua @@ -71,3 +71,23 @@ Event.addRoutine(function() end end end) + +Event.addRoutine(function() + + print('svnc: listening on port 5901') + + while true do + local socket = Socket.server(5901, { ENCRYPT = true }) + + print('svnc: connection from ' .. socket.dhost) + + -- no new process - only 1 connection allowed + -- due to term size issues + local s, m = pcall(vncHost, socket) + socket:close() + if not s and m then + print('vnc error') + _G.printError(m) + end + end +end) diff --git a/sys/apps/vnc.lua b/sys/apps/vnc.lua index cb2d945..0265254 100644 --- a/sys/apps/vnc.lua +++ b/sys/apps/vnc.lua @@ -10,7 +10,7 @@ local shell = _ENV.shell local term = _G.term local remoteId -local args = { ... } +local args, options = Util.parse(...) if #args == 1 then remoteId = tonumber(args[1]) else @@ -23,11 +23,12 @@ if not remoteId then end if multishell then - multishell.setTitle(multishell.getCurrent(), 'VNC-' .. remoteId) + multishell.setTitle(multishell.getCurrent(), + (options.s and 'SVNC-' or 'VNC-') .. remoteId) end local function connect() - local socket, msg, reason = Socket.connect(remoteId, 5900) + local socket, msg, reason = Socket.connect(remoteId, options.s and 5901 or 5900) if reason == 'NOTRUST' then local s, m = shell.run('trust ' .. remoteId) diff --git a/sys/modules/opus/crypto/cbor.lua b/sys/modules/opus/cbor.lua similarity index 100% rename from sys/modules/opus/crypto/cbor.lua rename to sys/modules/opus/cbor.lua diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index ba1afa7..89cf0ac 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -1,9 +1,8 @@ -- Chacha20 cipher in ComputerCraft -- By Anavrins -local LZW = require('opus.crypto.lualzw') +local cbor = require('opus.cbor') local sha2 = require('opus.crypto.sha2') -local Serializer = require('opus.crypto.serializer') local Util = require('opus.util') local ROUNDS = 8 -- Adjust this for speed tradeoff @@ -153,10 +152,10 @@ end local function encrypt(data, key) local nonce = genNonce(12) - data = Serializer.serialize(data) - data = LZW.compress(data) + data = cbor.encode(data) key = sha2.digest(key) local ctx = crypt(data, key, nonce, 1, ROUNDS) + return { nonce:toHex(), ctx:toHex() } end @@ -165,7 +164,7 @@ local function decrypt(data, key) data = Util.hexToByteArray(data[2]) key = sha2.digest(key) local ptx = crypt(data, key, nonce, 1, ROUNDS) - return textutils.unserialise(LZW.decompress(tostring(ptx))) + return cbor.decode(tostring(ptx)) end local obj = {} diff --git a/sys/modules/opus/crypto/lualzw.lua b/sys/modules/opus/crypto/lualzw.lua deleted file mode 100644 index 7bdfa21..0000000 --- a/sys/modules/opus/crypto/lualzw.lua +++ /dev/null @@ -1,164 +0,0 @@ --- see: https://github.com/Rochet2/lualzw ---[[ -MIT License - -Copyright (c) 2016 Rochet2 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -]] - -local char = string.char -local type = type -local sub = string.sub -local tconcat = table.concat - -local basedictcompress = {} -local basedictdecompress = {} -for i = 0, 255 do - local ic, iic = char(i), char(i, 0) - basedictcompress[ic] = iic - basedictdecompress[iic] = ic -end - -local function dictAddA(str, dict, a, b) - if a >= 256 then - a, b = 0, b+1 - if b >= 256 then - dict = {} - b = 1 - end - end - dict[str] = char(a,b) - a = a+1 - return dict, a, b -end - -local function compress(input) - if type(input) ~= "string" then - error ("string expected, got "..type(input)) - end - local len = #input - if len <= 1 then - return "u"..input - end - - local dict = {} - local a, b = 0, 1 - - local result = {"c"} - local resultlen = 1 - local n = 2 - local word = "" - for i = 1, len do - local c = sub(input, i, i) - local wc = word..c - if not (basedictcompress[wc] or dict[wc]) then - local write = basedictcompress[word] or dict[word] - if not write then - error "algorithm error, could not fetch word" - end - result[n] = write - resultlen = resultlen + #write - n = n+1 - if len <= resultlen then - return "u"..input - end - dict, a, b = dictAddA(wc, dict, a, b) - word = c - else - word = wc - end - end - result[n] = basedictcompress[word] or dict[word] - resultlen = resultlen+#result[n] - if len <= resultlen then - return "u"..input - end - return tconcat(result) -end - -local function dictAddB(str, dict, a, b) - if a >= 256 then - a, b = 0, b+1 - if b >= 256 then - dict = {} - b = 1 - end - end - dict[char(a,b)] = str - a = a+1 - return dict, a, b -end - -local function decompress(input) - if type(input) ~= "string" then - error( "string expected, got "..type(input)) - end - - if #input < 1 then - error("invalid input - not a compressed string") - end - - local control = sub(input, 1, 1) - if control == "u" then - return sub(input, 2) - elseif control ~= "c" then - error( "invalid input - not a compressed string") - end - input = sub(input, 2) - local len = #input - - if len < 2 then - error( "invalid input - not a compressed string") - end - - local dict = {} - local a, b = 0, 1 - - local result = {} - local n = 1 - local last = sub(input, 1, 2) - result[n] = basedictdecompress[last] or dict[last] - n = n+1 - for i = 3, len, 2 do - local code = sub(input, i, i+1) - local lastStr = basedictdecompress[last] or dict[last] - if not lastStr then - error( "could not find last from dict. Invalid input?") - end - local toAdd = basedictdecompress[code] or dict[code] - if toAdd then - result[n] = toAdd - n = n+1 - dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) - else - local tmp = lastStr..sub(lastStr, 1, 1) - result[n] = tmp - n = n+1 - dict, a, b = dictAddB(tmp, dict, a, b) - end - last = code - end - return tconcat(result) -end - -return { - compress = compress, - decompress = decompress, -} \ No newline at end of file diff --git a/sys/modules/opus/crypto/serializer.lua b/sys/modules/opus/crypto/serializer.lua deleted file mode 100644 index db19336..0000000 --- a/sys/modules/opus/crypto/serializer.lua +++ /dev/null @@ -1,50 +0,0 @@ -local Serializer = { } - -local insert = table.insert -local format = string.format - -function Serializer.serialize(tbl) - local output = { } - - local function recurse(t) - local sType = type(t) - if sType == 'table' then - if next(t) == nil then - insert(output, '{}') - else - insert(output, '{') - local tSeen = {} - for k, v in ipairs(t) do - tSeen[k] = true - recurse(v) - insert(output, ',') - end - for k, v in pairs(t) do - if not tSeen[k] then - if type(k) == 'string' and string.match(k, '^[%a_][%a%d_]*$') then - insert(output, k .. '=') - recurse(v) - insert(output, ',') - else - insert(output, '[') - recurse(k) - insert(output, ']=') - recurse(v) - insert(output, ',') - end - end - end - insert(output, '}') - end - elseif sType == 'string' then - insert(output, format('%q', t)) - else - insert(output, tostring(t)) - end - end - - recurse(tbl) - return table.concat(output) -end - -return Serializer From 9e85a0dae1c8b5e2b87071b827fd899d455d5a1b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 1 Jul 2019 17:22:19 -0400 Subject: [PATCH 168/231] shuffled some files around --- sys/apps/network/trust.lua | 4 +++- sys/autorun/apps.lua | 4 ---- sys/autorun/upgraded.lua | 1 + sys/etc/fstab | 4 ++++ sys/init/3.sys.lua | 4 ++++ sys/init/6.packages.lua | 7 +++++-- sys/modules/opus/crypto/chacha20.lua | 2 +- sys/modules/opus/socket.lua | 24 +++++++++++++++--------- 8 files changed, 33 insertions(+), 17 deletions(-) delete mode 100644 sys/autorun/apps.lua create mode 100644 sys/etc/fstab create mode 100644 sys/init/3.sys.lua diff --git a/sys/apps/network/trust.lua b/sys/apps/network/trust.lua index 58d3847..7f80427 100644 --- a/sys/apps/network/trust.lua +++ b/sys/apps/network/trust.lua @@ -13,7 +13,9 @@ local function trustConnection(socket) if not password then socket:write({ msg = 'No password has been set' }) else - data = Crypto.decrypt(data, password) + pcall(function() + data = Crypto.decrypt(data, password) + end) if data and data.pk and data.dh == socket.dhost then local trustList = Util.readTable('usr/.known_hosts') or { } trustList[data.dh] = data.pk diff --git a/sys/autorun/apps.lua b/sys/autorun/apps.lua deleted file mode 100644 index 5322c79..0000000 --- a/sys/autorun/apps.lua +++ /dev/null @@ -1,4 +0,0 @@ -fs.mount('sys/apps/pain.lua', 'urlfs', 'https://github.com/LDDestroier/CC/raw/master/pain.lua') -fs.mount('sys/apps/update.lua', 'urlfs', 'http://pastebin.com/raw/UzGHLbNC') -fs.mount('sys/apps/Enchat.lua', 'urlfs', 'https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua') -fs.mount('sys/apps/cloud.lua', 'urlfs', 'https://cloud-catcher.squiddev.cc/cloud.lua') diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index d3a2737..6cb1c92 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -10,3 +10,4 @@ if fs.exists('sys/autorun/gps.lua') then fs.delete('sys/autorun/gps.lua') end if fs.exists('sys/autorun/gpsHost.lua') then fs.delete('sys/autorun/gpsHost.lua') end if fs.exists('sys/apps/network/redserver.lua') then fs.delete('sys/apps/network/redserver.lua') end if fs.exists('sys/apis') then fs.delete('sys/apis') end +if fs.exists('sys/autorun/apps.lua') then fs.delete('sys/autorun/apps.lua') end diff --git a/sys/etc/fstab b/sys/etc/fstab new file mode 100644 index 0000000..deeac19 --- /dev/null +++ b/sys/etc/fstab @@ -0,0 +1,4 @@ +sys/apps/pain.lua urlfs https://github.com/LDDestroier/CC/raw/master/pain.lua +sys/apps/update.lua urlfs http://pastebin.com/raw/UzGHLbNC +sys/apps/Enchat.lua urlfs https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua +sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua \ No newline at end of file diff --git a/sys/init/3.sys.lua b/sys/init/3.sys.lua new file mode 100644 index 0000000..ce04901 --- /dev/null +++ b/sys/init/3.sys.lua @@ -0,0 +1,4 @@ +local fs = _G.fs + +fs.mount('rom/modules/main/opus', 'linkfs', 'sys/modules/opus') +fs.loadTab('sys/etc/fstab') diff --git a/sys/init/6.packages.lua b/sys/init/6.packages.lua index ad667cd..c991821 100644 --- a/sys/init/6.packages.lua +++ b/sys/init/6.packages.lua @@ -29,9 +29,12 @@ for name in pairs(Packages:installed()) do if fs.exists(helpPath) then table.insert(helpPaths, helpPath) end + + local fstabPath = fs.combine(packageDir, 'etc/fstab') + if fs.exists(fstabPath) then + fs.loadTab(fstabPath) + end end help.setPath(table.concat(helpPaths, ':')) shell.setPath(table.concat(appPaths, ':')) - -fs.mount('rom/modules/main/opus', 'linkfs', 'sys/modules/opus') diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index 89cf0ac..9547f6c 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -164,7 +164,7 @@ local function decrypt(data, key) data = Util.hexToByteArray(data[2]) key = sha2.digest(key) local ptx = crypt(data, key, nonce, 1, ROUNDS) - return cbor.decode(tostring(ptx)) + return cbor.decode(tostring(ptx)) end local obj = {} diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index d56ea38..822d195 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -181,18 +181,24 @@ local function trusted(socket, msg, options) local identifier = options and options.identifier or getIdentifier() - if identifier and type(msg.t) == 'table' then - local data = Crypto.decrypt(msg.t, Util.hexToByteArray(identifier)) + local s, m = pcall(function() + if identifier and type(msg.t) == 'table' then + local data = Crypto.decrypt(msg.t, Util.hexToByteArray(identifier)) - if data and data.ts and tonumber(data.ts) then - if math.abs(os.epoch('utc') - data.ts) < 4096 then - socket.remotePubKey = Util.hexToByteArray(data.pk) - socket.privKey, socket.pubKey = network.getKeyPair() - setupCrypto(socket) - return true + if data and data.ts and tonumber(data.ts) then + if math.abs(os.epoch('utc') - data.ts) < 4096 then + socket.remotePubKey = Util.hexToByteArray(data.pk) + socket.privKey, socket.pubKey = network.getKeyPair() + setupCrypto(socket) + return true + end + _G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts)) end - _G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts)) end + end) + if not s and m then + _G._syslog('trust failure') + _G._syslog(m) end end From cd7122921f4cd563aab6f8e1bcfc9d59f58f909f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 1 Jul 2019 19:20:38 -0400 Subject: [PATCH 169/231] oops --- sys/modules/opus/socket.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index 822d195..0ff53a9 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -200,6 +200,7 @@ local function trusted(socket, msg, options) _G._syslog('trust failure') _G._syslog(m) end + return s and m end function Socket.server(port, options) From aec5ac012167b76c25e9eeb6ff46870d5160c8d7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 1 Jul 2019 20:39:34 -0400 Subject: [PATCH 170/231] oops again --- sys/apps/network/trust.lua | 7 +++---- sys/modules/opus/socket.lua | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sys/apps/network/trust.lua b/sys/apps/network/trust.lua index 7f80427..c31b6ec 100644 --- a/sys/apps/network/trust.lua +++ b/sys/apps/network/trust.lua @@ -13,10 +13,9 @@ local function trustConnection(socket) if not password then socket:write({ msg = 'No password has been set' }) else - pcall(function() - data = Crypto.decrypt(data, password) - end) - if data and data.pk and data.dh == socket.dhost then + local s + s, data = pcall(Crypto.decrypt, data, password) + if s and data and data.pk and data.dh == socket.dhost then local trustList = Util.readTable('usr/.known_hosts') or { } trustList[data.dh] = data.pk Util.writeTable('usr/.known_hosts', trustList) diff --git a/sys/modules/opus/socket.lua b/sys/modules/opus/socket.lua index 0ff53a9..8151855 100644 --- a/sys/modules/opus/socket.lua +++ b/sys/modules/opus/socket.lua @@ -210,7 +210,6 @@ function Socket.server(port, options) local _, _, sport, dport, msg = os.pullEvent('modem_message') if sport == port and - msg and type(msg) == 'table' and msg.dhost == os.getComputerID() and msg.type == 'OPEN' then From 1dcb6d67b7ef6bfd6075af7eb2fa34290d61d02f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 2 Jul 2019 10:19:08 -0400 Subject: [PATCH 171/231] tweaks + Anavrins disk usage system module --- sys/apps/system/diskusage.lua | 146 ++++++++++++++++++ sys/autorun/clipboard.lua | 11 +- sys/init/1.device.lua | 18 ++- sys/modules/opus/input.lua | 43 +----- sys/modules/opus/ui.lua | 19 ++- sys/modules/opus/ui/components/NftImage.lua | 1 - .../opus/ui/components/ProgressBar.lua | 16 +- 7 files changed, 200 insertions(+), 54 deletions(-) create mode 100644 sys/apps/system/diskusage.lua diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua new file mode 100644 index 0000000..0ce1e14 --- /dev/null +++ b/sys/apps/system/diskusage.lua @@ -0,0 +1,146 @@ +local UI = require('opus.ui') +local Event = require('opus.event') +local Util = require('opus.util') +local NFT = require('opus.nft') + +local NftImages = { + blank = '\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153', + drive = '', + rom = '', + hdd = '', +} + +local tab = UI.Tab { + tabTitle = '1.Disks Usage', + description = 'Visualise HDD and disks usage', + drives = UI.ScrollingGrid { + y = 2, ey = 9, x = 2, ex = '47%', + columns = { + { heading = 'Drive', key = 'name' }, + { heading = 'Side' ,key = 'side' } + }, + sortColumn = 'name', + }, + infos = UI.Grid { + x = '52%', y = 3, ex = -2, ey = 9, + disableHeader = true, + unfocusedBackgroundSelectedColor = colors.black, + inactive = true, + backgroundSelectedColor = colors.black, --?? + columns = { + {key = 'name' }, + {key = 'value', align = 'right' }, + } + }, + + progress = UI.ProgressBar { + x = 11, y = 11, ex = -2, + barChar = '\127', + textColor = colors.blue, + backgroundColor = colors.black, + }, + percentage = UI.Text { + x = 11, y = 12, ex = -2, + align = 'center', + }, + icon = UI.NftImage { + x = 2, y = 11, + image = NFT.parse(NftImages.blank) + }, +} + +local function getDrives() + local unique = { ['hdd'] = true, ['virt'] = true } + local exclude = {} + local drives = { + {name = 'hdd', side = ''}, + } + for _, drive in pairs(fs.list('/')) do + local side = fs.getDrive(drive) + if side and not unique[side] then + unique[side] = true + exclude[drive] = true + table.insert(drives, {name=drive, side=side}) + end + end + return drives, exclude +end + +local function getDriveInfo(p) + local files, dirs, total = 0, 0, 0 + + if p == "hdd" then p = "/" end + p = fs.combine(p, '') + local drive = fs.getDrive(p) + + local function recurse(path) + if fs.getDrive(path) == drive then + if fs.isDir(path) then + if path ~= p then + total = total + 500 + dirs = dirs + 1 + end + for _, v in pairs(fs.list(path)) do + recurse(fs.combine(path, v)) + end + else + local sz = fs.getSize(path) + + files = files + 1 + if drive == 'rom' then + total = total + sz + else + total = total + math.max(500, sz) + end + end + end + end + + recurse(p) + local info = {} + table.insert(info, { name = 'Type', value = peripheral.getType(drive) or drive }) + table.insert(info, { name = 'Used', value = total }) + table.insert(info, { name = 'Total', value = total + fs.getFreeSpace(p) }) + table.insert(info, { name = 'Free', value = fs.getFreeSpace(p) }) + table.insert(info, { }) + table.insert(info, { name = 'Files', value = files }) + table.insert(info, { name = 'Dirs', value = dirs }) + return info, math.floor((total / (total + fs.getFreeSpace(p))) * 100) +end + +function tab:updateInfo() + local selected = self.drives:getSelected() + local info, percent = getDriveInfo(selected and selected.name or self.drives.values[1].name) + self.infos:setValues(info) + self.progress.value = percent + self.percentage.value = ('%#3d%%'):format(percent) + self:draw() +end + +function tab:updateDrives() + local drives, exclude = getDrives() + self.exclude = exclude + self.drives:setValues(drives) +end + +function tab:enable() + self:updateDrives() + self:updateInfo() + UI.Tab.enable(self) +end + +function tab:eventHandler(event) + if event.type == 'grid_focus_row' then + self:updateInfo() + end + return UI.Tab.eventHandler(self, event) +end + +Event.on({ 'disk', 'disk_eject' }, function() + sleep(1) + tab:updateDrives() + tab:updateInfo() + tab:sync() +end) + +return tab diff --git a/sys/autorun/clipboard.lua b/sys/autorun/clipboard.lua index 72c9434..992af47 100644 --- a/sys/autorun/clipboard.lua +++ b/sys/autorun/clipboard.lua @@ -5,19 +5,18 @@ local keyboard = _G.device.keyboard local os = _G.os local textutils = _G.textutils -local data - kernel.hook('clipboard_copy', function(_, args) - data = args[1] + keyboard.clipboard = args[1] end) keyboard.addHotkey('shift-paste', function() + local data = keyboard.clipboard + if type(data) == 'table' then local s, m = pcall(textutils.serialize, data) - data = (s and m) or Util.tostring(data) + data = s and m or Util.tostring(data) end - -- replace the event paste data with our internal data - -- args[1] = Util.tostring(data or '') + if data then os.queueEvent('paste', data) end diff --git a/sys/init/1.device.lua b/sys/init/1.device.lua index 65b1e76..c4946d3 100644 --- a/sys/init/1.device.lua +++ b/sys/init/1.device.lua @@ -78,16 +78,12 @@ local modifiers = Util.transpose { keys.leftAlt, keys.rightAlt, } -kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData) +kernel.hook({ 'key', 'char', 'paste' }, function(event, eventData) local code = eventData[1] -- maintain global keyboard modifier state - if modifiers[code] then - if event == 'key' then - keyboard.state[code] = true - elseif event == 'key_up' then - keyboard.state[code] = nil - end + if event == 'key' and modifiers[code] then + keyboard.state[code] = true end -- and fire hotkeys @@ -99,6 +95,14 @@ kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData) end end) +kernel.hook('key_up', function(_, eventData) + local code = eventData[1] + + if modifiers[code] then + keyboard.state[code] = nil + end +end) + kernel.hook({ 'mouse_click', 'mouse_up', 'mouse_drag' }, function(event, eventData) local button = eventData[1] if event == 'mouse_click' then diff --git a/sys/modules/opus/input.lua b/sys/modules/opus/input.lua index b7894d1..62d51b4 100644 --- a/sys/modules/opus/input.lua +++ b/sys/modules/opus/input.lua @@ -10,13 +10,7 @@ local modifiers = Util.transpose { keys.leftAlt, keys.rightAlt, } -local input = { - state = { }, -} - -if not keyboard then - keyboard = { state = input.state } -end +local input = { } function input:modifierPressed() return keyboard.state[keys.leftCtrl] or @@ -64,7 +58,6 @@ end function input:reset() self.state = { } - self.fired = nil self.timer = nil self.mch = nil @@ -81,7 +74,6 @@ function input:translate(event, code, p1, p2) if event == 'key' then if p1 then -- key is held down if not modifiers[code] then - self.fired = true local ch = input:toCode(keys.getName(code), code) if #ch == 1 then return { @@ -92,37 +84,19 @@ function input:translate(event, code, p1, p2) return { code = ch } end elseif code then - --self.fired = true - local ch = input:toCode(keys.getName(code), code) - if #ch ~= 1 then - return { code = ch } - end --- self.state[code] = true + local ch = input:toCode(keys.getName(code), code) + if #ch ~= 1 then + return { code = ch } + end end elseif event == 'char' then local combo = isCombo() - --if not self.fired then - if combo or not (keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl]) then - self.fired = not combo - return { code = event, ch = code } - --end --- return { code = event, ch = input:toCode(code) } + if combo or not (keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl]) then + return { code = event, ch = code } end - elseif event == 'key_upx' then - if not self.fired then - --if self.state[code] then - self.fired = true - local ch = input:toCode(keys.getName(code), code) - self.state[code] = nil - return { code = ch } - --end - end - self.state[code] = nil - elseif event == 'paste' then - self.fired = true if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] then return { code = 'shift-paste', text = code } else @@ -142,7 +116,6 @@ function input:translate(event, code, p1, p2) elseif event == 'mouse_drag' then self.mfired = true - self.fired = true return { code = input:toCode('mouse_drag', 255), button = code, @@ -169,7 +142,6 @@ function input:translate(event, code, p1, p2) self.mch = 'mouse_up' self.mfired = input:toCode(self.mch, 255) end - self.fired = true return { code = self.mfired, button = code, @@ -182,7 +154,6 @@ function input:translate(event, code, p1, p2) [ -1 ] = 'scroll_up', [ 1 ] = 'scroll_down' } - self.fired = true return { code = input:toCode(directions[code], 255), x = p1, diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 87a6a67..50864c7 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -457,7 +457,6 @@ function UI.Window:initChildren() if not child.parent then child.parent = self child:setParent() - -- child:reposition() -- maybe if self.enabled then child:enable() end @@ -468,6 +467,24 @@ function UI.Window:initChildren() end function UI.Window:layout() + local function calc(p, max) + p = tonumber(p:match('(%d+)%%')) + return p and math.floor(max * p / 100) or 1 + end + + if type(self.x) == 'string' then + self.x = calc(self.x, self.parent.width) + end + if type(self.ex) == 'string' then + self.ex = calc(self.ex, self.parent.width) + end + if type(self.y) == 'string' then + self.y = calc(self.y, self.parent.height) + end + if type(self.ey) == 'string' then + self.ey = calc(self.ey, self.parent.height) + end + if self.x < 0 then self.x = self.parent.width + self.x + 1 end diff --git a/sys/modules/opus/ui/components/NftImage.lua b/sys/modules/opus/ui/components/NftImage.lua index b932dfb..3457711 100644 --- a/sys/modules/opus/ui/components/NftImage.lua +++ b/sys/modules/opus/ui/components/NftImage.lua @@ -4,7 +4,6 @@ local UI = require('opus.ui') UI.NftImage = class(UI.Window) UI.NftImage.defaults = { UIElement = 'NftImage', - event = 'button_press', } function UI.NftImage:setParent() if self.image then diff --git a/sys/modules/opus/ui/components/ProgressBar.lua b/sys/modules/opus/ui/components/ProgressBar.lua index 56d6156..af12708 100644 --- a/sys/modules/opus/ui/components/ProgressBar.lua +++ b/sys/modules/opus/ui/components/ProgressBar.lua @@ -6,13 +6,23 @@ local colors = _G.colors UI.ProgressBar = class(UI.Window) UI.ProgressBar.defaults = { UIElement = 'ProgressBar', - progressColor = colors.lime, backgroundColor = colors.gray, height = 1, + progressColor = colors.lime, + progressChar = UI.extChars and '\153' or ' ', + fillChar = ' ', + fillColor = colors.gray, + textColor = colors.green, value = 0, } function UI.ProgressBar:draw() - self:clear() local width = math.ceil(self.value / 100 * self.width) - self:clearArea(1, 1, width, self.height, self.progressColor) + + local filler = string.rep(self.fillChar, self.width) + local progress = string.rep(self.progressChar, width) + + for i = 1, self.height do + self:write(1, i, filler, nil, self.fillColor) + self:write(1, i, progress, self.progressColor) + end end From 6ba458646ff8f16555c5923472873253523910bd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 2 Jul 2019 14:11:33 -0400 Subject: [PATCH 172/231] control-q instead of q for exitting apps + grid column override colors --- sys/apps/Files.lua | 4 ++-- sys/apps/Help.lua | 4 ++-- sys/apps/Network.lua | 2 +- sys/apps/System.lua | 2 +- sys/apps/Tasks.lua | 2 +- sys/apps/Welcome.lua | 16 ++++++++++++++++ sys/apps/system/diskusage.lua | 6 +++--- sys/modules/opus/ui/components/Grid.lua | 4 ++-- 8 files changed, 28 insertions(+), 12 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 6c6b453..019979e 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -47,7 +47,7 @@ local Browser = UI.Page { { text = 'Pastebin put p', event = 'pastebin', flags = FILE }, { text = 'Shell s', event = 'shell' }, { spacer = true }, - { text = 'Quit q', event = 'quit' }, + { text = 'Quit ^q', event = 'quit' }, } }, { text = 'Edit', dropdown = { { text = 'Cut ^x', event = 'cut' }, @@ -140,7 +140,7 @@ local Browser = UI.Page { }, }, accelerators = { - q = 'quit', + [ 'control-q' ] = 'quit', c = 'cedit', e = 'edit', s = 'shell', diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index b6e862c..abb6099 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -31,7 +31,7 @@ local page = UI.Page { sortColumn = 'name', }, accelerators = { - q = 'quit', + [ 'control-q' ] = 'quit', enter = 'grid_select', }, } @@ -47,7 +47,7 @@ local topicPage = UI.Page { x = 2, ex = -1, y = 3, ey = -2, }, accelerators = { - q = 'back', + [ 'control-q' ] = 'back', backspace = 'back', }, } diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 1c8405d..52be626 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -103,7 +103,7 @@ This only needs to be done once. t = 'telnet', v = 'vnc', r = 'reboot', - q = 'quit', + [ 'control-q' ] = 'quit', c = 'clear', }, } diff --git a/sys/apps/System.lua b/sys/apps/System.lua index b97d2e9..b18200d 100644 --- a/sys/apps/System.lua +++ b/sys/apps/System.lua @@ -23,7 +23,7 @@ local systemPage = UI.Page { }, notification = UI.Notification(), accelerators = { - q = 'quit', + [ 'control-q' ] = 'quit', }, } diff --git a/sys/apps/Tasks.lua b/sys/apps/Tasks.lua index 73ff93b..f67d71b 100644 --- a/sys/apps/Tasks.lua +++ b/sys/apps/Tasks.lua @@ -26,7 +26,7 @@ local page = UI.Page { autospace = true, }, accelerators = { - q = 'quit', + [ 'control-q' ] = 'quit', space = 'activate', t = 'terminate', }, diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 76c4c7f..5405174 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -19,6 +19,13 @@ local passwordIntro = [[A password is required for wireless access. local packagesIntro = [[Setup Complete %sOpen the package manager to add software to this computer.]] +local contributorsIntro = [[Contributors%s + +Anavrins: Encryption/security/custom apps +Community: Several selected applications +hugeblank: Startup screen improvements +LDDestroier: Art design + custom apps +Lemmmy: Application improvements]] local page = UI.Page { wizard = UI.Wizard { @@ -95,6 +102,15 @@ local page = UI.Page { value = string.format(packagesIntro, Ansi.white), }, }, + contributors = UI.WizardPage { + index = 5, + intro = UI.TextArea { + textColor = colors.yellow, + inactive = true, + x = 3, ex = -3, y = 2, ey = -2, + value = string.format(contributorsIntro, Ansi.white), + }, + }, }, }, notification = UI.Notification { }, diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index 0ce1e14..7ae69ff 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -17,7 +17,7 @@ local tab = UI.Tab { y = 2, ey = 9, x = 2, ex = '47%', columns = { { heading = 'Drive', key = 'name' }, - { heading = 'Side' ,key = 'side' } + { heading = 'Side' ,key = 'side', textColor = colors.yellow } }, sortColumn = 'name', }, @@ -29,7 +29,7 @@ local tab = UI.Tab { backgroundSelectedColor = colors.black, --?? columns = { {key = 'name' }, - {key = 'value', align = 'right' }, + {key = 'value', align = 'right', textColor = colors.yellow }, } }, @@ -113,7 +113,7 @@ function tab:updateInfo() local info, percent = getDriveInfo(selected and selected.name or self.drives.values[1].name) self.infos:setValues(info) self.progress.value = percent - self.percentage.value = ('%#3d%%'):format(percent) + self.percentage.value = ('%#3d%% used'):format(percent) self:draw() end diff --git a/sys/modules/opus/ui/components/Grid.lua b/sys/modules/opus/ui/components/Grid.lua index a1dc638..bcdab81 100644 --- a/sys/modules/opus/ui/components/Grid.lua +++ b/sys/modules/opus/ui/components/Grid.lua @@ -351,8 +351,8 @@ function UI.Grid:drawRow(sb, row, focused, bg, fg) sb:write(ind .. safeValue(row[col.key] or ''), col.cw + 1, col.align, - bg, - fg) + col.backgroundColor or bg, + col.textColor or fg) ind = ' ' end end From 2f5aea912b0f2bd5a9e9df61c4140dab9ad0da6d Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 2 Jul 2019 14:25:17 -0400 Subject: [PATCH 173/231] diskusage --- sys/apps/system/diskusage.lua | 41 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index 7ae69ff..c78ef96 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -1,8 +1,12 @@ local UI = require('opus.ui') local Event = require('opus.event') -local Util = require('opus.util') local NFT = require('opus.nft') +local colors = _G.colors +local fs = _G.files +local os = _G.os +local peripheral = _G.peripheral + local NftImages = { blank = '\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153', drive = '', @@ -11,40 +15,42 @@ local NftImages = { } local tab = UI.Tab { - tabTitle = '1.Disks Usage', + tabTitle = 'Disks Usage', description = 'Visualise HDD and disks usage', + drives = UI.ScrollingGrid { - y = 2, ey = 9, x = 2, ex = '47%', + x = 2, y = 1, + ex = '47%', ey = 8, columns = { { heading = 'Drive', key = 'name' }, - { heading = 'Side' ,key = 'side', textColor = colors.yellow } + { heading = 'Side' ,key = 'side', textColor = colors.yellow } }, sortColumn = 'name', }, infos = UI.Grid { - x = '52%', y = 3, ex = -2, ey = 9, + x = '52%', y = 2, + ex = -2, ey = 8, disableHeader = true, unfocusedBackgroundSelectedColor = colors.black, inactive = true, - backgroundSelectedColor = colors.black, --?? + backgroundSelectedColor = colors.black, columns = { - {key = 'name' }, - {key = 'value', align = 'right', textColor = colors.yellow }, + { key = 'name' }, + { key = 'value', align = 'right', textColor = colors.yellow }, } }, progress = UI.ProgressBar { - x = 11, y = 11, ex = -2, - barChar = '\127', - textColor = colors.blue, - backgroundColor = colors.black, + x = 11, y = 10, + ex = -2, }, percentage = UI.Text { - x = 11, y = 12, ex = -2, + x = 11, y = 11, + ex = -2, align = 'center', }, icon = UI.NftImage { - x = 2, y = 11, + x = 2, y = 10, image = NFT.parse(NftImages.blank) }, } @@ -96,7 +102,8 @@ local function getDriveInfo(p) end end - recurse(p) + recurse(p) + local info = {} table.insert(info, { name = 'Type', value = peripheral.getType(drive) or drive }) table.insert(info, { name = 'Used', value = total }) @@ -113,7 +120,7 @@ function tab:updateInfo() local info, percent = getDriveInfo(selected and selected.name or self.drives.values[1].name) self.infos:setValues(info) self.progress.value = percent - self.percentage.value = ('%#3d%% used'):format(percent) + self.percentage.value = ('%#3d%%'):format(percent) self:draw() end @@ -137,7 +144,7 @@ function tab:eventHandler(event) end Event.on({ 'disk', 'disk_eject' }, function() - sleep(1) + os.sleep(1) tab:updateDrives() tab:updateInfo() tab:sync() From 9456d318819f19e461c121654ab999e17449c519 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 2 Jul 2019 14:32:41 -0400 Subject: [PATCH 174/231] oops --- sys/apps/system/diskusage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index c78ef96..3cec732 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -3,7 +3,7 @@ local Event = require('opus.event') local NFT = require('opus.nft') local colors = _G.colors -local fs = _G.files +local fs = _G.fs local os = _G.os local peripheral = _G.peripheral From 0b222207ba512d5c8248252b46665c99accce2e9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 3 Jul 2019 10:44:30 -0400 Subject: [PATCH 175/231] package manager improvements --- sys/apps/PackageManager.lua | 26 ++++++++++++++++++++++---- sys/apps/Welcome.lua | 7 +++++-- sys/apps/package.lua | 27 ++++++++++++++++++++++----- sys/autorun/complete.lua | 2 +- sys/init/6.packages.lua | 6 ------ sys/modules/opus/packages.lua | 3 +++ 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index de8af57..1329ec7 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -33,6 +33,12 @@ local page = UI.Page { operationText = 'Remove', help = 'Remove', }, + updateall = UI.Button { + ex = -2, y = -3, width = 12, + text = 'Update All', + event = 'updateall', + help = 'Update all installed packages', + }, description = UI.TextArea { x = 16, y = 3, ey = -5, marginRight = 0, marginLeft = 0, @@ -138,6 +144,13 @@ function page:eventHandler(event) self.description:draw() self:updateSelection(event.selected) + elseif event.type == 'updateall' then + self.operation = 'updateall' + self.action.button.text = ' Begin ' + self.action.button.event = 'begin' + self.action.titleBar.title = 'Update All' + self.action:show() + elseif event.type == 'action' then local selected = self.grid:getSelected() if selected then @@ -153,11 +166,16 @@ function page:eventHandler(event) self.action:hide() elseif event.type == 'begin' then - local selected = self.grid:getSelected() - self:run(self.operation, selected.name) - selected.installed = Packages:isInstalled(selected.name) + if self.operation == 'updateall' then + self:run(self.operation, '') + else + local selected = self.grid:getSelected() + self:run(self.operation, selected.name) + selected.installed = Packages:isInstalled(selected.name) + + self:updateSelection(selected) + end - self:updateSelection(selected) self.action.button.text = ' Done ' self.action.button.event = 'hide-action' self.action.button:draw() diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 5405174..47c658f 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -25,7 +25,10 @@ Anavrins: Encryption/security/custom apps Community: Several selected applications hugeblank: Startup screen improvements LDDestroier: Art design + custom apps -Lemmmy: Application improvements]] +Lemmmy: Application improvements + +%sContribute at:%s +https://github.com/kepler155c/opus]] local page = UI.Page { wizard = UI.Wizard { @@ -108,7 +111,7 @@ local page = UI.Page { textColor = colors.yellow, inactive = true, x = 3, ex = -3, y = 2, ey = -2, - value = string.format(contributorsIntro, Ansi.white), + value = string.format(contributorsIntro, Ansi.white, Ansi.yellow, Ansi.white), }, }, }, diff --git a/sys/apps/package.lua b/sys/apps/package.lua index 864f4fd..3d95c17 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -35,13 +35,15 @@ local function progress(max) end end -local function install(name, isUpdate) +local function install(name, isUpdate, ignoreDeps) local manifest = Packages:downloadManifest(name) or error('Invalid package') - if manifest.required then - for _, v in pairs(manifest.required) do - if isUpdate or not Packages:isInstalled(v) then - install(v, isUpdate) + if not ignoreDeps then + if manifest.required then + for _, v in pairs(manifest.required) do + if isUpdate or not Packages:isInstalled(v) then + install(v, isUpdate) + end end end end @@ -89,6 +91,21 @@ if action == 'install' then return end +if action == 'refresh' then + print('Downloading...') + Packages:downloadList() + print('refresh complete') + return +end + +if action == 'updateall' then + for name in pairs(Packages:installed()) do + install(name, true, true) + end + print('updateall complete') + return +end + if action == 'update' then local name = args[1] or Syntax('Invalid package') if not Packages:isInstalled(name) then diff --git a/sys/autorun/complete.lua b/sys/autorun/complete.lua index 82b2fe5..31a6bd9 100644 --- a/sys/autorun/complete.lua +++ b/sys/autorun/complete.lua @@ -17,6 +17,6 @@ end _ENV.shell.setCompletionFunction("sys/apps/package.lua", function(_, index, text) if index == 1 then - return completeMultipleChoice(text, { "install ", "update ", "uninstall " }) + return completeMultipleChoice(text, { "install ", "update ", "uninstall ", "updateall ", "refresh" }) end end) diff --git a/sys/init/6.packages.lua b/sys/init/6.packages.lua index c991821..b1e6ef7 100644 --- a/sys/init/6.packages.lua +++ b/sys/init/6.packages.lua @@ -5,12 +5,6 @@ local fs = _G.fs local help = _G.help local shell = _ENV.shell -if not fs.exists('usr/config/packages') then - pcall(function() - Packages:downloadList() - end) -end - local appPaths = Util.split(shell.path(), '(.-):') local helpPaths = Util.split(help.path(), '(.-):') diff --git a/sys/modules/opus/packages.lua b/sys/modules/opus/packages.lua index c54bb65..a3890da 100644 --- a/sys/modules/opus/packages.lua +++ b/sys/modules/opus/packages.lua @@ -21,6 +21,9 @@ function Packages:installed() end function Packages:list() + if not fs.exists('usr/config/packages') then + self:downloadList() + end return Util.readTable('usr/config/packages') or { } end From ddb5433c0176d1d345f8cf33965baa4eaec99fd2 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Thu, 4 Jul 2019 21:33:47 -0400 Subject: [PATCH 176/231] New sniffer app --- sys/apps/Network.lua | 4 +- sys/apps/Sniff.lua | 361 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 362 insertions(+), 3 deletions(-) create mode 100644 sys/apps/Sniff.lua diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index 52be626..c437fe9 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -44,7 +44,7 @@ local page = UI.Page { x = -3, dropdown = { { text = 'Port Status', event = 'ports', modem = true }, - { spacer = true }, + { spacer = true }, { text = 'Help', event = 'help', noCheck = true }, }, }, @@ -127,14 +127,12 @@ local function sendCommand(host, command) end end ---[[ function page.ports:eventHandler(event) if event.type == 'grid_select' then shell.openForegroundTab('sniff ' .. event.selected.port) end return UI.SlideOut.eventHandler(self, event) end -]] function page.ports.grid:update() local transport = network:getTransport() diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua new file mode 100644 index 0000000..8499c72 --- /dev/null +++ b/sys/apps/Sniff.lua @@ -0,0 +1,361 @@ +local UI = require('opus.ui') +local Event = require('opus.event') +local Util = require('opus.util') + +local colors = _G.colors +local device = _G.device +local textutils = _G.textutils +local peripheral = _G.peripheral +local multishell = _ENV.multishell + +local gridColumns = {} +table.insert(gridColumns, { heading = '#', key = 'id', width = 4, align = 'right' }) +table.insert(gridColumns, { heading = 'Port', key = 'portid', width = 5, align = 'right' }) +table.insert(gridColumns, { heading = 'Reply', key = 'replyid', width = 5, align = 'right' }) +if UI.defaultDevice.width > 50 then table.insert(gridColumns, { heading = 'Dist', key = 'distance', width = 6, align = 'right' }) end +table.insert(gridColumns, { heading = 'Msg', key = 'message' }) + +local page = UI.Page { + paused = false, + index = 0, + notification = UI.Notification { }, + accelerators = { ['control-q'] = 'quit' }, + + menuBar = UI.MenuBar { + buttons = { + { text = 'Pause', event = 'pause_click', name = 'pauseButton' }, + { text = 'Clear', event = 'clear_click' }, + { text = 'Config', event = 'config_click' }, + }, + }, + + packetGrid = UI.ScrollingGrid { + y = 2, + maxPacket = 300, + inverseSort = true, + sortColumn = 'id', + columns = gridColumns, + accelerators = { ['space'] = 'pause_click' }, + }, + + configSlide = UI.SlideOut { + y = -11, + titleBar = UI.TitleBar { title = 'Sniffer Config', event = 'config_close' }, + accelerators = { ['backspace'] = 'config_close' }, + configTabs = UI.Tabs { + y = 2, + filterTab = UI.Tab { + tabTitle = 'Filter', + filterGridText = UI.Text { + x = 2, y = 2, + value = 'ID filter', + }, + filterGrid = UI.ScrollingGrid { + x = 2, y = 3, + width = 10, height = 4, + disableHeader = true, + columns = { + { key = 'id', width = 5 }, + }, + }, + filterEntry = UI.TextEntry { + x = 2, y = 8, + width = 7, + shadowText = 'ID', + limit = 5, + accelerators = { enter = 'filter_add' }, + }, + filterAdd = UI.Button { + x = 10, y = 8, + text = '+', + event = 'filter_add', + }, + filterAllCheck = UI.Checkbox { + x = 13, y = 4, + value = false, + }, + filterAddText = UI.Text { + x = 17, y = 4, + value = "Use ID filter", + }, + }, + modemTab = UI.Tab { + tabTitle = 'Modem', + channelGrid = UI.ScrollingGrid { + x = 2, y = 2, + width = 12, height = 5, + autospace = true, + columns = {{ heading = 'Open Ports', key = 'port' }}, + }, + modemGrid = UI.ScrollingGrid { + x = 15, y = 2, + ex = -2, height = 5, + autospace = true, + columns = { + { heading = 'Side', key = 'side' }, + { heading = 'Type', key = 'type' }, + }, + }, + channelEntry = UI.TextEntry { + x = 2, y = 8, + width = 7, + shadowText = 'ID', + limit = 5, + accelerators = { enter = 'channel_add' }, + }, + channelAdd = UI.Button { + x = 10, y = 8, + text = '+', + event = 'channel_add', + }, + }, + }, + }, + + packetSlide = UI.SlideOut { + titleBar = UI.TitleBar { + title = 'Packet Information', + event = 'packet_close', + }, + backgroundColor = colors.cyan, + accelerators = { + ['backspace'] = 'packet_close', + ['left'] = 'prev_packet', + ['right'] = 'next_packet', + }, + packetMeta = UI.Grid { + x = 2, y = 2, + ex = 23, height = 4, + inactive = true, + columns = { + { key = 'text' }, + { key = 'value', align = 'right', textColor = colors.yellow }, + }, + values = { + port = { text = 'Port' }, + reply = { text = 'Reply' }, + dist = { text = 'Distance' }, + } + }, + packetButton = UI.Button { + x = 25, y = 5, + text = 'Open in Lua', + event = 'packet_lua', + }, + packetData = UI.TextArea { + y = 7, ey = -1, + backgroundColor = colors.black, + }, + }, +} + +local filterConfig = page.configSlide.configTabs.filterTab +local modemConfig = page.configSlide.configTabs.modemTab + +function filterConfig:eventHandler(event) + if event.type == 'filter_add' then + local id = tonumber(self.filterEntry.value) + if id then self.filterGrid.values[id] = { id = id } + self.filterGrid:update() + self.filterEntry:reset() + self:draw() + end + + elseif event.type == 'grid_select' then + self.filterGrid.values[event.selected.id] = nil + self.filterGrid:update() + self.filterGrid:draw() + + else return UI.Tab.eventHandler(self, event) + end + return true +end + +function modemConfig:loadChannel() + for chan = 0, 65535 do + self.currentModem.openChannels[chan] = self.currentModem.device.isOpen(chan) and { port = chan } or nil + end + self.channelGrid:setValues(self.currentModem.openChannels) + self.currentModem.loaded = true +end + +function modemConfig:enable() + if not self.currentModem.loaded then + self:loadChannel() + end + + UI.Tab.enable(self) +end + +function modemConfig:eventHandler(event) + if event.type == 'channel_add' then + local id = tonumber(modemConfig.channelEntry.value) + if id then + self.currentModem.openChannels[id] = { port = id } + self.currentModem.device.open(id) + self.channelGrid:setValues(self.currentModem.openChannels) + self.channelGrid:update() + self.channelEntry:reset() + self:draw() + end + + elseif event.type == 'grid_select' then + if event.element == self.channelGrid then + self.currentModem.openChannels[event.selected.port] = nil + self.currentModem.device.close(event.selected.port) + self.channelGrid:setValues(self.currentModem.openChannels) + page.configSlide.configTabs.modemTab.channelGrid:update() + page.configSlide.configTabs.modemTab.channelGrid:draw() + + elseif event.element == self.modemGrid then + self.currentModem = event.selected + page.notification:info("Loading channel list") + page:sync() + modemConfig:loadChannel() + page.notification:success("Now using modem on " .. self.currentModem.side) + self.channelGrid:draw() + end + + else return UI.Tab.eventHandler(self, event) + end + return true +end + +function page.packetSlide:setPacket(packet) + self.currentPacket = packet + local p, res = pcall(textutils.serialize, page.packetSlide.currentPacket.message) + self.packetData.textColor = p and colors.white or colors.red + self.packetData:setText(res) + self.packetMeta.values.port.value = page.packetSlide.currentPacket.portid + self.packetMeta.values.reply.value = page.packetSlide.currentPacket.replyid + self.packetMeta.values.dist.value = Util.round(page.packetSlide.currentPacket.distance, 2) +end + +function page.packetSlide:show(packet) + self:setPacket(packet) + + UI.SlideOut.show(self) +end + +function page.packetSlide:eventHandler(event) + if event.type == 'packet_close' then + self:hide() + page:setFocus(page.packetGrid) + + elseif event.type == 'packet_lua' then + multishell.openTab({ path = 'sys/apps/Lua.lua', args = { self.currentPacket.message }, focused = true }) + + elseif event.type == 'prev_packet' then + local c = self.currentPacket + local n = page.packetGrid.values[c.id - 1] + if n then + self:setPacket(n) + self:draw() + end + + elseif event.type == 'next_packet' then + local c = self.currentPacket + local n = page.packetGrid.values[c.id + 1] + if n then + self:setPacket(n) + self:draw() + end + + else return UI.SlideOut.eventHandler(self, event) + end + return true +end + +function page:enable() + modemConfig.modems = {} + peripheral.find('modem', function(side, dev) + modemConfig.modems[side] = { + type = dev.isWireless() and 'Wireless' or 'Wired', + side = side, + openChannels = { }, + device = dev, + loaded = false + } + end) + modemConfig.currentModem = device.wireless_modem and + modemConfig.modems[device.wireless_modem.side] or + device.wired_modem and + modemConfig.modems[device.wired_modem.side] or + nil + + modemConfig.modemGrid.values = modemConfig.modems + modemConfig.modemGrid:update() + modemConfig.modemGrid:setSelected(modemConfig.currentModem) + + UI.Page.enable(self) +end + + +function page:eventHandler(event) + if event.type == 'pause_click' then + self.paused = not self.paused + self.menuBar.pauseButton.text = self.paused and 'Resume' or 'Pause' + self.notification:success(self.paused and 'Paused' or 'Resumed', 2) + self.menuBar:draw() + + elseif event.type == 'clear_click' then + self.packetGrid:setValues({ }) + self.notification:success('Cleared', 2) + self.packetGrid:draw() + + elseif event.type == 'config_click' then + self.configSlide:show() + self:setFocus(filterConfig.filterEntry) + + elseif event.type == 'config_close' then + self.configSlide:hide() + self:setFocus(self.packetGrid) + + elseif event.type == 'grid_select' then + self.packetSlide:show(event.selected) + + elseif event.type == 'quit' then + Event.exitPullEvents() + + else return UI.Page.eventHandler(self, event) + end + return true +end + +Event.on('modem_message', function(event, side, chan, reply, msg, dist) + if not page.paused and modemConfig.currentModem.side == side and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[chan]) then + page.index = page.index + 1 + table.insert(page.packetGrid.values, { + id = page.index, + portid = chan, + replyid = reply, + message = msg, + distance = dist, + }) + + if #page.packetGrid.values > page.packetGrid.maxPacket then + local t = { } + for i = 10, #page.packetGrid.values do + t[i - 9] = page.packetGrid.values[i] + end + page.packetGrid:setValues(t) + end + + page.packetGrid:update() + page.packetGrid:draw() + page:sync() + end +end) + +local args = {...} +if args[1] then + local id = tonumber(args[1]) + if id then + filterConfig.filterGrid.values[id] = { id = id } + filterConfig.filterAllCheck:setValue(true) + filterConfig.filterGrid:update() + end +end + +UI:setPage(page) +UI:pullEvents() From 08eac79109562d22b4d5c0e074727cf86bd26881 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Thu, 4 Jul 2019 21:46:09 -0400 Subject: [PATCH 177/231] Oops --- sys/apps/Network.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index c437fe9..bc551a4 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -129,7 +129,7 @@ end function page.ports:eventHandler(event) if event.type == 'grid_select' then - shell.openForegroundTab('sniff ' .. event.selected.port) + shell.openForegroundTab('Sniff ' .. event.selected.port) end return UI.SlideOut.eventHandler(self, event) end From 4a089ecd85d91404291af0b0762ab465ff6acb33 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Fri, 5 Jul 2019 02:14:28 -0400 Subject: [PATCH 178/231] Added icons to diskusage --- sys/apps/system/diskusage.lua | 222 +++++++++++++++++----------------- 1 file changed, 112 insertions(+), 110 deletions(-) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index 3cec732..c07c485 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -8,146 +8,148 @@ local os = _G.os local peripheral = _G.peripheral local NftImages = { - blank = '\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153', - drive = '', - rom = '', - hdd = '', + blank = '\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153', + disk = '\30\32\31\32\32\30\98\31\98\128\30\56\31\56\128\128\30\102\149\30\98\149\31\57\139\10\30\32\31\32\32\30\98\31\98\128\128\128\128\128\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128', + rom = '\30\57\31\57\128\31\56\144\144\144\144\144\31\57\128\10\30\56\31\57\157\30\55\31\55\128\128\128\128\128\30\57\31\56\145\10\30\57\31\56\136\30\55\31\55\128\30\55\31\48\82\79\77\30\55\128\30\57\31\56\132\10\30\56\31\57\157\30\55\31\55\128\128\128\128\128\30\57\31\56\145\10\30\57\31\57\128\31\56\129\129\129\129\129\31\57\128', + hdd = '\30\32\31\32\32\30\55\31\55\128\30\48\135\131\139\30\55\128\10\30\32\31\32\32\30\48\31\55\149\31\48\128\30\55\131\30\48\128\30\55\149\10\30\32\31\32\32\30\55\31\48\130\30\48\31\55\144\30\56\31\48\133\30\55\159\129\10\30\32\31\32\32\30\56\31\55\149\129\142\159\30\55\128\10\30\32\31\32\32\30\57\31\55\143\143\143\143\143', } local tab = UI.Tab { - tabTitle = 'Disks Usage', - description = 'Visualise HDD and disks usage', + tabTitle = 'Disks Usage', + description = 'Visualise HDD and disks usage', - drives = UI.ScrollingGrid { - x = 2, y = 1, - ex = '47%', ey = 8, - columns = { - { heading = 'Drive', key = 'name' }, - { heading = 'Side' ,key = 'side', textColor = colors.yellow } - }, - sortColumn = 'name', - }, - infos = UI.Grid { - x = '52%', y = 2, - ex = -2, ey = 8, - disableHeader = true, - unfocusedBackgroundSelectedColor = colors.black, - inactive = true, - backgroundSelectedColor = colors.black, - columns = { - { key = 'name' }, - { key = 'value', align = 'right', textColor = colors.yellow }, - } - }, + drives = UI.ScrollingGrid { + x = 2, y = 1, + ex = '47%', ey = 8, + columns = { + { heading = 'Drive', key = 'name' }, + { heading = 'Side' ,key = 'side', textColor = colors.yellow } + }, + sortColumn = 'name', + }, + infos = UI.Grid { + x = '52%', y = 2, + ex = -2, ey = 8, + disableHeader = true, + unfocusedBackgroundSelectedColor = colors.black, + inactive = true, + backgroundSelectedColor = colors.black, + columns = { + { key = 'name' }, + { key = 'value', align = 'right', textColor = colors.yellow }, + } + }, - progress = UI.ProgressBar { - x = 11, y = 10, - ex = -2, - }, - percentage = UI.Text { - x = 11, y = 11, - ex = -2, - align = 'center', - }, - icon = UI.NftImage { - x = 2, y = 10, - image = NFT.parse(NftImages.blank) - }, + progress = UI.ProgressBar { + x = 11, y = 10, + ex = -2, + }, + percentage = UI.Text { + x = 11, y = 11, + ex = -2, + align = 'center', + }, + icon = UI.NftImage { + x = 2, y = 10, + image = NFT.parse(NftImages.blank) + }, } local function getDrives() - local unique = { ['hdd'] = true, ['virt'] = true } - local exclude = {} - local drives = { - {name = 'hdd', side = ''}, - } - for _, drive in pairs(fs.list('/')) do - local side = fs.getDrive(drive) - if side and not unique[side] then - unique[side] = true - exclude[drive] = true - table.insert(drives, {name=drive, side=side}) - end - end - return drives, exclude + local unique = { ['hdd'] = true, ['virt'] = true } + local exclude = {} + local drives = { + {name = 'hdd', side = ''}, + } + for _, drive in pairs(fs.list('/')) do + local side = fs.getDrive(drive) + if side and not unique[side] then + unique[side] = true + exclude[drive] = true + table.insert(drives, {name=drive, side=side}) + end + end + return drives, exclude end local function getDriveInfo(p) - local files, dirs, total = 0, 0, 0 + local files, dirs, total = 0, 0, 0 - if p == "hdd" then p = "/" end - p = fs.combine(p, '') - local drive = fs.getDrive(p) + if p == "hdd" then p = "/" end + p = fs.combine(p, '') + local drive = fs.getDrive(p) - local function recurse(path) - if fs.getDrive(path) == drive then - if fs.isDir(path) then - if path ~= p then - total = total + 500 - dirs = dirs + 1 - end - for _, v in pairs(fs.list(path)) do - recurse(fs.combine(path, v)) - end - else - local sz = fs.getSize(path) + local function recurse(path) + if fs.getDrive(path) == drive then + if fs.isDir(path) then + if path ~= p then + total = total + 500 + dirs = dirs + 1 + end + for _, v in pairs(fs.list(path)) do + recurse(fs.combine(path, v)) + end + else + local sz = fs.getSize(path) + files = files + 1 + if drive == 'rom' then + total = total + sz + else + total = total + math.max(500, sz) + end + end + end + end - files = files + 1 - if drive == 'rom' then - total = total + sz - else - total = total + math.max(500, sz) - end - end - end - end + recurse(p) - recurse(p) - - local info = {} - table.insert(info, { name = 'Type', value = peripheral.getType(drive) or drive }) - table.insert(info, { name = 'Used', value = total }) - table.insert(info, { name = 'Total', value = total + fs.getFreeSpace(p) }) - table.insert(info, { name = 'Free', value = fs.getFreeSpace(p) }) - table.insert(info, { }) - table.insert(info, { name = 'Files', value = files }) - table.insert(info, { name = 'Dirs', value = dirs }) - return info, math.floor((total / (total + fs.getFreeSpace(p))) * 100) + local info = {} + table.insert(info, { name = 'Type', value = peripheral.getType(drive) or drive }) + table.insert(info, { name = 'Used', value = total }) + table.insert(info, { name = 'Total', value = total + fs.getFreeSpace(p) }) + table.insert(info, { name = 'Free', value = fs.getFreeSpace(p) }) + table.insert(info, { }) + table.insert(info, { name = 'Files', value = files }) + table.insert(info, { name = 'Dirs', value = dirs }) + return info, math.floor((total / (total + fs.getFreeSpace(p))) * 100) end function tab:updateInfo() - local selected = self.drives:getSelected() - local info, percent = getDriveInfo(selected and selected.name or self.drives.values[1].name) - self.infos:setValues(info) - self.progress.value = percent - self.percentage.value = ('%#3d%%'):format(percent) - self:draw() + local selected = self.drives:getSelected() + _syslog(selected) + local info, percent = getDriveInfo(selected and selected.name or self.drives.values[1].name) + self.infos:setValues(info) + self.progress.value = percent + self.percentage.value = ('%#3d%%'):format(percent) + self.icon.image = NFT.parse(NftImages[selected.name] or NftImages.blank) + self:draw() end function tab:updateDrives() - local drives, exclude = getDrives() - self.exclude = exclude - self.drives:setValues(drives) + local drives, exclude = getDrives() + self.exclude = exclude + self.drives:setValues(drives) end function tab:enable() - self:updateDrives() - self:updateInfo() - UI.Tab.enable(self) + self:updateDrives() + self:updateInfo() + UI.Tab.enable(self) end function tab:eventHandler(event) - if event.type == 'grid_focus_row' then - self:updateInfo() - end - return UI.Tab.eventHandler(self, event) + if event.type == 'grid_focus_row' then + self:updateInfo() + else return UI.Tab.eventHandler(self, event) + end + return true end Event.on({ 'disk', 'disk_eject' }, function() - os.sleep(1) - tab:updateDrives() - tab:updateInfo() - tab:sync() + os.sleep(1) + tab:updateDrives() + tab:updateInfo() + tab:sync() end) return tab From 88d06267eadec8972d6a121971af617a0aac5c64 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Fri, 5 Jul 2019 19:10:44 -0400 Subject: [PATCH 179/231] More refactor --- sys/apps/Sniff.lua | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua index 8499c72..3e82605 100644 --- a/sys/apps/Sniff.lua +++ b/sys/apps/Sniff.lua @@ -9,7 +9,7 @@ local peripheral = _G.peripheral local multishell = _ENV.multishell local gridColumns = {} -table.insert(gridColumns, { heading = '#', key = 'id', width = 4, align = 'right' }) +table.insert(gridColumns, { heading = '#', key = 'id', width = 5, align = 'right' }) table.insert(gridColumns, { heading = 'Port', key = 'portid', width = 5, align = 'right' }) table.insert(gridColumns, { heading = 'Reply', key = 'replyid', width = 5, align = 'right' }) if UI.defaultDevice.width > 50 then table.insert(gridColumns, { heading = 'Dist', key = 'distance', width = 6, align = 'right' }) end @@ -17,7 +17,7 @@ table.insert(gridColumns, { heading = 'Msg', key = 'message' }) local page = UI.Page { paused = false, - index = 0, + index = 1, notification = UI.Notification { }, accelerators = { ['control-q'] = 'quit' }, @@ -266,6 +266,24 @@ function page.packetSlide:eventHandler(event) return true end +function page.packetGrid:addPacket(packet) + if not page.paused and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[packet.portid]) then + page.index = page.index + 1 + table.insert(self.values, packet) + end + if #self.values > self.maxPacket then + local t = { } + for i = 10, #self.values do + t[i - 9] = self.values[i] + end + self:setValues(t) + end + + self:update() + self:draw() + page:sync() +end + function page:enable() modemConfig.modems = {} peripheral.find('modem', function(side, dev) @@ -323,27 +341,14 @@ function page:eventHandler(event) end Event.on('modem_message', function(event, side, chan, reply, msg, dist) - if not page.paused and modemConfig.currentModem.side == side and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[chan]) then - page.index = page.index + 1 - table.insert(page.packetGrid.values, { + if modemConfig.currentModem.side == side then + page.packetGrid:addPacket({ id = page.index, portid = chan, replyid = reply, message = msg, distance = dist, }) - - if #page.packetGrid.values > page.packetGrid.maxPacket then - local t = { } - for i = 10, #page.packetGrid.values do - t[i - 9] = page.packetGrid.values[i] - end - page.packetGrid:setValues(t) - end - - page.packetGrid:update() - page.packetGrid:draw() - page:sync() end end) From f1b9dcc4f4f48d9475fdf3869dc2d65e67c07ba1 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Fri, 5 Jul 2019 19:45:29 -0400 Subject: [PATCH 180/231] Last oopsie --- sys/apps/system/diskusage.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index c07c485..3749642 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -9,7 +9,7 @@ local peripheral = _G.peripheral local NftImages = { blank = '\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153', - disk = '\30\32\31\32\32\30\98\31\98\128\30\56\31\56\128\128\30\102\149\30\98\149\31\57\139\10\30\32\31\32\32\30\98\31\98\128\128\128\128\128\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128', + drive = '\30\32\31\32\32\30\98\31\98\128\30\56\31\56\128\128\30\102\149\30\98\149\31\57\139\10\30\32\31\32\32\30\98\31\98\128\128\128\128\128\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128', rom = '\30\57\31\57\128\31\56\144\144\144\144\144\31\57\128\10\30\56\31\57\157\30\55\31\55\128\128\128\128\128\30\57\31\56\145\10\30\57\31\56\136\30\55\31\55\128\30\55\31\48\82\79\77\30\55\128\30\57\31\56\132\10\30\56\31\57\157\30\55\31\55\128\128\128\128\128\30\57\31\56\145\10\30\57\31\57\128\31\56\129\129\129\129\129\31\57\128', hdd = '\30\32\31\32\32\30\55\31\55\128\30\48\135\131\139\30\55\128\10\30\32\31\32\32\30\48\31\55\149\31\48\128\30\55\131\30\48\128\30\55\149\10\30\32\31\32\32\30\55\31\48\130\30\48\31\55\144\30\56\31\48\133\30\55\159\129\10\30\32\31\32\32\30\56\31\55\149\129\142\159\30\55\128\10\30\32\31\32\32\30\57\31\55\143\143\143\143\143', } @@ -116,12 +116,11 @@ end function tab:updateInfo() local selected = self.drives:getSelected() - _syslog(selected) local info, percent = getDriveInfo(selected and selected.name or self.drives.values[1].name) self.infos:setValues(info) self.progress.value = percent self.percentage.value = ('%#3d%%'):format(percent) - self.icon.image = NFT.parse(NftImages[selected.name] or NftImages.blank) + self.icon.image = NFT.parse(NftImages[info[1].value] or NftImages.blank) self:draw() end From ae2ea81d1d3720809bcbf269a74fd36e7900d480 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Sat, 6 Jul 2019 21:56:21 -0400 Subject: [PATCH 181/231] Show serialized packet in packetGrid --- sys/apps/Sniff.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua index 3e82605..b90bbe8 100644 --- a/sys/apps/Sniff.lua +++ b/sys/apps/Sniff.lua @@ -13,7 +13,7 @@ table.insert(gridColumns, { heading = '#', key = 'id', width = 5, align = 'righ table.insert(gridColumns, { heading = 'Port', key = 'portid', width = 5, align = 'right' }) table.insert(gridColumns, { heading = 'Reply', key = 'replyid', width = 5, align = 'right' }) if UI.defaultDevice.width > 50 then table.insert(gridColumns, { heading = 'Dist', key = 'distance', width = 6, align = 'right' }) end -table.insert(gridColumns, { heading = 'Msg', key = 'message' }) +table.insert(gridColumns, { heading = 'Msg', key = 'packetStr' }) local page = UI.Page { paused = false, @@ -269,6 +269,8 @@ end function page.packetGrid:addPacket(packet) if not page.paused and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[packet.portid]) then page.index = page.index + 1 + local p, res = pcall(textutils.serialize, packet.message) + packet.packetStr = res:gsub("\n%s*", "") table.insert(self.values, packet) end if #self.values > self.maxPacket then @@ -341,7 +343,7 @@ function page:eventHandler(event) end Event.on('modem_message', function(event, side, chan, reply, msg, dist) - if modemConfig.currentModem.side == side then + if modemConfig.currentModem.side == side then page.packetGrid:addPacket({ id = page.index, portid = chan, From cf87c29cf62f5b15ae300e2700d176201aa3d120 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 6 Jul 2019 23:52:29 -0400 Subject: [PATCH 182/231] lint warnings + old file cleanup --- sys/apps/Sniff.lua | 8 +++++--- sys/autorun/upgraded.lua | 23 ++++++++++++----------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua index b90bbe8..c0d299b 100644 --- a/sys/apps/Sniff.lua +++ b/sys/apps/Sniff.lua @@ -12,7 +12,9 @@ local gridColumns = {} table.insert(gridColumns, { heading = '#', key = 'id', width = 5, align = 'right' }) table.insert(gridColumns, { heading = 'Port', key = 'portid', width = 5, align = 'right' }) table.insert(gridColumns, { heading = 'Reply', key = 'replyid', width = 5, align = 'right' }) -if UI.defaultDevice.width > 50 then table.insert(gridColumns, { heading = 'Dist', key = 'distance', width = 6, align = 'right' }) end +if UI.defaultDevice.width > 50 then + table.insert(gridColumns, { heading = 'Dist', key = 'distance', width = 6, align = 'right' }) +end table.insert(gridColumns, { heading = 'Msg', key = 'packetStr' }) local page = UI.Page { @@ -269,7 +271,7 @@ end function page.packetGrid:addPacket(packet) if not page.paused and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[packet.portid]) then page.index = page.index + 1 - local p, res = pcall(textutils.serialize, packet.message) + local _, res = pcall(textutils.serialize, packet.message) packet.packetStr = res:gsub("\n%s*", "") table.insert(self.values, packet) end @@ -342,7 +344,7 @@ function page:eventHandler(event) return true end -Event.on('modem_message', function(event, side, chan, reply, msg, dist) +Event.on('modem_message', function(_, side, chan, reply, msg, dist) if modemConfig.currentModem.side == side then page.packetGrid:addPacket({ id = page.index, diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index 6cb1c92..96bd5f1 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -1,13 +1,14 @@ -if fs.exists('sys/apps/shell') and fs.exists('sys/apps/shell.lua') then - fs.delete('sys/apps/shell') -end -if fs.exists('sys/etc/app.db') then fs.delete('sys/etc/app.db') end -if fs.exists('sys/extensions') then fs.delete('sys/extensions') end -if fs.exists('sys/network') then fs.delete('sys/network') end -if fs.exists('startup') then fs.delete('startup') end +local fs = _G.fs -if fs.exists('sys/autorun/gps.lua') then fs.delete('sys/autorun/gps.lua') end -if fs.exists('sys/autorun/gpsHost.lua') then fs.delete('sys/autorun/gpsHost.lua') end -if fs.exists('sys/apps/network/redserver.lua') then fs.delete('sys/apps/network/redserver.lua') end +-- cleanup outdated files +fs.delete('sys/apps/shell') +fs.delete('sys/etc/app.db') +fs.delete('sys/extensions') +fs.delete('sys/network') +fs.delete('startup') +fs.delete('sys/apps/system/turtle.lua') +fs.delete('sys/autorun/gps.lua') +fs.delete('sys/autorun/gpsHost.lua') +fs.delete('sys/apps/network/redserver.lua') if fs.exists('sys/apis') then fs.delete('sys/apis') end -if fs.exists('sys/autorun/apps.lua') then fs.delete('sys/autorun/apps.lua') end +fs.delete('sys/autorun/apps.lua') From 86cd6e3c0e13fb3ea0e16bf26c05e3b29b0db871 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 7 Jul 2019 01:14:39 -0400 Subject: [PATCH 183/231] app icons --- sys/apps/system/diskusage.lua | 12 ++++++------ sys/autorun/upgraded.lua | 2 +- sys/etc/apps.db | 6 ++++++ sys/modules/opus/packages.lua | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index 3749642..99e3547 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -20,7 +20,7 @@ local tab = UI.Tab { drives = UI.ScrollingGrid { x = 2, y = 1, - ex = '47%', ey = 8, + ex = '47%', ey = -7, columns = { { heading = 'Drive', key = 'name' }, { heading = 'Side' ,key = 'side', textColor = colors.yellow } @@ -29,7 +29,7 @@ local tab = UI.Tab { }, infos = UI.Grid { x = '52%', y = 2, - ex = -2, ey = 8, + ex = -2, ey = -4, disableHeader = true, unfocusedBackgroundSelectedColor = colors.black, inactive = true, @@ -41,16 +41,16 @@ local tab = UI.Tab { }, progress = UI.ProgressBar { - x = 11, y = 10, + x = 11, y = -2, ex = -2, }, percentage = UI.Text { - x = 11, y = 11, + x = 11, y = -1, ex = -2, align = 'center', }, icon = UI.NftImage { - x = 2, y = 10, + x = 2, y = -5, image = NFT.parse(NftImages.blank) }, } @@ -151,4 +151,4 @@ Event.on({ 'disk', 'disk_eject' }, function() tab:sync() end) -return tab +return tab \ No newline at end of file diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index 96bd5f1..f6881db 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -8,7 +8,7 @@ fs.delete('sys/network') fs.delete('startup') fs.delete('sys/apps/system/turtle.lua') fs.delete('sys/autorun/gps.lua') -fs.delete('sys/autorun/gpsHost.lua') +fs.delete('sys/autorun/gpshost.lua') fs.delete('sys/apps/network/redserver.lua') if fs.exists('sys/apis') then fs.delete('sys/apis') end fs.delete('sys/autorun/apps.lua') diff --git a/sys/etc/apps.db b/sys/etc/apps.db index d7ea0dd..951778a 100644 --- a/sys/etc/apps.db +++ b/sys/etc/apps.db @@ -100,6 +100,12 @@ \030 \031f\030f\0318\143\133\0312\136\0302\031f\159\159\143\131\030f\0312\132", run = "pain", }, + [ "6a381ca189cbddd63737cbaf6e8b593844ce467ba52b1c5e5e05d8f29864385d" ] = { + title = "Sniff", + category = "Apps", + icon = "\31\102\128\128\128\128\31\53\149\30\53\31\102\154\30\102\31\53\137\10\30\52\31\102\159\31\52\128\128\30\102\144\31\53\130\30\53\31\102\155\140\10\31\52\151\30\52\31\102\148\30\102\31\52\151\30\52\31\102\148\30\102\128\128\128", + run = "Sniff.lua", + }, [ "01c933b2a36ad8ed2d54089cb2903039046c1216" ] = { title = "Enchat", icon = "\030e\031f\151\030f\031e\156\0311\140\0314\140\0315\140\031d\140\031b\140\031a\132\ diff --git a/sys/modules/opus/packages.lua b/sys/modules/opus/packages.lua index a3890da..0c5187a 100644 --- a/sys/modules/opus/packages.lua +++ b/sys/modules/opus/packages.lua @@ -33,7 +33,7 @@ end function Packages:downloadList() local packages = { - [ 'develop-1.8' ] = 'https://pastebin.com/raw/WhEiNGZE', + [ 'develop-1.8' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/packages.list', [ 'master-1.8' ] = 'https://pastebin.com/raw/pexZpAxt', } From ccc7693f460cefd602dde746c8eb3147ad267319 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 8 Jul 2019 00:16:28 -0400 Subject: [PATCH 184/231] minor tweaks --- sys/apps/Sniff.lua | 2 +- sys/apps/network/snmp.lua | 2 ++ sys/etc/apps.db | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua index c0d299b..6a683eb 100644 --- a/sys/apps/Sniff.lua +++ b/sys/apps/Sniff.lua @@ -351,7 +351,7 @@ Event.on('modem_message', function(_, side, chan, reply, msg, dist) portid = chan, replyid = reply, message = msg, - distance = dist, + distance = dist or -1, }) end end) diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index ff42b99..ad976a4 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -215,3 +215,5 @@ Event.on('turtle_response', function() sendInfo() end end) + +sendInfo() diff --git a/sys/etc/apps.db b/sys/etc/apps.db index 951778a..edfabba 100644 --- a/sys/etc/apps.db +++ b/sys/etc/apps.db @@ -101,7 +101,7 @@ run = "pain", }, [ "6a381ca189cbddd63737cbaf6e8b593844ce467ba52b1c5e5e05d8f29864385d" ] = { - title = "Sniff", + title = "Sniffer", category = "Apps", icon = "\31\102\128\128\128\128\31\53\149\30\53\31\102\154\30\102\31\53\137\10\30\52\31\102\159\31\52\128\128\30\102\144\31\53\130\30\53\31\102\155\140\10\31\52\151\30\52\31\102\148\30\102\31\52\151\30\52\31\102\148\30\102\128\128\128", run = "Sniff.lua", From 4c2d1215627e6e9b8a63130c2655be89b0ff2512 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 8 Jul 2019 13:52:53 -0400 Subject: [PATCH 185/231] reduce net traffic --- sys/apps/network/snmp.lua | 54 +++++++++++++++++++---------------- sys/apps/system/diskusage.lua | 23 +++++++-------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/sys/apps/network/snmp.lua b/sys/apps/network/snmp.lua index ad976a4..0fc9a34 100644 --- a/sys/apps/network/snmp.lua +++ b/sys/apps/network/snmp.lua @@ -121,8 +121,7 @@ print('discovery: listening on port 999') Event.on('modem_message', function(_, _, sport, id, info, distance) if sport == 999 and tonumber(id) and type(info) == 'table' then - if info.label and info.id and - type(info.label) == 'string' and type(info.id) == 'number' then + if type(info.label) == 'string' and type(info.id) == 'number' then if not network[id] then network[id] = { } @@ -150,6 +149,15 @@ local info = { } local infoTimer = os.clock() +local function getSlots() + return Util.reduce(turtle.getInventory(), function(acc, v) + if v.count > 0 then + acc[v.index .. ',' .. v.count] = v.key + end + return acc + end, { }) +end + local function sendInfo() if os.clock() - infoTimer >= 1 then -- don't flood infoTimer = os.clock() @@ -160,7 +168,7 @@ local function sendInfo() info.fuel = turtle.getFuelLevel() info.status = turtle.getStatus() info.point = turtle.point - info.inventory = turtle.getInventory() + info.inv = getSlots() info.slotIndex = turtle.getSelectedSlot() end if device.neuralInterface then @@ -168,28 +176,24 @@ local function sendInfo() if not info.status and device.neuralInterface.getMetaOwner then pcall(function() local meta = device.neuralInterface.getMetaOwner() - - if meta.isWet then - info.status = 'Swimming' - elseif meta.isElytraFlying then - info.status = 'Flying' - elseif meta.isBurning then - info.status = 'Burning' - elseif meta.isDead then - info.status = 'Deceased' - elseif meta.isOnLadder then - info.status = 'Climbing' - elseif meta.isRiding then - info.status = 'Riding' - elseif meta.isSneaking then - info.status = 'Sneaking' - elseif meta.isSprinting then - info.status = 'Running' - else - info.status = 'health: ' .. - math.floor(meta.health / - meta.maxHealth * 100) + local states = { + isWet = 'Swimming', + isElytraFlying = 'Flying', + isBurning = 'Burning', + isDead = 'Deceased', + isOnLadder = 'Climbing', + isRiding = 'Riding', + isSneaking = 'Sneaking', + isSprinting = 'Running', + } + for k,v in pairs(states) do + if meta[k] then + info.status = v + break + end end + info.status = info.status or 'health: ' .. + math.floor(meta.health / meta.maxHealth * 100) end) end end @@ -216,4 +220,4 @@ Event.on('turtle_response', function() end end) -sendInfo() +Event.onTimeout(1, sendInfo) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index 99e3547..8fbdd71 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -45,8 +45,8 @@ local tab = UI.Tab { ex = -2, }, percentage = UI.Text { - x = 11, y = -1, - ex = -2, + x = 11, y = -3, + ex = '47%', align = 'center', }, icon = UI.NftImage { @@ -57,19 +57,16 @@ local tab = UI.Tab { local function getDrives() local unique = { ['hdd'] = true, ['virt'] = true } - local exclude = {} - local drives = { - {name = 'hdd', side = ''}, - } + local drives = { { name = 'hdd', side = '' } } + for _, drive in pairs(fs.list('/')) do local side = fs.getDrive(drive) if side and not unique[side] then unique[side] = true - exclude[drive] = true - table.insert(drives, {name=drive, side=side}) + table.insert(drives, { name = drive, side = side }) end end - return drives, exclude + return drives end local function getDriveInfo(p) @@ -125,8 +122,7 @@ function tab:updateInfo() end function tab:updateDrives() - local drives, exclude = getDrives() - self.exclude = exclude + local drives = getDrives() self.drives:setValues(drives) end @@ -139,7 +135,8 @@ end function tab:eventHandler(event) if event.type == 'grid_focus_row' then self:updateInfo() - else return UI.Tab.eventHandler(self, event) + else + return UI.Tab.eventHandler(self, event) end return true end @@ -151,4 +148,4 @@ Event.on({ 'disk', 'disk_eject' }, function() tab:sync() end) -return tab \ No newline at end of file +return tab From 8f176572633f2026f224b09eef5124a994011c4b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 10 Jul 2019 11:06:29 -0600 Subject: [PATCH 186/231] make page/window themeable - oops --- sys/modules/opus/ui.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 50864c7..5f2245e 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -1217,6 +1217,8 @@ end loadComponents() UI:loadTheme('usr/config/ui.theme') +Util.merge(UI.Window.defaults, UI.theme.Window) +Util.merge(UI.Page.defaults, UI.theme.Page) UI:setDefaultDevice(UI.Device({ device = term.current() })) return UI From 0e1b712adcbb1f4c2a2c44658efb64ea82463230 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 10 Jul 2019 19:02:46 -0600 Subject: [PATCH 187/231] ntf transparency --- sys/modules/opus/nft.lua | 7 ++++--- sys/modules/opus/ui.lua | 8 +++++--- sys/modules/opus/ui/components/NftImage.lua | 5 ++++- sys/modules/opus/util.lua | 4 ++-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sys/modules/opus/nft.lua b/sys/modules/opus/nft.lua index f6d5468..52d5c6c 100644 --- a/sys/modules/opus/nft.lua +++ b/sys/modules/opus/nft.lua @@ -50,9 +50,10 @@ function NFT.parse(imageText) currFG = getColourOf(nextChar) fgNext = false else - if nextChar ~= " " and currFG == nil then - currFG = _G.colors.white - end + --if nextChar ~= " " and currFG == nil then + -- any color not in range is considered transparent + -- currFG = _G.colors.white + --end image.bg[num][writeIndex] = currBG image.fg[num][writeIndex] = currFG image.text[num][writeIndex] = nextChar diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 5f2245e..0acfb16 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -912,10 +912,12 @@ function UI.Window:emit(event) end end +function UI.Window:getProperty(property) + return self[property] or self.parent and self.parent:getProperty(property) +end + function UI.Window:find(uid) - if self.children then - return Util.find(self.children, 'uid', uid) - end + return self.children and Util.find(self.children, 'uid', uid) end function UI.Window:eventHandler() diff --git a/sys/modules/opus/ui/components/NftImage.lua b/sys/modules/opus/ui/components/NftImage.lua index 3457711..4d295d7 100644 --- a/sys/modules/opus/ui/components/NftImage.lua +++ b/sys/modules/opus/ui/components/NftImage.lua @@ -17,9 +17,12 @@ end function UI.NftImage:draw() if self.image then + -- due to blittle, the background and foreground transparent + -- color is the same as the background color + local bg = self:getProperty('backgroundColor') for y = 1, self.image.height do for x = 1, #self.image.text[y] do - self:write(x, y, self.image.text[y][x], self.image.bg[y][x], self.image.fg[y][x]) + self:write(x, y, self.image.text[y][x], self.image.bg[y][x], self.image.fg[y][x] or bg) end end else diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index e670857..2c8e097 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -412,8 +412,8 @@ function Util.first(t, order) end --[[ File functions ]]-- -function Util.readFile(fname) - local f = fs.open(fname, "r") +function Util.readFile(fname, flags) + local f = fs.open(fname, flags or "r") if f then local t = f.readAll() f.close() From e9559165a443d4df65a279668dd774be790bc521 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 11 Jul 2019 00:42:57 -0600 Subject: [PATCH 188/231] icon transparency --- sys/apps/Overview.lua | 4 --- sys/etc/apps.db | 69 ++++++++++++---------------------------- sys/etc/fstab | 3 +- sys/modules/opus/nft.lua | 37 +++++++++------------ 4 files changed, 37 insertions(+), 76 deletions(-) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index bfcbbb3..8cd2c92 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -155,10 +155,6 @@ local page = UI.Page { }, } -if extSupport then - page.container.backgroundColor = colors.black -end - local function loadApplications() local requirements = { turtle = not not turtle, diff --git a/sys/etc/apps.db b/sys/etc/apps.db index edfabba..7bf79ab 100644 --- a/sys/etc/apps.db +++ b/sys/etc/apps.db @@ -3,17 +3,13 @@ title = "Packages", category = "System", run = "PackageManager.lua", - iconExt = "\030c\0317\151\131\131\131\0307\031c\148\ -\030c\0317\151\131\0310\143\0317\131\0307\031c\148\ -\0307\031c\138\030f\0317\151\131\131\131", + iconExt = "\030c\0317\151\131\131\131\0307\031c\148\010\030c\0317\151\131\0310\143\0317\131\0307\031c\148\010\0307\031c\138\030 \0317\151\131\131\131", }, [ "b2efeaa1a7d6d2185ea02473cf758203dfcea3fe" ] = { title = "Cloud", category = "Apps", run = "cshell.lua", - iconExt = "\0300\031f\159\131\135\0310\128\128\031f\139\131\030f\0310\144\ -\0300\128\031f\137\144\0310\128\030a\136\149\133\0300\128\ -\0300\031f\144\134\136\132\031a\142\138\138\030f\0310\159", + iconExt = "\0300\031 \159\131\135\0310\128\128\031 \139\131\030 \0310\144\010\0300\128\031f\137\144\0310\128\030a\136\149\133\0300\128\010\0300\031 \144\031f\134\136\132\031a\142\138\138\030 \0310\159", }, [ "53ebc572b4a44802ba114729f07bdaaf5409a9d7" ] = { title = "Network", @@ -21,9 +17,7 @@ icon = "\0304 \030 \ \030f \0304 \0307 \030 \031 \031f)\ \030f \0304 \0307 \030 \031f)", - iconExt = "\030 \031f \0305\031f\140\030f\0315\137\144\ -\030 \031f\030f\0314\131\131\0304\031f\148\030 \0305\155\150\149\ -\030 \031f\030f\0310\147\0300\031f\141\0304\149\0307\0318\149\030 ", + iconExt = "\030 \031 \128\128\128\128\0305\140\030 \0315\137\144\010\0314\131\131\0304\031f\148\030 \031 \128\0305\155\150\149\010\147\0300\031f\141\0304\149\0307\0318\149\030 \031 \128\128\128", run = "Network.lua", }, c7116629a6a855cb774d9c7c8ad822fd83c71fb5 = { @@ -32,9 +26,7 @@ icon = "\0304\031f \030f\0310o..\0304\031f \ \0304\031f \030f\0310.o.\0304\031f \ \0304\031f - ", - iconExt = "\0307\031f\135\0300\0317\159\0307\0310\144\031f\139\ -\0300\0317\131\0307\0310\147\0300\0317\156\131\ -\130\143\143\129", + iconExt = "\0307\031 \135\0300\0317\159\0307\0310\144\031 \139\010\0300\0317\131\0307\0310\147\0300\0317\156\131\010\030 \130\143\143\129", run = "rom/programs/reboot", }, fb91e24fa52d8d2b32937bf04d843f730319a902 = { @@ -43,9 +35,7 @@ icon = "\0301\03171\03180\030 \031 \ \0301\03181\030 \031 \ \0301\03170\03180\03171\0307\031f>", - iconExt = "\031f\128\0313\152\131\131\132\031f\128\ -\0313\139\159\129\0303\031f\159\129\139\ -\031f\128\0313\136\0303\031f\143\143\030f\0313\134\031f\128", + iconExt = "\030 \031 \128\0313\152\131\131\132\031 \128\010\030 \0313\139\159\129\0303\031 \159\129\139\010\030 \031 \128\0313\136\0303\031 \143\143\030 \0313\134\031 \128", run = "update update", }, c47ae15370cfe1ed2781eedc1dc2547d12d9e972 = { @@ -54,9 +44,7 @@ icon = " \031f?\031 \ \031f?\031 \ \031f?", - iconExt = "\0300\031f\129\030f\0310\131\0300\031f\148\030f\0310\148\ -\030 \031 \0300\031f\131\030f\0310\142\129\ -\030 \031 \0300\031f\131\030f\128", + iconExt = "\0300\031 \129\030 \0310\131\0300\031 \148\030 \0310\148\010\030 \031 \128\0300\131\030 \0310\142\129\010\030 \031 \128\0300\131\030 \128\128", run = "Help.lua", }, b0832074630eb731d7fbe8074de48a90cd9bb220 = { @@ -65,9 +53,7 @@ icon = "\030f \ \030f\0310lua>\031 \ \030f ", - iconExt = "\0300\031f\151\030f\128\0300\159\159\159\030f\0310\144\0304\031f\159\030f\128\ -\0300\031f\149\030f\128\0300\149\149\151\145\030f\128\0314\153\ -\130\131\130\131\130\131\0314\130\031f\128", + iconExt = "\0300\031 \151\030 \128\0300\159\159\159\030 \0310\144\0304\031 \159\030 \128\010\0300\031 \149\030 \128\0300\149\149\151\145\030 \128\0314\153\010\030 \130\131\130\131\130\131\0314\130\031 \128", run = "Lua.lua", }, bc0792d8dc81e8aa30b987246a5ce97c40cd6833 = { @@ -76,9 +62,7 @@ icon = " \0307\031f| \ \0307\031f---o\030 \031 \ \0307\031f| ", - iconExt = "\0318\138\0308\031f\130\0318\128\031f\129\030f\0318\133\ -\0318\143\0308\128\0317\143\0318\128\030f\143\ -\0318\138\135\143\139\133", + iconExt = "\030 \0318\138\0308\031 \130\0318\128\031 \129\030 \0318\133\010\030 \0318\143\0308\128\0317\143\0318\128\030 \143\010\030 \0318\138\135\143\139\133", run = "System.lua", }, [ "2a4d562b1d9a9c90bdede6fac8ce4f7402462b86" ] = { @@ -87,23 +71,20 @@ icon = "\030f\031f \0315/\ \030f\031f \0315/\\/ \ \030f\0315/\031f ", - iconExt = "\031f\128\128\0305\159\030f\128\0305\159\030f\0315\134\031f\128\ -\031f\128\0315\152\129\137\0305\031f\158\139\030f\0317 \ -\0315\134\031f\128\128\128\128\0305\154\030f\0317 ", + iconExt = "\030 \031 \128\128\0305\159\030 \128\0305\159\030 \0315\134\031 \128\010\030 \031 \128\0315\152\129\137\0305\031 \158\139\030 \128\010\030 \0315\134\031 \128\128\128\128\0305\154\030 \128", run = "Tasks.lua", }, [ "a0365977708b7387ee9ce2c13e5820e6e11732cb" ] = { title = "Pain", category = "Apps", - icon = "\030 \031f\0307\031f\159\030 \159\030 \ -\030 \031f\0308\031f\135\0307\0318\144\140\030f\0317\159\143\031c\139\0302\135\030f\0312\157\ -\030 \031f\030f\0318\143\133\0312\136\0302\031f\159\159\143\131\030f\0312\132", + iconExt = "\0307\031 \159\030 \128\128\128\128\128\128\128\010\0308\031 \135\0307\0318\144\140\030 \0317\159\143\031c\139\0302\135\030 \0312\157\010\030 \0318\143\133\0312\136\0302\031 \159\159\143\131\030 \0312\132", run = "pain", }, [ "6a381ca189cbddd63737cbaf6e8b593844ce467ba52b1c5e5e05d8f29864385d" ] = { title = "Sniffer", category = "Apps", icon = "\31\102\128\128\128\128\31\53\149\30\53\31\102\154\30\102\31\53\137\10\30\52\31\102\159\31\52\128\128\30\102\144\31\53\130\30\53\31\102\155\140\10\31\52\151\30\52\31\102\148\30\102\31\52\151\30\52\31\102\148\30\102\128\128\128", + iconExt = "\030 \031 \128\128\128\128\0315\149\0305\031 \154\030 \0315\137\010\0304\031 \159\0314\128\128\030 \144\0315\130\0305\031 \155\140\010\0314\151\0304\031f\148\030f\0314\151\0304\031f\148\030 \031 \128\128\128", run = "Sniff.lua", }, [ "01c933b2a36ad8ed2d54089cb2903039046c1216" ] = { @@ -120,9 +101,7 @@ icon = "\0300\0317==\031 \0307 \ \0300\0317====\ \0300\0317====", - iconExt = "\030 \031f\0300\031f\136\140\132\0308\130\030f\0318\144\ -\030 \031f\030f\0310\157\0300\031f\147\030f\0310\142\143\149\ -\030 \031f\0300\031f\136\140\132\140\030f\0310\149", + iconExt = "\0300\031f\136\140\132\0308\031 \130\030 \0318\144\010\157\0300\031f\147\030f\0310\142\143\030 \149\010\0300\031f\136\140\132\140\030 \0310\149", run = "Files.lua", }, [ "7fddb7d8d1d60b1eeefa9af01082e0811d4b484d" ] = { @@ -131,23 +110,19 @@ icon = "\0304\031f \ \0304\031f \030f\0310zz\031 \ \0304\031f \030f ", - iconExt = "\030e\031f\135\030f\031e\148\030e\128\031f\151\139\ -\030e\031e\128\030f\031f\128\031e\143\031f\128\030e\031e\128\ -\031e\139\030e\031f\130\131\129\030f\031e\135", + iconExt = "\030e\031 \135\030 \031e\148\030e\128\031 \151\139\010\030e\031e\128\030 \031 \128\031e\143\031 \128\030e\031e\128\010\030 \031e\139\030e\031 \130\131\129\030 \031e\135", run = "/rom/programs/shutdown", }, - bdc1fd5d3c0f3dcfd55d010426e61bf9451e680d = { + [ "bdc1fd5d3c0f3dcfd55d010426e61bf9451e680d" ] = { title = "Shell", category = "Apps", icon = "\0304 \030 \ \0304 \030f\0314> \0310_\031 \ \0304 \030f \030 ", - iconExt = "\030f\0314\151\131\131\131\131\ -\030f\0314\149\030f\0314> \0310_ \ -\030f\0314\149\030f ", + iconExt = "\030f\0314\151\131\131\131\131\010\030f\0314\149\030f\0314> \0310_ \010\030f\0314\149\030f ", run = "shell", }, - b77aad5fb24921ef76ac8f3e500ed93fddae8f2a = { + [ "b77aad5fb24921ef76ac8f3e500ed93fddae8f2a" ] = { title = "Redirection", category = "Games", icon = "\0307 \0308 \0307 \ @@ -156,7 +131,7 @@ run = "rom/programs/fun/advanced/redirection", requires = 'advanced', }, - f39d173d91c22348565c20283b89d4d1cabd3b7e = { + [ "f39d173d91c22348565c20283b89d4d1cabd3b7e" ] = { title = "Falling", category = "Games", icon = "\030f \0302 \ @@ -165,7 +140,7 @@ run = "rom/programs/pocket/falling", requires = 'advancedPocket', }, - db56e2e1db9f7accfc37f2b132d27505c66ba521 = { + [ "db56e2e1db9f7accfc37f2b132d27505c66ba521" ] = { title = "Adventure", category = "Games", icon = "\030f\0310You \031 \ @@ -179,9 +154,7 @@ icon = "\030d \030 \030e \030 \ \030d \030 \ \030d ", - iconExt = "\030 \031f\0305\031f\151\030f\0315\135\131\0305\031f\146\ -\030 \031f\030f\0315\130\141\0305\031f\139\030f\0315\130\ -\030 \031f\0305\031f\146\143\030f\0315\158\031e\130", + iconExt = "\0305\031 \151\030 \0315\135\131\0305\031 \146\010\030 \0315\130\141\0305\031 \139\030 \0315\130\010\0305\031 \146\143\030 \0315\158\031e\130", run = "/rom/programs/fun/worm", }, [ "9f46ca3ef617166776ef6014a58d4e66859caa62" ] = { @@ -190,9 +163,7 @@ icon = " \030f \ \030f \0307 \ \030f \0307 \0300 ", - iconExt = "\031f\128\0307\143\131\131\131\131\143\030f\128\ -\0307\031f\129\0317\128\0319\136\0309\031b\136\132\0307\0319\132\0317\128\031f\130\ -\0317\130\143\0307\128\128\128\128\030f\143\129", + iconExt = "\030 \031 \128\0307\143\131\131\131\131\143\030 \128\010\0307\031 \129\0317\128\0319\136\0309\031b\136\132\0307\0319\132\0317\128\031 \130\010\030 \0317\130\143\0307\128\128\128\128\030 \143\129", run = "/rom/programs/fun/dj", }, } diff --git a/sys/etc/fstab b/sys/etc/fstab index deeac19..235ecf0 100644 --- a/sys/etc/fstab +++ b/sys/etc/fstab @@ -1,4 +1,5 @@ sys/apps/pain.lua urlfs https://github.com/LDDestroier/CC/raw/master/pain.lua sys/apps/update.lua urlfs http://pastebin.com/raw/UzGHLbNC sys/apps/Enchat.lua urlfs https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua -sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua \ No newline at end of file +sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua +sys/apps/ntftrans.lua urlfs https://pastebin.com/raw/e8XrzeDY \ No newline at end of file diff --git a/sys/modules/opus/nft.lua b/sys/modules/opus/nft.lua index 52d5c6c..4fd8d02 100644 --- a/sys/modules/opus/nft.lua +++ b/sys/modules/opus/nft.lua @@ -34,30 +34,23 @@ function NFT.parse(imageText) --As we're no longer 1-1, we keep track of what index to write to local writeIndex = 1 --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour - local bgNext, fgNext = false, false - --The current background and foreground colours - local currBG, currFG = nil,nil - for i = 1, #sLine do - local nextChar = string.sub(sLine, i, i) - if nextChar:byte() == 30 then - bgNext = true - elseif nextChar:byte() == 31 then - fgNext = true - elseif bgNext then - currBG = getColourOf(nextChar) - bgNext = false - elseif fgNext then - currFG = getColourOf(nextChar) - fgNext = false + + local tcol, bcol = colors.white,colors.black + local cx, sx = 1, 0 + while sx < #sLine do + sx = sx + 1 + if sLine:sub(sx,sx) == "\30" then + bcol = getColourOf(sLine:sub(sx+1,sx+1)) + sx = sx + 1 + elseif sLine:sub(sx,sx) == "\31" then + tcol = getColourOf(sLine:sub(sx+1,sx+1)) + sx = sx + 1 else - --if nextChar ~= " " and currFG == nil then - -- any color not in range is considered transparent - -- currFG = _G.colors.white - --end - image.bg[num][writeIndex] = currBG - image.fg[num][writeIndex] = currFG - image.text[num][writeIndex] = nextChar + image.bg[num][writeIndex] = bcol + image.fg[num][writeIndex] = tcol + image.text[num][writeIndex] = sLine:sub(sx,sx) writeIndex = writeIndex + 1 + cx = cx + 1 end end image.height = num From 43c86c263ba80f5647bd9a6caf797edfa0ae6764 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 11 Jul 2019 10:36:17 -0600 Subject: [PATCH 189/231] upper/lowercase transformations for TextEntry --- sys/apps/Help.lua | 1 + sys/modules/opus/ui/components/TextEntry.lua | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index abb6099..72b5308 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -21,6 +21,7 @@ local page = UI.Page { filter = UI.TextEntry { x = 10, y = 2, ex = -3, limit = 32, + transform = 'lowercase', }, grid = UI.ScrollingGrid { y = 4, diff --git a/sys/modules/opus/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua index 512f668..09631ef 100644 --- a/sys/modules/opus/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -5,6 +5,8 @@ local Util = require('opus.util') local colors = _G.colors local _rep = string.rep +local _lower = string.lower +local _upper = string.upper UI.TextEntry = class(UI.Window) UI.TextEntry.defaults = { @@ -104,12 +106,21 @@ function UI.TextEntry:focus() end end +function UI.TextEntry:_transform(text) + if self.transform == 'lowercase' then + return _lower(text) + elseif self.transform == 'uppercase' then + return _upper(text) + end + return text +end + function UI.TextEntry:eventHandler(event) local text = self.value self.entry.value = tostring(text) if event.ie and self.entry:process(event.ie) then if self.entry.textChanged then - self.value = self.entry.value + self.value = self:_transform(self.entry.value) self:draw() if text ~= self.value then self:emit({ type = 'text_change', text = self.value, element = self }) From 51e40a1dd73ed14c8188fbc1554f3d506853ce22 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 12 Jul 2019 02:59:36 -0600 Subject: [PATCH 190/231] Anavrins Slider component --- sys/modules/opus/ui/components/Slider.lua | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 sys/modules/opus/ui/components/Slider.lua diff --git a/sys/modules/opus/ui/components/Slider.lua b/sys/modules/opus/ui/components/Slider.lua new file mode 100644 index 0000000..5966160 --- /dev/null +++ b/sys/modules/opus/ui/components/Slider.lua @@ -0,0 +1,48 @@ +local class = require('opus.class') +local UI = require('opus.ui') +local Util = require('opus.util') + +local colors = _G.colors + +UI.Slider = class(UI.Window) +UI.Slider.defaults = { + UIElement = 'Slider', + height = 1, + barChar = UI.extChars and '\140' or '-', + barColor = colors.gray, + sliderChar = UI.extChars and '\143' or '\124', + sliderColor = colors.blue, + leftBorder = '\141', + rightBorder = '\142', + value = 0, + min = 0, + max = 100, + event = 'slider_update', +} +function UI.Slider:draw() + local range = self.max - self.min + local perc = (self.value - self.min) / range + local progress = Util.clamp(1 + self.width * perc, 1, self.width) + + local bar = { } + for i = 1, self.width do + local filler = + i == 1 and self.leftBorder or + i == self.width and self.rightBorder or + self.barChar + + table.insert(bar, filler) + end + self:write(1, 1, table.concat(bar), nil, self.barColor) + self:write(progress, 1, self.sliderChar, nil, self.sliderColor) +end + +function UI.Slider:eventHandler(event) + if event.type == "mouse_down" or event.type == "mouse_drag" then + local range = self.max - self.min + local i = (event.x - 1) / (self.width - 1) + self.value = self.min + (i * range) + self:emit({ type = self.event, value = self.value, element = self }) + self:draw() + end +end From c43fe19f1d82eee4b39cb64ef7ce3522da0041f4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 12 Jul 2019 12:47:51 -0600 Subject: [PATCH 191/231] sliders in forms + form component setValue (hopefully didnt break anything) --- sys/modules/opus/ui/components/Form.lua | 9 ++--- sys/modules/opus/ui/components/Slider.lua | 35 ++++++++++++++++++-- sys/modules/opus/ui/components/TextEntry.lua | 4 +-- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/sys/modules/opus/ui/components/Form.lua b/sys/modules/opus/ui/components/Form.lua index f1eb6f3..68b59d3 100644 --- a/sys/modules/opus/ui/components/Form.lua +++ b/sys/modules/opus/ui/components/Form.lua @@ -29,10 +29,11 @@ function UI.Form:setValues(values) self.values = values for _,child in pairs(self.children) do if child.formKey then - -- this should be child:setValue(self.values[child.formKey]) - -- so chooser can set default choice if null - -- null should be valid as well - child.value = self.values[child.formKey] or '' + if child.setValue then + child:setValue(self.values[child.formKey]) + else + child.value = self.values[child.formKey] or '' + end end end end diff --git a/sys/modules/opus/ui/components/Slider.lua b/sys/modules/opus/ui/components/Slider.lua index 5966160..9dee765 100644 --- a/sys/modules/opus/ui/components/Slider.lua +++ b/sys/modules/opus/ui/components/Slider.lua @@ -12,13 +12,31 @@ UI.Slider.defaults = { barColor = colors.gray, sliderChar = UI.extChars and '\143' or '\124', sliderColor = colors.blue, - leftBorder = '\141', - rightBorder = '\142', + sliderFocusColor = colors.lightBlue, + leftBorder = UI.extChars and '\141' or '\124', + rightBorder = UI.extChars and '\142' or '\124', value = 0, min = 0, max = 100, event = 'slider_update', + accelerators = { + right = 'slide_right', + left = 'slide_left', + } } +function UI.Slider:setValue(value) + self.value = tonumber(value) or self.min +end + +function UI.Slider:reset() -- form support + self.value = self.min + self:draw() +end + +function UI.Slider:focus() + self:draw() +end + function UI.Slider:draw() local range = self.max - self.min local perc = (self.value - self.min) / range @@ -34,7 +52,7 @@ function UI.Slider:draw() table.insert(bar, filler) end self:write(1, 1, table.concat(bar), nil, self.barColor) - self:write(progress, 1, self.sliderChar, nil, self.sliderColor) + self:write(progress, 1, self.sliderChar, nil, self.focused and self.sliderFocusColor or self.sliderColor) end function UI.Slider:eventHandler(event) @@ -44,5 +62,16 @@ function UI.Slider:eventHandler(event) self.value = self.min + (i * range) self:emit({ type = self.event, value = self.value, element = self }) self:draw() + + elseif event.type == 'slide_left' or event.type == 'slide_right' then + local range = self.max - self.min + local step = range / self.width + if event.type == 'slide_left' then + self.value = Util.clamp(self.value - step, self.min, self.max) + else + self.value = Util.clamp(self.value + step, self.min, self.max) + end + self:emit({ type = self.event, value = self.value, element = self }) + self:draw() end end diff --git a/sys/modules/opus/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua index 09631ef..151dd2b 100644 --- a/sys/modules/opus/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -25,7 +25,7 @@ UI.TextEntry.defaults = { } } function UI.TextEntry:postInit() - self.value = tostring(self.value) + self.value = tostring(self.value) -- is this right ? shouldnt raw numbers be allowed self.entry = entry({ limit = self.limit, offset = 2 }) end @@ -35,7 +35,7 @@ function UI.TextEntry:layout() end function UI.TextEntry:setValue(value) - self.value = value + self.value = value or '' self.entry:unmark() self.entry.value = tostring(value) self.entry:updateScroll() From 87c7e5ff7e4de9e4202323a4acbcea38b43302f9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 15 Jul 2019 20:08:30 -0600 Subject: [PATCH 192/231] ui theme generator + better module handling --- sys/apps/system/requires.lua | 3 +- sys/init/1.device.lua | 78 +-------------------- sys/init/3.modules.lua | 93 ++++++++++++++++++++----- sys/init/3.relay.lua | 2 +- sys/modules/opus/ui.lua | 29 ++++++++ sys/modules/opus/ui/components/Menu.lua | 1 + 6 files changed, 110 insertions(+), 96 deletions(-) diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua index 38acef9..1e41216 100644 --- a/sys/apps/system/requires.lua +++ b/sys/apps/system/requires.lua @@ -100,4 +100,5 @@ function tab:eventHandler(event) end end -return tab +--this needs rework - see 4.user.lua +--return tab diff --git a/sys/init/1.device.lua b/sys/init/1.device.lua index c4946d3..b61a767 100644 --- a/sys/init/1.device.lua +++ b/sys/init/1.device.lua @@ -34,25 +34,12 @@ local keys = _G.keys local mouse = _G.device.mouse local os = _G.os -local drivers = { } - kernel.hook('peripheral', function(_, eventData) local side = eventData[1] if side then local dev = Peripheral.addDevice(device, side) if dev then - if drivers[dev.type] then - local e = drivers[dev.type](dev) - if type(e) == 'table' then - for _, v in pairs(e) do - os.queueEvent('device_attach', v.name) - end - elseif e then - os.queueEvent('device_attach', e.name) - end - end - - os.queueEvent('device_attach', dev.name, dev) + os.queueEvent('device_attach', dev.name) end end end) @@ -61,12 +48,7 @@ kernel.hook('peripheral_detach', function(_, eventData) local side = eventData[1] if side then for _, dev in pairs(Util.findAll(device, 'side', side)) do - os.queueEvent('device_detach', dev.name, dev) - if dev._children then - for _,v in pairs(dev._children) do - os.queueEvent('peripheral_detach', v.name) - end - end + os.queueEvent('device_detach', dev.name) device[dev.name] = nil end end @@ -124,59 +106,3 @@ end function keyboard.removeHotkey(code) keyboard.hotkeys[code] = nil end - -local function createDevice(name, devType, method, manipulator) - local dev = { - name = name, - side = name, - type = devType, - } - local methods = { - 'drop', 'getDocs', 'getItem', 'getItemMeta', 'getTransferLocations', - 'list', 'pullItems', 'pushItems', 'size', 'suck', - } - if manipulator[method] then - for _,k in pairs(methods) do - dev[k] = function(...) - return manipulator[method]()[k](...) - end - end - if not manipulator._children then - manipulator._children = { dev } - else - table.insert(manipulator._children, dev) - end - device[name] = dev - end -end - -drivers['manipulator'] = function(dev) - if dev.getName then - pcall(function() - local name = dev.getName() - if name then - if dev.getInventory then - createDevice(name .. ':inventory', 'inventory', 'getInventory', dev) - end - if dev.getEquipment then - createDevice(name .. ':equipment', 'equipment', 'getEquipment', dev) - end - if dev.getEnder then - createDevice(name .. ':enderChest', 'enderChest', 'getEnder', dev) - end - - return dev._children - end - end) - end -end - --- initialize drivers -for _,v in pairs(device) do - if drivers[v.type] then - local s, m = pcall(drivers[v.type], v) - if not s and m then - _G.printError(m) - end - end -end diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index 8dd5fcb..174f2be 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -3,17 +3,17 @@ local Util = require('opus.util') local device = _G.device local kernel = _G.kernel local os = _G.os -local peripheral = _G.peripheral local containers = { manipulator = true, neuralInterface = true, } +local cache = { } + local function getModules(dev, side) local list = { } - - if dev then + if dev and dev.listModules then for _, module in pairs(dev.listModules()) do list[module] = Util.shallowCopy(dev) list[module].name = module @@ -24,29 +24,86 @@ local function getModules(dev, side) return list end -for _,v in pairs(device) do - if containers[v.type] then - local list = getModules(v, v.side) - for k, dev in pairs(list) do - -- neural and attached modules have precedence over manipulator modules - if not device[k] or v.type ~= 'manipulator' then - device[k] = dev - end +-- if a device has been reattached, reuse the existing +-- table so any references to the table are retained +local function addDevice(dev, args, doQueue) + local name = args.name + + if not cache[name] then + cache[name] = { } + end + device[name] = cache[name] + Util.merge(device[name], dev) + Util.merge(device[name], args) + + if doQueue then + os.queueEvent('device_attach', name) + end +end + +local function addContainer(v, doQueue) + -- add devices like plethora:scanner + for name, dev in pairs(getModules(v, v.side)) do + -- neural and attached modules have precedence over manipulator modules + if not device[name] or v.type ~= 'manipulator' then + addDevice(dev, { name = dev.name, type = dev.name, side = dev.side }, doQueue) end end + + if v.getName then + pcall(function() + local name = v.getName() + if name then + if v.getInventory then + addDevice(v.getInventory(), { + name = name .. ':inventory', + type = 'inventory', + side = v.side + }, doQueue) + end + if v.getEquipment then + addDevice(v.getEquipment(), { + name = name .. ':equipment', + type = 'equipment', + side = v.side + }, doQueue) + end + if v.getEnder then + addDevice(v.getEnder(), { + name = name .. ':enderChest', + type = 'enderChest', + side = v.side + }, doQueue) + end + end + end) + end +end + +for k,v in pairs(device) do + if containers[v.type] then + cache[k] = v + addContainer(v) + end end -- register modules as peripherals kernel.hook('device_attach', function(_, eventData) - local dev = eventData[2] + local name = eventData[1] + local dev = device[name] if dev and containers[dev.type] then - local list = getModules(peripheral.wrap(dev.side), dev.side) - for k,v in pairs(list) do - if not device[k] or dev.type ~= 'manipulator' then - device[k] = v - os.queueEvent('device_attach', k, v) - end + -- so... basically, if you get a handle to device.neuralInterface + -- (or manipulator) - that handle will still be valid after + -- a module is removed + if cache[name] then + device[name] = cache[name] + -- TODO: cannot simply merge - need to remove + -- all functions then merge + Util.merge(device[name], dev) + else + cache[name] = dev end + addContainer(dev, true) end end) diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua index 5ddc4bc..a2132e7 100644 --- a/sys/init/3.relay.lua +++ b/sys/init/3.relay.lua @@ -23,5 +23,5 @@ end -- register oc devices as peripherals kernel.hook('device_attach', function(_, eventData) - register(device[eventData[2]]) + register(device[eventData[1]]) end) diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 0acfb16..b291e82 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -12,6 +12,7 @@ local fs = _G.fs local os = _G.os local peripheral = _G.peripheral local term = _G.term +local textutils = _G.textutils --[[ Using the shorthand window definition, elements are created from @@ -217,6 +218,34 @@ function Manager:loadTheme(filename) end end +function Manager:generateTheme(filename) + local t = { } + for k,v in pairs(self) do + if type(v) == 'table' then + if v._preload then + v._preload() + v = self[k] + end + if v.defaults and v.defaults.UIElement ~= 'Device' then + for p,d in pairs(v.defaults) do + if p:find('olor') then + if not t[k] then + t[k] = { } + end + for c, n in pairs(colors) do + if n == d then + t[k][p] = 'colors.' .. c + break + end + end + end + end + end + end + end + Util.writeFile(filename, textutils.serialize(t):gsub('(")', '')) +end + function Manager:emitEvent(event) local currentPage = self:getActivePage() if currentPage and currentPage.focused then diff --git a/sys/modules/opus/ui/components/Menu.lua b/sys/modules/opus/ui/components/Menu.lua index f581874..e31e8df 100644 --- a/sys/modules/opus/ui/components/Menu.lua +++ b/sys/modules/opus/ui/components/Menu.lua @@ -7,6 +7,7 @@ UI.Menu.defaults = { UIElement = 'Menu', disableHeader = true, columns = { { heading = 'Prompt', key = 'prompt', width = 20 } }, + menuItems = { }, } function UI.Menu:postInit() self.values = self.menuItems From c8f200ebb6cc140d46b31721c6e872bf7c4a0fa9 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Tue, 16 Jul 2019 22:29:47 -0400 Subject: [PATCH 193/231] Fix apps.db and legacy icon transparency --- sys/apps/Network.lua | 4 +-- sys/etc/apps.db | 77 +++++++++++++------------------------------- sys/etc/fstab | 2 +- 3 files changed, 24 insertions(+), 59 deletions(-) diff --git a/sys/apps/Network.lua b/sys/apps/Network.lua index bc551a4..6ae002a 100644 --- a/sys/apps/Network.lua +++ b/sys/apps/Network.lua @@ -188,9 +188,7 @@ function page:eventHandler(event) os.queueEvent('overview_shortcut', { title = t.label, category = "VNC", - icon = "\ - \031e\\\031 \031e/\031dn\ - \031e\\/\031 \0319c", + icon = "\010\030 \009\009\031e\\\031 \031e/\031dn\010\030 \009\009 \031e\\/\031 \031bc", run = "vnc.lua " .. t.id, }) diff --git a/sys/etc/apps.db b/sys/etc/apps.db index 7bf79ab..e753fd1 100644 --- a/sys/etc/apps.db +++ b/sys/etc/apps.db @@ -14,63 +14,49 @@ [ "53ebc572b4a44802ba114729f07bdaaf5409a9d7" ] = { title = "Network", category = "Apps", - icon = "\0304 \030 \ -\030f \0304 \0307 \030 \031 \031f)\ -\030f \0304 \0307 \030 \031f)", + icon = "\0304 \030 \010\030f \0304 \0307 \030 \031 \031f)\010\030f \0304 \0307 \030 \031f)", iconExt = "\030 \031 \128\128\128\128\0305\140\030 \0315\137\144\010\0314\131\131\0304\031f\148\030 \031 \128\0305\155\150\149\010\147\0300\031f\141\0304\149\0307\0318\149\030 \031 \128\128\128", run = "Network.lua", }, - c7116629a6a855cb774d9c7c8ad822fd83c71fb5 = { + [ "c7116629a6a855cb774d9c7c8ad822fd83c71fb5" ] = { title = "Reboot", category = "System", - icon = "\0304\031f \030f\0310o..\0304\031f \ -\0304\031f \030f\0310.o.\0304\031f \ -\0304\031f - ", + icon = "\0304\031f \030f\0310o..\0304\031f \010\0304\031f \030f\0310.o.\0304\031f \010\0304\031f - ", iconExt = "\0307\031 \135\0300\0317\159\0307\0310\144\031 \139\010\0300\0317\131\0307\0310\147\0300\0317\156\131\010\030 \130\143\143\129", run = "rom/programs/reboot", }, - fb91e24fa52d8d2b32937bf04d843f730319a902 = { + [ "fb91e24fa52d8d2b32937bf04d843f730319a902" ] = { title = "Update", category = "System", - icon = "\0301\03171\03180\030 \031 \ -\0301\03181\030 \031 \ -\0301\03170\03180\03171\0307\031f>", + icon = "\0301\03171\03180\030 \031 \010\0301\03181\030 \031 \010\0301\03170\03180\03171\0307\031f>", iconExt = "\030 \031 \128\0313\152\131\131\132\031 \128\010\030 \0313\139\159\129\0303\031 \159\129\139\010\030 \031 \128\0313\136\0303\031 \143\143\030 \0313\134\031 \128", run = "update update", }, - c47ae15370cfe1ed2781eedc1dc2547d12d9e972 = { + [ "c47ae15370cfe1ed2781eedc1dc2547d12d9e972" ] = { title = "Help", category = "Apps", - icon = " \031f?\031 \ -\031f?\031 \ - \031f?", + icon = "\030 \0310 ? \010\030 \0310? \010\030 \0310\009 ?", iconExt = "\0300\031 \129\030 \0310\131\0300\031 \148\030 \0310\148\010\030 \031 \128\0300\131\030 \0310\142\129\010\030 \031 \128\0300\131\030 \128\128", run = "Help.lua", }, - b0832074630eb731d7fbe8074de48a90cd9bb220 = { + [ "b0832074630eb731d7fbe8074de48a90cd9bb220" ] = { title = "Lua", category = "Apps", - icon = "\030f \ -\030f\0310lua>\031 \ -\030f ", + icon = "\030 \010\030 \0310lua>\031 \010\030 ", iconExt = "\0300\031 \151\030 \128\0300\159\159\159\030 \0310\144\0304\031 \159\030 \128\010\0300\031 \149\030 \128\0300\149\149\151\145\030 \128\0314\153\010\030 \130\131\130\131\130\131\0314\130\031 \128", run = "Lua.lua", }, - bc0792d8dc81e8aa30b987246a5ce97c40cd6833 = { + [ "bc0792d8dc81e8aa30b987246a5ce97c40cd6833" ] = { title = "System", category = "System", - icon = " \0307\031f| \ -\0307\031f---o\030 \031 \ - \0307\031f| ", + icon = "\030 \0307\031f| \010\0307\031f---o\030 \031 \010\030 \009 \0307\031f| ", iconExt = "\030 \0318\138\0308\031 \130\0318\128\031 \129\030 \0318\133\010\030 \0318\143\0308\128\0317\143\0318\128\030 \143\010\030 \0318\138\135\143\139\133", run = "System.lua", }, [ "2a4d562b1d9a9c90bdede6fac8ce4f7402462b86" ] = { title = "Tasks", category = "System", - icon = "\030f\031f \0315/\ -\030f\031f \0315/\\/ \ -\030f\0315/\031f ", + icon = "\030 \031f \0315/\010\030 \031f \0315/\\/ \010\030 \0315/\031f ", iconExt = "\030 \031 \128\128\0305\159\030 \128\0305\159\030 \0315\134\031 \128\010\030 \031 \128\0315\152\129\137\0305\031 \158\139\030 \128\010\030 \0315\134\031 \128\128\128\128\0305\154\030 \128", run = "Tasks.lua", }, @@ -83,86 +69,67 @@ [ "6a381ca189cbddd63737cbaf6e8b593844ce467ba52b1c5e5e05d8f29864385d" ] = { title = "Sniffer", category = "Apps", - icon = "\31\102\128\128\128\128\31\53\149\30\53\31\102\154\30\102\31\53\137\10\30\52\31\102\159\31\52\128\128\30\102\144\31\53\130\30\53\31\102\155\140\10\31\52\151\30\52\31\102\148\30\102\31\52\151\30\52\31\102\148\30\102\128\128\128", - iconExt = "\030 \031 \128\128\128\128\0315\149\0305\031 \154\030 \0315\137\010\0304\031 \159\0314\128\128\030 \144\0315\130\0305\031 \155\140\010\0314\151\0304\031f\148\030f\0314\151\0304\031f\148\030 \031 \128\128\128", + iconExt = "\030 \031 \128\128\128\128\0315\149\0305\031 \154\030 \0315\137\010\0304\031 \159\0314\128\128\030 \144\0315\130\0305\031 \155\140\010\0314\151\0304\031f\148\030f\0314\151\0304\031f\148\030 \031 \128\128\128", run = "Sniff.lua", }, [ "01c933b2a36ad8ed2d54089cb2903039046c1216" ] = { title = "Enchat", - icon = "\030e\031f\151\030f\031e\156\0311\140\0314\140\0315\140\031d\140\031b\140\031a\132\ -\030f\0314\128\030e\031f\132\030f\031e\132\0318nchat\ -\030f\031e\138\141\0311\140\0314\140\0315\132\0317v\03183\031a\132", + iconExt = "\030e\031f\151\030f\031e\156\0311\140\0314\140\0315\140\031d\140\031b\140\031a\132\010\030f\0314\128\030e\031f\132\030f\031e\132\0318nchat\010\030f\031e\138\141\0311\140\0314\140\0315\132\0317v\03183\031a\132", category = "Apps", run = "Enchat", }, [ "6ce6c512ea433a7fc5c8841628e7696cd0ff7f2b" ] = { title = "Files", category = "Apps", - icon = "\0300\0317==\031 \0307 \ -\0300\0317====\ -\0300\0317====", + icon = "\0300\0317==\031 \0307 \010\0300\0317====\010\0300\0317====", iconExt = "\0300\031f\136\140\132\0308\031 \130\030 \0318\144\010\157\0300\031f\147\030f\0310\142\143\030 \149\010\0300\031f\136\140\132\140\030 \0310\149", run = "Files.lua", }, [ "7fddb7d8d1d60b1eeefa9af01082e0811d4b484d" ] = { title = "Shutdown", category = "System", - icon = "\0304\031f \ -\0304\031f \030f\0310zz\031 \ -\0304\031f \030f ", + icon = "\0304\031f \010\0304\031f \030f\0310zz\031 \010\0304\031f \030f ", iconExt = "\030e\031 \135\030 \031e\148\030e\128\031 \151\139\010\030e\031e\128\030 \031 \128\031e\143\031 \128\030e\031e\128\010\030 \031e\139\030e\031 \130\131\129\030 \031e\135", run = "/rom/programs/shutdown", }, [ "bdc1fd5d3c0f3dcfd55d010426e61bf9451e680d" ] = { title = "Shell", category = "Apps", - icon = "\0304 \030 \ -\0304 \030f\0314> \0310_\031 \ -\0304 \030f \030 ", + icon = "\0304 \030 \010\0304 \030f\0314> \0310_\031 \010\0304 \030f \030 ", iconExt = "\030f\0314\151\131\131\131\131\010\030f\0314\149\030f\0314> \0310_ \010\030f\0314\149\030f ", run = "shell", }, [ "b77aad5fb24921ef76ac8f3e500ed93fddae8f2a" ] = { title = "Redirection", category = "Games", - icon = "\0307 \0308 \0307 \ -\0308\031b> \030b\0310>\0308\0318 \ -\0307 ", + icon = "\0307 \0308 \0307 \010\0308\031b> \030b\0310>\0308\0318 \010\0307 ", run = "rom/programs/fun/advanced/redirection", requires = 'advanced', }, [ "f39d173d91c22348565c20283b89d4d1cabd3b7e" ] = { title = "Falling", category = "Games", - icon = "\030f \0302 \ -\0309 \0302 \0301 \ -\030e \0309 \0301 ", + icon = "\030f \0302 \010\0309 \0302 \0301 \010\030e \0309 \0301 ", run = "rom/programs/pocket/falling", requires = 'advancedPocket', }, [ "db56e2e1db9f7accfc37f2b132d27505c66ba521" ] = { title = "Adventure", category = "Games", - icon = "\030f\0310You \031 \ -\030f\0310Ther\030 \031 \ -\030f\0314?\031f \031 \030 ", + icon = "\030f\0310You \031 \010\030f\0310Ther\030 \031 \010\030f\0314?\031f \031 \030 ", run = "rom/programs/fun/adventure", }, [ "76b849f460640bc789c433894382fb5acbac42a2" ] = { title = "Worm", category = "Games", - icon = "\030d \030 \030e \030 \ -\030d \030 \ -\030d ", + icon = "\030d \030 \030e \030 \010\030d \030 \010\030d ", iconExt = "\0305\031 \151\030 \0315\135\131\0305\031 \146\010\030 \0315\130\141\0305\031 \139\030 \0315\130\010\0305\031 \146\143\030 \0315\158\031e\130", run = "/rom/programs/fun/worm", }, [ "9f46ca3ef617166776ef6014a58d4e66859caa62" ] = { title = "DJ", category = "Games", - icon = " \030f \ -\030f \0307 \ -\030f \0307 \0300 ", + icon = " \030f \010\030f \0307 \010\030f \0307 \0300 ", iconExt = "\030 \031 \128\0307\143\131\131\131\131\143\030 \128\010\0307\031 \129\0317\128\0319\136\0309\031b\136\132\0307\0319\132\0317\128\031 \130\010\030 \0317\130\143\0307\128\128\128\128\030 \143\129", run = "/rom/programs/fun/dj", }, diff --git a/sys/etc/fstab b/sys/etc/fstab index 235ecf0..6514f50 100644 --- a/sys/etc/fstab +++ b/sys/etc/fstab @@ -2,4 +2,4 @@ sys/apps/pain.lua urlfs https://github.com/LDDestroier/CC/raw/master/pain.lua sys/apps/update.lua urlfs http://pastebin.com/raw/UzGHLbNC sys/apps/Enchat.lua urlfs https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua -sys/apps/ntftrans.lua urlfs https://pastebin.com/raw/e8XrzeDY \ No newline at end of file +sys/apps/nfttrans.lua urlfs https://pastebin.com/raw/e8XrzeDY From 672cca30841d6fdd40f75d9025aa9810ff900e14 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Tue, 16 Jul 2019 23:21:33 -0400 Subject: [PATCH 194/231] ui theme generator + better module handling --- sys/apps/system/requires.lua | 3 +- sys/init/1.device.lua | 78 +-------------------- sys/init/3.modules.lua | 93 ++++++++++++++++++++----- sys/init/3.relay.lua | 2 +- sys/modules/opus/ui.lua | 29 ++++++++ sys/modules/opus/ui/components/Menu.lua | 1 + 6 files changed, 110 insertions(+), 96 deletions(-) diff --git a/sys/apps/system/requires.lua b/sys/apps/system/requires.lua index 38acef9..1e41216 100644 --- a/sys/apps/system/requires.lua +++ b/sys/apps/system/requires.lua @@ -100,4 +100,5 @@ function tab:eventHandler(event) end end -return tab +--this needs rework - see 4.user.lua +--return tab diff --git a/sys/init/1.device.lua b/sys/init/1.device.lua index c4946d3..b61a767 100644 --- a/sys/init/1.device.lua +++ b/sys/init/1.device.lua @@ -34,25 +34,12 @@ local keys = _G.keys local mouse = _G.device.mouse local os = _G.os -local drivers = { } - kernel.hook('peripheral', function(_, eventData) local side = eventData[1] if side then local dev = Peripheral.addDevice(device, side) if dev then - if drivers[dev.type] then - local e = drivers[dev.type](dev) - if type(e) == 'table' then - for _, v in pairs(e) do - os.queueEvent('device_attach', v.name) - end - elseif e then - os.queueEvent('device_attach', e.name) - end - end - - os.queueEvent('device_attach', dev.name, dev) + os.queueEvent('device_attach', dev.name) end end end) @@ -61,12 +48,7 @@ kernel.hook('peripheral_detach', function(_, eventData) local side = eventData[1] if side then for _, dev in pairs(Util.findAll(device, 'side', side)) do - os.queueEvent('device_detach', dev.name, dev) - if dev._children then - for _,v in pairs(dev._children) do - os.queueEvent('peripheral_detach', v.name) - end - end + os.queueEvent('device_detach', dev.name) device[dev.name] = nil end end @@ -124,59 +106,3 @@ end function keyboard.removeHotkey(code) keyboard.hotkeys[code] = nil end - -local function createDevice(name, devType, method, manipulator) - local dev = { - name = name, - side = name, - type = devType, - } - local methods = { - 'drop', 'getDocs', 'getItem', 'getItemMeta', 'getTransferLocations', - 'list', 'pullItems', 'pushItems', 'size', 'suck', - } - if manipulator[method] then - for _,k in pairs(methods) do - dev[k] = function(...) - return manipulator[method]()[k](...) - end - end - if not manipulator._children then - manipulator._children = { dev } - else - table.insert(manipulator._children, dev) - end - device[name] = dev - end -end - -drivers['manipulator'] = function(dev) - if dev.getName then - pcall(function() - local name = dev.getName() - if name then - if dev.getInventory then - createDevice(name .. ':inventory', 'inventory', 'getInventory', dev) - end - if dev.getEquipment then - createDevice(name .. ':equipment', 'equipment', 'getEquipment', dev) - end - if dev.getEnder then - createDevice(name .. ':enderChest', 'enderChest', 'getEnder', dev) - end - - return dev._children - end - end) - end -end - --- initialize drivers -for _,v in pairs(device) do - if drivers[v.type] then - local s, m = pcall(drivers[v.type], v) - if not s and m then - _G.printError(m) - end - end -end diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index 8dd5fcb..174f2be 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -3,17 +3,17 @@ local Util = require('opus.util') local device = _G.device local kernel = _G.kernel local os = _G.os -local peripheral = _G.peripheral local containers = { manipulator = true, neuralInterface = true, } +local cache = { } + local function getModules(dev, side) local list = { } - - if dev then + if dev and dev.listModules then for _, module in pairs(dev.listModules()) do list[module] = Util.shallowCopy(dev) list[module].name = module @@ -24,29 +24,86 @@ local function getModules(dev, side) return list end -for _,v in pairs(device) do - if containers[v.type] then - local list = getModules(v, v.side) - for k, dev in pairs(list) do - -- neural and attached modules have precedence over manipulator modules - if not device[k] or v.type ~= 'manipulator' then - device[k] = dev - end +-- if a device has been reattached, reuse the existing +-- table so any references to the table are retained +local function addDevice(dev, args, doQueue) + local name = args.name + + if not cache[name] then + cache[name] = { } + end + device[name] = cache[name] + Util.merge(device[name], dev) + Util.merge(device[name], args) + + if doQueue then + os.queueEvent('device_attach', name) + end +end + +local function addContainer(v, doQueue) + -- add devices like plethora:scanner + for name, dev in pairs(getModules(v, v.side)) do + -- neural and attached modules have precedence over manipulator modules + if not device[name] or v.type ~= 'manipulator' then + addDevice(dev, { name = dev.name, type = dev.name, side = dev.side }, doQueue) end end + + if v.getName then + pcall(function() + local name = v.getName() + if name then + if v.getInventory then + addDevice(v.getInventory(), { + name = name .. ':inventory', + type = 'inventory', + side = v.side + }, doQueue) + end + if v.getEquipment then + addDevice(v.getEquipment(), { + name = name .. ':equipment', + type = 'equipment', + side = v.side + }, doQueue) + end + if v.getEnder then + addDevice(v.getEnder(), { + name = name .. ':enderChest', + type = 'enderChest', + side = v.side + }, doQueue) + end + end + end) + end +end + +for k,v in pairs(device) do + if containers[v.type] then + cache[k] = v + addContainer(v) + end end -- register modules as peripherals kernel.hook('device_attach', function(_, eventData) - local dev = eventData[2] + local name = eventData[1] + local dev = device[name] if dev and containers[dev.type] then - local list = getModules(peripheral.wrap(dev.side), dev.side) - for k,v in pairs(list) do - if not device[k] or dev.type ~= 'manipulator' then - device[k] = v - os.queueEvent('device_attach', k, v) - end + -- so... basically, if you get a handle to device.neuralInterface + -- (or manipulator) - that handle will still be valid after + -- a module is removed + if cache[name] then + device[name] = cache[name] + -- TODO: cannot simply merge - need to remove + -- all functions then merge + Util.merge(device[name], dev) + else + cache[name] = dev end + addContainer(dev, true) end end) diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua index 5ddc4bc..a2132e7 100644 --- a/sys/init/3.relay.lua +++ b/sys/init/3.relay.lua @@ -23,5 +23,5 @@ end -- register oc devices as peripherals kernel.hook('device_attach', function(_, eventData) - register(device[eventData[2]]) + register(device[eventData[1]]) end) diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 0acfb16..b291e82 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -12,6 +12,7 @@ local fs = _G.fs local os = _G.os local peripheral = _G.peripheral local term = _G.term +local textutils = _G.textutils --[[ Using the shorthand window definition, elements are created from @@ -217,6 +218,34 @@ function Manager:loadTheme(filename) end end +function Manager:generateTheme(filename) + local t = { } + for k,v in pairs(self) do + if type(v) == 'table' then + if v._preload then + v._preload() + v = self[k] + end + if v.defaults and v.defaults.UIElement ~= 'Device' then + for p,d in pairs(v.defaults) do + if p:find('olor') then + if not t[k] then + t[k] = { } + end + for c, n in pairs(colors) do + if n == d then + t[k][p] = 'colors.' .. c + break + end + end + end + end + end + end + end + Util.writeFile(filename, textutils.serialize(t):gsub('(")', '')) +end + function Manager:emitEvent(event) local currentPage = self:getActivePage() if currentPage and currentPage.focused then diff --git a/sys/modules/opus/ui/components/Menu.lua b/sys/modules/opus/ui/components/Menu.lua index f581874..e31e8df 100644 --- a/sys/modules/opus/ui/components/Menu.lua +++ b/sys/modules/opus/ui/components/Menu.lua @@ -7,6 +7,7 @@ UI.Menu.defaults = { UIElement = 'Menu', disableHeader = true, columns = { { heading = 'Prompt', key = 'prompt', width = 20 } }, + menuItems = { }, } function UI.Menu:postInit() self.values = self.menuItems From 4093d4cd0d8ac4ff0f63f13a1b822a016f1113b9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 17 Jul 2019 15:29:26 -0600 Subject: [PATCH 195/231] fix issue with manipulator not working after relog --- sys/init/3.modules.lua | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index 174f2be..c80bcc7 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -39,6 +39,21 @@ local function addDevice(dev, args, doQueue) if doQueue then os.queueEvent('device_attach', name) end + return device[name] +end + +local function damnManipulator(container, method, args, doQueue) + local dev = addDevice(container[method](), args) + for k,v in pairs(dev) do + if type(v) == 'function' then + dev[k] = function(...) + return device[container.name][method]()[k](...) + end + end + end + if doQueue then + os.queueEvent('device_attach', args.name) + end end local function addContainer(v, doQueue) @@ -55,21 +70,21 @@ local function addContainer(v, doQueue) local name = v.getName() if name then if v.getInventory then - addDevice(v.getInventory(), { + damnManipulator(v, 'getInventory', { name = name .. ':inventory', type = 'inventory', side = v.side }, doQueue) end if v.getEquipment then - addDevice(v.getEquipment(), { + damnManipulator(v, 'getEquipment', { name = name .. ':equipment', type = 'equipment', side = v.side }, doQueue) end if v.getEnder then - addDevice(v.getEnder(), { + damnManipulator(v, 'getEnder', { name = name .. ':enderChest', type = 'enderChest', side = v.side From d8dd17333c1cfe491fb23bd0d79785ac86c54af1 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Thu, 18 Jul 2019 01:00:22 -0400 Subject: [PATCH 196/231] Disk Usage icon transparency --- sys/apps/system/diskusage.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index 8fbdd71..fb958f5 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -8,10 +8,10 @@ local os = _G.os local peripheral = _G.peripheral local NftImages = { - blank = '\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153\10\30\55\31\56\153\153\153\153\153\153\153\153\10\30\56\31\55\153\153\153\153\153\153\153\153', - drive = '\30\32\31\32\32\30\98\31\98\128\30\56\31\56\128\128\30\102\149\30\98\149\31\57\139\10\30\32\31\32\32\30\98\31\98\128\128\128\128\128\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128\10\30\32\31\32\32\30\98\31\98\128\30\48\31\55\95\95\95\95\30\98\31\98\128', - rom = '\30\57\31\57\128\31\56\144\144\144\144\144\31\57\128\10\30\56\31\57\157\30\55\31\55\128\128\128\128\128\30\57\31\56\145\10\30\57\31\56\136\30\55\31\55\128\30\55\31\48\82\79\77\30\55\128\30\57\31\56\132\10\30\56\31\57\157\30\55\31\55\128\128\128\128\128\30\57\31\56\145\10\30\57\31\57\128\31\56\129\129\129\129\129\31\57\128', - hdd = '\30\32\31\32\32\30\55\31\55\128\30\48\135\131\139\30\55\128\10\30\32\31\32\32\30\48\31\55\149\31\48\128\30\55\131\30\48\128\30\55\149\10\30\32\31\32\32\30\55\31\48\130\30\48\31\55\144\30\56\31\48\133\30\55\159\129\10\30\32\31\32\32\30\56\31\55\149\129\142\159\30\55\128\10\30\32\31\32\32\30\57\31\55\143\143\143\143\143', + blank = '\0308\0317\153\153\153\153\153\153\153\153\010\0307\0318\153\153\153\153\153\153\153\153\010\0308\0317\153\153\153\153\153\153\153\153\010\0307\0318\153\153\153\153\153\153\153\153\010\0308\0317\153\153\153\153\153\153\153\153', + drive = '\030 \031 \030b\031b\128\0308\0318\128\128\030f\149\030b\149\031 \139\010\030 \031 \030b\031b\128\128\128\128\128\128\010\030 \031 \030b\031b\128\0300\0317____\030b\031b\128\010\030 \031 \030b\031b\128\0300\0317____\030b\031b\128', + rom = '\030 \031 \128\0318\144\144\144\144\144\031 \128\010\0308\031 \157\0307\0317\128\128\128\128\128\030 \0318\145\010\030 \0318\136\0307\0317\128\0307\0310ROM\0307\128\030 \0318\132\010\0308\031 \157\0307\0317\128\128\128\128\128\030 \0318\145\010\030 \031 \128\0318\129\129\129\129\129\031 \128', + hdd = '\030 \031 \0307\0317\128\0300\135\131\139\0307\128\010\030 \031 \0300\0317\149\0310\128\0307\131\0300\128\0307\149\010\030 \031 \0307\0310\130\0300\0317\144\0308\0310\133\0307\159\129\010\030 \031 \0308\0317\149\129\142\159\0307\128\010\030 \031 \030 \0317\143\143\143\143\143', } local tab = UI.Tab { From 92686381c7fb2016d12724081877b88271eee6e3 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 19 Jul 2019 10:06:34 -0600 Subject: [PATCH 197/231] manipulators aaarrrggghhh --- sys/etc/fstab | 1 + sys/init/3.modules.lua | 89 ++++++++++++++++++++++++------------------ sys/init/3.sys.lua | 1 - sys/init/4.label.lua | 10 ++++- 4 files changed, 61 insertions(+), 40 deletions(-) diff --git a/sys/etc/fstab b/sys/etc/fstab index 6514f50..60fb9e1 100644 --- a/sys/etc/fstab +++ b/sys/etc/fstab @@ -3,3 +3,4 @@ sys/apps/update.lua urlfs http://pastebin.com/raw/UzGHLbNC sys/apps/Enchat.lua urlfs https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua sys/apps/nfttrans.lua urlfs https://pastebin.com/raw/e8XrzeDY +rom/modules/main/opus linkfs sys/modules/opus \ No newline at end of file diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index c80bcc7..3d585c0 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -11,15 +11,22 @@ local containers = { local cache = { } +-- manipulators will throw an error on listModules +-- if the user has logged off local function getModules(dev, side) local list = { } - if dev and dev.listModules then - for _, module in pairs(dev.listModules()) do - list[module] = Util.shallowCopy(dev) - list[module].name = module - list[module].type = module - list[module].side = side + local s, m = pcall(function() + if dev and dev.listModules then + for _, module in pairs(dev.listModules()) do + list[module] = Util.shallowCopy(dev) + list[module].name = module + list[module].type = module + list[module].side = side + end end + end) + if not s and m then + _G._syslog(m) end return list end @@ -39,20 +46,27 @@ local function addDevice(dev, args, doQueue) if doQueue then os.queueEvent('device_attach', name) end - return device[name] end +-- directly access the peripheral as the methods in getInventory, etc. +-- can become invalid without any way to tell local function damnManipulator(container, method, args, doQueue) - local dev = addDevice(container[method](), args) - for k,v in pairs(dev) do - if type(v) == 'function' then + local dev = { } + local methods = { + 'drop', 'getDocs', 'getItem', 'getItemMeta', 'getTransferLocations', + 'list', 'pullItems', 'pushItems', 'size', 'suck', + } + -- the user might not be logged in when the compputer is started + -- and there's no way to know when they have logged in. + -- these methods will error if the user is not logged in + if container[method] then + for _,k in pairs(methods) do dev[k] = function(...) return device[container.name][method]()[k](...) end end - end - if doQueue then - os.queueEvent('device_attach', args.name) + + addDevice(dev, args, doQueue) end end @@ -66,32 +80,29 @@ local function addContainer(v, doQueue) end if v.getName then - pcall(function() + local s, m = pcall(function() local name = v.getName() if name then - if v.getInventory then - damnManipulator(v, 'getInventory', { - name = name .. ':inventory', - type = 'inventory', - side = v.side - }, doQueue) - end - if v.getEquipment then - damnManipulator(v, 'getEquipment', { - name = name .. ':equipment', - type = 'equipment', - side = v.side - }, doQueue) - end - if v.getEnder then - damnManipulator(v, 'getEnder', { - name = name .. ':enderChest', - type = 'enderChest', - side = v.side - }, doQueue) - end + damnManipulator(v, 'getInventory', { + name = name .. ':inventory', + type = 'inventory', + side = v.side + }, doQueue) + damnManipulator(v, 'getEquipment', { + name = name .. ':equipment', + type = 'equipment', + side = v.side + }, doQueue) + damnManipulator(v, 'getEnder', { + name = name .. ':enderChest', + type = 'enderChest', + side = v.side + }, doQueue) end end) + if not s and m then + _G._syslog(m) + end end end @@ -113,9 +124,11 @@ kernel.hook('device_attach', function(_, eventData) -- a module is removed if cache[name] then device[name] = cache[name] - -- TODO: cannot simply merge - need to remove - -- all functions then merge - Util.merge(device[name], dev) + for k,v in pairs(device[name]) do + if type(v) == 'function' then + device[name][k] = nil + end + end else cache[name] = dev end diff --git a/sys/init/3.sys.lua b/sys/init/3.sys.lua index ce04901..7e18d18 100644 --- a/sys/init/3.sys.lua +++ b/sys/init/3.sys.lua @@ -1,4 +1,3 @@ local fs = _G.fs -fs.mount('rom/modules/main/opus', 'linkfs', 'sys/modules/opus') fs.loadTab('sys/etc/fstab') diff --git a/sys/init/4.label.lua b/sys/init/4.label.lua index 0a34862..dfdb89c 100644 --- a/sys/init/4.label.lua +++ b/sys/init/4.label.lua @@ -1,14 +1,22 @@ -local os = _G.os +local os = _G.os +local peripheral = _G.peripheral -- Default label if not os.getComputerLabel() then local id = os.getComputerID() + if _G.turtle then os.setComputerLabel('turtle_' .. id) + elseif _G.pocket then os.setComputerLabel('pocket_' .. id) + elseif _G.commands then os.setComputerLabel('command_' .. id) + + elseif peripheral.find('neuralInterface') then + os.setComputerLabel('neural_' .. id) + else os.setComputerLabel('computer_' .. id) end From 9ce61b5d98d5cee2b859d74a4348d5229ae418a8 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 19 Jul 2019 10:12:25 -0600 Subject: [PATCH 198/231] oops --- sys/init/3.modules.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/init/3.modules.lua b/sys/init/3.modules.lua index 3d585c0..c01ae43 100644 --- a/sys/init/3.modules.lua +++ b/sys/init/3.modules.lua @@ -129,6 +129,7 @@ kernel.hook('device_attach', function(_, eventData) device[name][k] = nil end end + Util.merge(device[name], dev) else cache[name] = dev end From 09be81be27859de6654a69bfc6668b1c97c6eb3a Mon Sep 17 00:00:00 2001 From: Kan18 <24967425+Kan18@users.noreply.github.com> Date: Sat, 20 Jul 2019 18:19:30 -0400 Subject: [PATCH 199/231] lua 5.2 compatibility (#14) compatibility update - making a few changes in next commit... --- startup.lua | 2 +- sys/apps/mount.lua | 2 +- sys/apps/network/samba.lua | 2 +- sys/apps/vnc.lua | 2 +- sys/init/6.tl3.lua | 4 ++-- sys/modules/opus/crypto/chacha20.lua | 8 ++++---- sys/modules/opus/crypto/sha2.lua | 6 +++--- sys/modules/opus/util.lua | 11 ++++++----- 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/startup.lua b/startup.lua index 082bdc9..0306df6 100644 --- a/startup.lua +++ b/startup.lua @@ -139,7 +139,7 @@ end term.clear() term.setCursorPos(1, 1) if bootOptions[bootOption].args then - os.run(_G.getfenv(1), table.unpack(bootOptions[bootOption].args)) + os.run({}, table.unpack(bootOptions[bootOption].args)) else print(bootOptions[bootOption].prompt) end diff --git a/sys/apps/mount.lua b/sys/apps/mount.lua index d7bde84..a25eb38 100644 --- a/sys/apps/mount.lua +++ b/sys/apps/mount.lua @@ -3,4 +3,4 @@ local args = { ... } local target = table.remove(args, 1) target = shell.resolve(target) -fs.mount(target, unpack(args)) +fs.mount(target, table.unpack(args)) diff --git a/sys/apps/network/samba.lua b/sys/apps/network/samba.lua index f679b4d..50cbfd0 100644 --- a/sys/apps/network/samba.lua +++ b/sys/apps/network/samba.lua @@ -48,7 +48,7 @@ local function sambaConnection(socket) end local ret local s, m = pcall(function() - ret = fn(unpack(msg.args)) + ret = fn(table.unpack(msg.args)) end) if not s and m then _G.printError('samba: ' .. m) diff --git a/sys/apps/vnc.lua b/sys/apps/vnc.lua index 0265254..c9d865c 100644 --- a/sys/apps/vnc.lua +++ b/sys/apps/vnc.lua @@ -70,7 +70,7 @@ local function connect() break end for _,v in ipairs(data) do - ct[v.f](unpack(v.args)) + ct[v.f](table.unpack(v.args)) end end end) diff --git a/sys/init/6.tl3.lua b/sys/init/6.tl3.lua index ee3f3aa..e1e9ecf 100644 --- a/sys/init/6.tl3.lua +++ b/sys/init/6.tl3.lua @@ -241,7 +241,7 @@ local function _place(action, indexOrId) if not state.digPolicy(action) then state.attackPolicy(action) end - return unpack(result) + return table.unpack(result) end) end @@ -1024,7 +1024,7 @@ function turtle.run(fn, ...) synchronized(turtle, function() turtle.resetState() - s, m = pcall(function() fn(unpack(args)) end) + s, m = pcall(function() fn(table.unpack(args)) end) turtle.resetState() if not s and m then _G.printError(m) diff --git a/sys/modules/opus/crypto/chacha20.lua b/sys/modules/opus/crypto/chacha20.lua index 9547f6c..7c3b819 100644 --- a/sys/modules/opus/crypto/chacha20.lua +++ b/sys/modules/opus/crypto/chacha20.lua @@ -34,7 +34,7 @@ local function quarterRound(s, a, b, c, d) end local function hashBlock(state, rnd) - local s = {unpack(state)} + local s = {table.unpack(state)} for i = 1, rnd do local r = i%2==1 s = r and quarterRound(s, 1, 5, 9, 13) or quarterRound(s, 1, 6, 11, 16) @@ -92,9 +92,9 @@ local function serialize(state) end local mt = { - __tostring = function(a) return string.char(unpack(a)) end, + __tostring = function(a) return string.char(table.unpack(a)) end, __index = { - toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end, + toHex = function(self) return ("%02x"):rep(#self):format(table.unpack(self)) end, isEqual = function(self, t) if type(t) ~= "table" then return false end if #self ~= #t then return false end @@ -113,7 +113,7 @@ local function crypt(data, key, nonce, cntr, round) assert(#key == 16 or #key == 32, "ChaCha20: Invalid key length ("..#key.."), must be 16 or 32") assert(#nonce == 12, "ChaCha20: Invalid nonce length ("..#nonce.."), must be 12") - data = type(data) == "table" and {unpack(data)} or {tostring(data):byte(1,-1)} + data = type(data) == "table" and {table.unpack(data)} or {tostring(data):byte(1,-1)} cntr = tonumber(cntr) or 1 round = tonumber(round) or 20 diff --git a/sys/modules/opus/crypto/sha2.lua b/sys/modules/opus/crypto/sha2.lua index 2754ee7..4dcb98b 100644 --- a/sys/modules/opus/crypto/sha2.lua +++ b/sys/modules/opus/crypto/sha2.lua @@ -8,7 +8,7 @@ local band = bit32 and bit32.band or bit.band local bnot = bit32 and bit32.bnot or bit.bnot local bxor = bit32 and bit32.bxor or bit.bxor local blshift = bit32 and bit32.lshift or bit.blshift -local upack = unpack +local upack = unpack or table.unpack local function rrotate(n, b) local s = n/(2^b) @@ -95,9 +95,9 @@ local function digestblock(w, C) end local mt = { - __tostring = function(a) return string.char(unpack(a)) end, + __tostring = function(a) return string.char(upack(a)) end, __index = { - toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end, + toHex = function(self) return ("%02x"):rep(#self):format(upack(self)) end, isEqual = function(self, t) if type(t) ~= "table" then return false end if #self ~= #t then return false end diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index 2c8e097..85ab2f0 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -21,7 +21,7 @@ end function Util.byteArrayToHex(tbl) if not tbl then error('byteArrayToHex: invalid table', 2) end - return ("%02x"):rep(#tbl):format(unpack(tbl)) + return ("%02x"):rep(#tbl):format(table.unpack(tbl)) end function Util.tryTimed(timeout, f, ...) @@ -39,10 +39,10 @@ function Util.tryTimes(attempts, f, ...) for _ = 1, attempts do result = { f(...) } if result[1] then - return unpack(result) + return table.unpack(result) end end - return unpack(result) + return table.unpack(result) end function Util.timer() @@ -490,7 +490,7 @@ function Util.loadTable(fname) if not fc then return false, 'Unable to read file' end - local s, m = loadstring('return ' .. fc, fname) + local s, m = load('return ' .. fc, fname) if s then s, m = pcall(s) if s then @@ -551,8 +551,9 @@ function Util.run(env, path, ...) end function Util.runFunction(env, fn, ...) - setfenv(fn, env) + --setfenv(fn, env) setmetatable(env, { __index = _G }) + fn = load(fn,"util.runfunction",nil,env) return pcall(fn, ...) end From 30b71999761bd7999bed4ffd3d273f1b01a4edfd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 20 Jul 2019 16:23:48 -0600 Subject: [PATCH 200/231] path fix + compat changes --- startup.lua | 2 +- sys/init/4.user.lua | 4 ++-- sys/init/6.packages.lua | 2 +- sys/modules/opus/util.lua | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/startup.lua b/startup.lua index 0306df6..d94be2b 100644 --- a/startup.lua +++ b/startup.lua @@ -139,7 +139,7 @@ end term.clear() term.setCursorPos(1, 1) if bootOptions[bootOption].args then - os.run({}, table.unpack(bootOptions[bootOption].args)) + os.run(_ENV, table.unpack(bootOptions[bootOption].args)) else print(bootOptions[bootOption].prompt) end diff --git a/sys/init/4.user.lua b/sys/init/4.user.lua index 0349808..4decc1f 100644 --- a/sys/init/4.user.lua +++ b/sys/init/4.user.lua @@ -19,7 +19,7 @@ end if not fs.exists('usr/config/shell') then Util.writeTable('usr/config/shell', { aliases = shell.aliases(), - path = 'usr/apps', + path = '/usr/apps', lua_path = package.path, upgraded = 1, }) @@ -36,7 +36,7 @@ if config.aliases then end local path = config.path and Util.split(config.path, '(.-):') or { } -table.insert(path, 'sys/apps') +table.insert(path, '/sys/apps') for _, v in pairs(Util.split(shell.path(), '(.-):')) do table.insert(path, v) end diff --git a/sys/init/6.packages.lua b/sys/init/6.packages.lua index b1e6ef7..7d06abe 100644 --- a/sys/init/6.packages.lua +++ b/sys/init/6.packages.lua @@ -13,7 +13,7 @@ table.insert(helpPaths, '/sys/help') for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) - table.insert(appPaths, 1, packageDir) + table.insert(appPaths, 1, '/' .. packageDir) local apiPath = fs.combine(packageDir, 'apis') if fs.exists(apiPath) then fs.mount(fs.combine('rom/modules/main', name), 'linkfs', apiPath) diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index 85ab2f0..eee7f70 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -490,7 +490,7 @@ function Util.loadTable(fname) if not fc then return false, 'Unable to read file' end - local s, m = load('return ' .. fc, fname) + local s, m = loadstring('return ' .. fc, fname) if s then s, m = pcall(s) if s then @@ -551,9 +551,8 @@ function Util.run(env, path, ...) end function Util.runFunction(env, fn, ...) - --setfenv(fn, env) + setfenv(fn, env) setmetatable(env, { __index = _G }) - fn = load(fn,"util.runfunction",nil,env) return pcall(fn, ...) end From ec7fc5bb23c9bfcb8073051e7324f4f41b1657df Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 20 Jul 2019 19:29:44 -0600 Subject: [PATCH 201/231] fix ui default device via args --- sys/modules/opus/ui.lua | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index b291e82..409ec85 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -125,9 +125,9 @@ function Manager:init() focused = true }) elseif ie and currentPage then - --if not self.currentPage.parent.device.side then + if not currentPage.parent.device.side then self:click(currentPage, ie.code, button, x, y) - --end + end end end, @@ -158,21 +158,16 @@ function Manager:init() end function Manager:configure(appName, ...) - local options = { - device = { arg = 'd', type = 'string', - desc = 'Device type' }, - textScale = { arg = 't', type = 'number', - desc = 'Text scale' }, - } local defaults = Util.loadTable('usr/config/' .. appName) or { } if not defaults.device then defaults.device = { } end - Util.getOptions(options, { ... }, true) + -- starting a program: gpsServer --display=monitor_3148 --scale=.5 gps + local _, options = Util.parse(...) local optionValues = { - name = options.device.value, - textScale = options.textScale.value, + name = options.display, + textScale = tonumber(options.scale), } Util.merge(defaults.device, optionValues) @@ -183,7 +178,7 @@ function Manager:configure(appName, ...) if defaults.device.name == 'terminal' then dev = term.current() else - dev = peripheral.wrap(defaults.device.name) + dev = _G.device[defaults.device.name] end if not dev then From ae98aaf9d5239a8459219016d85ca2f15ae14bbd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 21 Jul 2019 10:16:47 -0600 Subject: [PATCH 202/231] lint warnings --- sys/modules/opus/ui.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/modules/opus/ui.lua b/sys/modules/opus/ui.lua index 409ec85..9e9a4c5 100644 --- a/sys/modules/opus/ui.lua +++ b/sys/modules/opus/ui.lua @@ -8,9 +8,9 @@ local Util = require('opus.util') local _rep = string.rep local _sub = string.sub local colors = _G.colors +local device = _G.device local fs = _G.fs local os = _G.os -local peripheral = _G.peripheral local term = _G.term local textutils = _G.textutils @@ -178,7 +178,7 @@ function Manager:configure(appName, ...) if defaults.device.name == 'terminal' then dev = term.current() else - dev = _G.device[defaults.device.name] + dev = device[defaults.device.name] end if not dev then From c18945467f0f476814c88b1d2c8efb04f436099f Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 22 Jul 2019 22:21:41 -0600 Subject: [PATCH 203/231] ability to specify index in form fields --- sys/modules/opus/ui/components/Form.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/modules/opus/ui/components/Form.lua b/sys/modules/opus/ui/components/Form.lua index 68b59d3..527af3f 100644 --- a/sys/modules/opus/ui/components/Form.lua +++ b/sys/modules/opus/ui/components/Form.lua @@ -60,14 +60,14 @@ function UI.Form:createForm() end if child.formLabel then child.x = self.labelWidth + self.margin - 1 - child.y = y + child.y = child.formIndex and (child.formIndex + self.margin - 1) or y if not child.width and not child.ex then child.ex = -self.margin end table.insert(self.children, UI.Text { x = self.margin, - y = y, + y = child.y, textColor = colors.black, width = #child.formLabel, value = child.formLabel, From 5dd3001ffd26d1d947bfb53a05c17c9561fb674b Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 22 Jul 2019 22:57:22 -0600 Subject: [PATCH 204/231] dont close modem ports on network startup (due to multiple computers may be using same modem) --- sys/apps/netdaemon.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/apps/netdaemon.lua b/sys/apps/netdaemon.lua index 2457a49..1d3fd66 100644 --- a/sys/apps/netdaemon.lua +++ b/sys/apps/netdaemon.lua @@ -14,7 +14,9 @@ if not device.wireless_modem then end print('Net daemon starting') -device.wireless_modem.closeAll() +-- don't close as multiple computers may be sharing the +-- wireless modem +--device.wireless_modem.closeAll() for _,file in pairs(fs.list('sys/apps/network')) do local fn, msg = Util.run(_ENV, 'sys/apps/network/' .. file) From e084c733f83d9c5a3255a8a3f03d4505cc961740 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 23 Jul 2019 13:29:43 -0600 Subject: [PATCH 205/231] consistent command line processing-usage --- sys/apps/Files.lua | 2 +- sys/apps/Help.lua | 2 +- sys/apps/Lua.lua | 2 +- sys/apps/Sniff.lua | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 019979e..9f17255 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -542,7 +542,7 @@ function Browser.associations:eventHandler(event) end --[[-- Startup logic --]]-- -local args = { ... } +local args = Util.parse(...) Browser:setDir(args[1] or shell.dir()) diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index 72b5308..ffd0486 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -99,6 +99,6 @@ function page:eventHandler(event) end end -local args = { ... } +local args = Util.parse(...) UI:setPage(args[1] and topicPage or page, args[1]) UI:pullEvents() diff --git a/sys/apps/Lua.lua b/sys/apps/Lua.lua index a7442be..45cec04 100644 --- a/sys/apps/Lua.lua +++ b/sys/apps/Lua.lua @@ -376,7 +376,7 @@ function page:executeStatement(statement) end end -local args = { ... } +local args = Util.parse(...) if args[1] then command = 'args[1]' sandboxEnv.args = args diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua index 6a683eb..3a8257c 100644 --- a/sys/apps/Sniff.lua +++ b/sys/apps/Sniff.lua @@ -356,7 +356,7 @@ Event.on('modem_message', function(_, side, chan, reply, msg, dist) end end) -local args = {...} +local args = Util.parse(...) if args[1] then local id = tonumber(args[1]) if id then From cd2024d7cefe4f5fb37ce0d6d0d5697052273c7b Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Wed, 24 Jul 2019 00:37:41 -0400 Subject: [PATCH 206/231] TextEntry number transform --- sys/modules/opus/ui/components/TextEntry.lua | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sys/modules/opus/ui/components/TextEntry.lua b/sys/modules/opus/ui/components/TextEntry.lua index 151dd2b..dda3766 100644 --- a/sys/modules/opus/ui/components/TextEntry.lua +++ b/sys/modules/opus/ui/components/TextEntry.lua @@ -11,7 +11,7 @@ local _upper = string.upper UI.TextEntry = class(UI.Window) UI.TextEntry.defaults = { UIElement = 'TextEntry', - value = '', + --value = '', shadowText = '', focused = false, textColor = colors.white, @@ -25,7 +25,6 @@ UI.TextEntry.defaults = { } } function UI.TextEntry:postInit() - self.value = tostring(self.value) -- is this right ? shouldnt raw numbers be allowed self.entry = entry({ limit = self.limit, offset = 2 }) end @@ -35,7 +34,7 @@ function UI.TextEntry:layout() end function UI.TextEntry:setValue(value) - self.value = value or '' + self.value = value --or '' self.entry:unmark() self.entry.value = tostring(value) self.entry:updateScroll() @@ -43,7 +42,7 @@ end function UI.TextEntry:setPosition(pos) self.entry.pos = pos - self.entry.value = tostring(self.value) + self.entry.value = tostring(self.value or '') self.entry:updateScroll() end @@ -54,7 +53,7 @@ function UI.TextEntry:draw() bg = self.backgroundFocusColor end - local text = tostring(self.value) + local text = tostring(self.value or '') if #text > 0 then if self.entry.scroll > 0 then text = text:sub(1 + self.entry.scroll) @@ -88,7 +87,7 @@ end function UI.TextEntry:reset() self.entry:reset() - self.value = '' + self.value = nil--'' self:draw() self:updateCursor() end @@ -111,13 +110,15 @@ function UI.TextEntry:_transform(text) return _lower(text) elseif self.transform == 'uppercase' then return _upper(text) + elseif self.transform == 'number' then + return tonumber(text) --or 0 end return text end function UI.TextEntry:eventHandler(event) - local text = self.value - self.entry.value = tostring(text) + local text = self.value --or '' + self.entry.value = tostring(text or '') if event.ie and self.entry:process(event.ie) then if self.entry.textChanged then self.value = self:_transform(self.entry.value) From b3efbc7438a3a25167f9c39b4bd7c6f1708bd161 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Wed, 24 Jul 2019 00:45:00 -0400 Subject: [PATCH 207/231] Distance filter in Sniffer --- sys/apps/Sniff.lua | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/sys/apps/Sniff.lua b/sys/apps/Sniff.lua index 3a8257c..2bda4f0 100644 --- a/sys/apps/Sniff.lua +++ b/sys/apps/Sniff.lua @@ -73,13 +73,24 @@ local page = UI.Page { event = 'filter_add', }, filterAllCheck = UI.Checkbox { - x = 13, y = 4, + x = 14, y = 8, value = false, }, filterAddText = UI.Text { - x = 17, y = 4, + x = 18, y = 8, value = "Use ID filter", }, + rangeText = UI.Text { + x = 15, y = 2, + value = "Distance filter", + }, + rangeEntry = UI.TextEntry { + x = 15, y = 3, + width = 10, + limit = 8, + shadowText = 'Range', + transform = 'number', + }, }, modemTab = UI.Tab { tabTitle = 'Modem', @@ -268,8 +279,14 @@ function page.packetSlide:eventHandler(event) return true end +function page.packetGrid:getDisplayValues(row) + local row = Util.shallowCopy(row) + row.distance = Util.toBytes(Util.round(row.distance), 2) + return row +end + function page.packetGrid:addPacket(packet) - if not page.paused and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[packet.portid]) then + if not page.paused and (packet.distance <= (filterConfig.rangeEntry.value or math.huge)) and (not filterConfig.filterAllCheck.value or filterConfig.filterGrid.values[packet.portid]) then page.index = page.index + 1 local _, res = pcall(textutils.serialize, packet.message) packet.packetStr = res:gsub("\n%s*", "") From b739c0c77e23fb4c87a6dc92d8347bad89085017 Mon Sep 17 00:00:00 2001 From: Kan18 <24967425+Kan18@users.noreply.github.com> Date: Thu, 25 Jul 2019 22:51:16 -0400 Subject: [PATCH 208/231] fix no password error --- sys/apps/Welcome.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/apps/Welcome.lua b/sys/apps/Welcome.lua index 47c658f..04b60f9 100644 --- a/sys/apps/Welcome.lua +++ b/sys/apps/Welcome.lua @@ -125,7 +125,7 @@ function page.wizard.pages.label:validate() end function page.wizard.pages.password:validate() - if #self.newPass.value > 0 then + if type(self.newPass.value) == "string" and #self.newPass.value > 0 then Security.updatePassword(SHA.compute(self.newPass.value)) end --[[ From 9c4aac27f8521be23f680650b1bf0b92bd7d8119 Mon Sep 17 00:00:00 2001 From: Kan18 <24967425+Kan18@users.noreply.github.com> Date: Thu, 25 Jul 2019 23:04:20 -0400 Subject: [PATCH 209/231] Update upgraded.lua Kind of make the program look better as the 'sys/apis' line is the only one not to do fs.exists. Also fixes error when opus is nested inside a potatOS instance. --- sys/autorun/upgraded.lua | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/sys/autorun/upgraded.lua b/sys/autorun/upgraded.lua index f6881db..5922c3a 100644 --- a/sys/autorun/upgraded.lua +++ b/sys/autorun/upgraded.lua @@ -1,14 +1,20 @@ local fs = _G.fs +local function deleteIfExists(path) + if fs.exists(path) then + fs.delete(path) + print("Deleted outdated file at: "..path) + end +end -- cleanup outdated files -fs.delete('sys/apps/shell') -fs.delete('sys/etc/app.db') -fs.delete('sys/extensions') -fs.delete('sys/network') -fs.delete('startup') -fs.delete('sys/apps/system/turtle.lua') -fs.delete('sys/autorun/gps.lua') -fs.delete('sys/autorun/gpshost.lua') -fs.delete('sys/apps/network/redserver.lua') -if fs.exists('sys/apis') then fs.delete('sys/apis') end -fs.delete('sys/autorun/apps.lua') +deleteIfExists('sys/apps/shell') +deleteIfExists('sys/etc/app.db') +deleteIfExists('sys/extensions') +deleteIfExists('sys/network') +deleteIfExists('startup') +deleteIfExists('sys/apps/system/turtle.lua') +deleteIfExists('sys/autorun/gps.lua') +deleteIfExists('sys/autorun/gpshost.lua') +deleteIfExists('sys/apps/network/redserver.lua') +deleteIfExists('sys/apis') +deleteIfExists('sys/autorun/apps.lua') From c1430f6dac79cf687a10c15af786fa9204a0b3b6 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Sat, 27 Jul 2019 00:13:24 -0400 Subject: [PATCH 210/231] GPS ambiguous position fix --- sys/modules/opus/gps.lua | 24 +++++------ sys/modules/opus/util.lua | 83 ++++++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 43 deletions(-) diff --git a/sys/modules/opus/gps.lua b/sys/modules/opus/gps.lua index 1b3e223..0ca7a66 100644 --- a/sys/modules/opus/gps.lua +++ b/sys/modules/opus/gps.lua @@ -1,3 +1,5 @@ +local Util = require('opus.util') + local GPS = { } local device = _G.device @@ -89,19 +91,17 @@ end -- end stock gps api function GPS.trilaterate(tFixes) - local pos1, pos2 = trilaterate(tFixes[1], tFixes[2], tFixes[3]) - - if pos2 then - pos1, pos2 = narrow(pos1, pos2, tFixes[4]) + local attemps = 0 + for tFixes in Util.permutation(tFixes) do + attemps = attemps + 1 + local pos1, pos2 = trilaterate(tFixes[4], tFixes[3], tFixes[2]) + if pos2 then + pos1, pos2 = narrow(pos1, pos2, tFixes[1]) + end + if not pos2 then + return pos1, attemps + end end - - if pos1 and pos2 then - print("Ambiguous position") - print("Could be "..pos1.x..","..pos1.y..","..pos1.z.." or "..pos2.x..","..pos2.y..","..pos2.z ) - return - end - - return pos1 end return GPS \ No newline at end of file diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index eee7f70..4604199 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -46,10 +46,10 @@ function Util.tryTimes(attempts, f, ...) end function Util.timer() - local ct = os.clock() - return function() - return os.clock() - ct - end + local ct = os.clock() + return function() + return os.clock() - ct + end end Util.Timer = Util.timer -- deprecate @@ -678,33 +678,33 @@ end -- https://github.com/MightyPirates/OpenComputers function Util.parse(...) - local params = table.pack(...) - local args = {} - local options = {} - local doneWithOptions = false - for i = 1, params.n do - local param = params[i] - if not doneWithOptions and type(param) == "string" then - if param == "--" then - doneWithOptions = true -- stop processing options at `--` - elseif param:sub(1, 2) == "--" then - local key, value = param:match("%-%-(.-)=(.*)") - if not key then - key, value = param:sub(3), true - end - options[key] = value - elseif param:sub(1, 1) == "-" and param ~= "-" then - for j = 2, string.len(param) do - options[string.sub(param, j, j)] = true - end - else - table.insert(args, param) - end - else - table.insert(args, param) - end - end - return args, options + local params = table.pack(...) + local args = {} + local options = {} + local doneWithOptions = false + for i = 1, params.n do + local param = params[i] + if not doneWithOptions and type(param) == "string" then + if param == "--" then + doneWithOptions = true -- stop processing options at `--` + elseif param:sub(1, 2) == "--" then + local key, value = param:match("%-%-(.-)=(.*)") + if not key then + key, value = param:sub(3), true + end + options[key] = value + elseif param:sub(1, 1) == "-" and param ~= "-" then + for j = 2, string.len(param) do + options[string.sub(param, j, j)] = true + end + else + table.insert(args, param) + end + else + table.insert(args, param) + end + end + return args, options end function Util.args(arg) @@ -799,4 +799,25 @@ function Util.getOptions(options, args, ignoreInvalid) return true, Util.size(rawOptions) end +-- https://www.lua.org/pil/9.3.html +function Util.permutation(tbl) + local function permgen(a, n) + if n == 0 then + coroutine.yield(a) + else + for i=1,n do + a[n], a[i] = a[i], a[n] + permgen(a, n - 1) + a[n], a[i] = a[i], a[n] + end + end + end + + local co = coroutine.create(function() permgen(tbl, #tbl) end) + return function() + local _, res = coroutine.resume(co) + return res + end +end + return Util From 7e8dc5bd49f0407a420e09bd4747ae30db6e0f66 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 27 Jul 2019 19:07:34 -0600 Subject: [PATCH 211/231] fix for new text entry behaviour + oc relay fix --- sys/apps/system/password.lua | 13 +------------ sys/init/3.relay.lua | 3 +-- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/sys/apps/system/password.lua b/sys/apps/system/password.lua index 4340a73..d822996 100644 --- a/sys/apps/system/password.lua +++ b/sys/apps/system/password.lua @@ -7,13 +7,6 @@ local colors = _G.colors local passwordTab = UI.Tab { tabTitle = 'Password', description = 'Wireless network password', - oldPass = UI.TextEntry { - x = 3, ex = -3, y = 2, - limit = 32, - mask = true, - shadowText = 'old password', - inactive = not Security.getPassword(), - }, newPass = UI.TextEntry { x = 3, ex = -3, y = 3, limit = 32, @@ -37,15 +30,11 @@ local passwordTab = UI.Tab { } function passwordTab:eventHandler(event) if event.type == 'update_password' then - if #self.newPass.value == 0 then + if not self.newPass.value or #self.newPass.value == 0 then self:emit({ type = 'error_message', message = 'Invalid password' }) - elseif Security.getPassword() and not Security.verifyPassword(SHA.compute(self.oldPass.value)) then - self:emit({ type = 'error_message', message = 'Passwords do not match' }) - else Security.updatePassword(SHA.compute(self.newPass.value)) - self.oldPass.inactive = false self:emit({ type = 'success_message', message = 'Password updated' }) end return true diff --git a/sys/init/3.relay.lua b/sys/init/3.relay.lua index a2132e7..1b24f07 100644 --- a/sys/init/3.relay.lua +++ b/sys/init/3.relay.lua @@ -8,10 +8,9 @@ local function register(v) local dev = v.getMethodsRemote(name) if dev then dev.name = name - dev.side = name + dev.side = v.side dev.type = v.getTypeRemote(name) device[name] = dev - table.insert(v._children, dev) end end end From 748dcd8f8207378f85775fe61b28871ae8cc92c1 Mon Sep 17 00:00:00 2001 From: Kan18 <24967425+Kan18@users.noreply.github.com> Date: Wed, 31 Jul 2019 18:21:18 -0400 Subject: [PATCH 212/231] Remove confusion over kiosk mode (#7) --- sys/boot/kiosk.boot | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/boot/kiosk.boot b/sys/boot/kiosk.boot index ea36162..61155fe 100644 --- a/sys/boot/kiosk.boot +++ b/sys/boot/kiosk.boot @@ -15,6 +15,7 @@ end local mon = name and peripheral.wrap(name) if mon then + print("Opus OS is running in Kiosk mode, and the screen will be redirected to the monitor. To undo this, go to the boot option menu by pressing a key while booting, then select the option 2.") term.redirect(mon) mon.setTextScale(tonumber(settings.get('kiosk.textscale')) or 1) From 6e6d4b81cd3dd506807e226a956548f67c27712e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 3 Aug 2019 08:33:32 -0600 Subject: [PATCH 213/231] keyboard handling when not using opus os --- sys/modules/opus/input.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sys/modules/opus/input.lua b/sys/modules/opus/input.lua index 62d51b4..46b58fe 100644 --- a/sys/modules/opus/input.lua +++ b/sys/modules/opus/input.lua @@ -10,6 +10,17 @@ local modifiers = Util.transpose { keys.leftAlt, keys.rightAlt, } +if not keyboard then -- not running under Opus OS + keyboard = { state = { } } + + local Event = require('opus.event') + Event.on({ 'key', 'key_up' }, function(event, code) + if modifiers[code] then + keyboard.state[code] = event == 'key' + end + end) +end + local input = { } function input:modifierPressed() From 2f597d0dc403be6d9bbc4e901fb012d8c772ea1a Mon Sep 17 00:00:00 2001 From: Kan18 <24967425+Kan18@users.noreply.github.com> Date: Tue, 13 Aug 2019 13:14:11 -0400 Subject: [PATCH 214/231] support MOTDs (#19) --- sys/apps/shell.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index c5dbf28..d64f046 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -3,6 +3,7 @@ local parentShell = _ENV.shell _ENV.shell = { } local fs = _G.fs +local settings = _G.settings local shell = _ENV.shell local sandboxEnv = setmetatable({ }, { __index = _G }) @@ -673,6 +674,10 @@ local history = History.load('usr/.shell_history', 25) term.setBackgroundColor(_colors.backgroundColor) term.clear() +if settings.get("motd.enabled") then + shell.run("motd") +end + while not bExit do if config.displayDirectory then term.setTextColour(_colors.directoryTextColor) From 3512b2441d00beef553b19677790b6fb6f7c9d94 Mon Sep 17 00:00:00 2001 From: Kan18 <24967425+Kan18@users.noreply.github.com> Date: Tue, 13 Aug 2019 13:14:45 -0400 Subject: [PATCH 215/231] update license / readme (#18) * Update README.md the installer already reboots for you * Update LICENSE.md --- LICENSE.md | 2 +- README.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index a5e2567..8e8b7db 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2017 kepler155c +Copyright (c) 2016-2019 kepler155c Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3a2d070..7b5e66d 100644 --- a/README.md +++ b/README.md @@ -15,5 +15,4 @@ ## Install ``` pastebin run uzghlbnc -reboot ``` From 457c8a8a526401c503141a184d3e0cdf2643b0f5 Mon Sep 17 00:00:00 2001 From: xAnavrins Date: Sun, 18 Aug 2019 14:53:27 -0400 Subject: [PATCH 216/231] Fix forms numeric validation --- sys/modules/opus/ui/components/Form.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/modules/opus/ui/components/Form.lua b/sys/modules/opus/ui/components/Form.lua index 527af3f..ed9ae0d 100644 --- a/sys/modules/opus/ui/components/Form.lua +++ b/sys/modules/opus/ui/components/Form.lua @@ -100,6 +100,7 @@ function UI.Form:validateField(field) end end if field.validate == 'numeric' then + field.value = field.value or '' if #tostring(field.value) > 0 then if not tonumber(field.value) then return false, 'Invalid number' From 774d3ed415257ba44f7687a529e5e205df1dd334 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 28 Oct 2019 20:01:57 -0600 Subject: [PATCH 217/231] improve startup, dont rely on debug (cbor) --- startup.lua | 146 ++++++++++++++++++++++--------------- sys/modules/opus/cbor.lua | 2 +- sys/modules/opus/entry.lua | 26 +++---- 3 files changed, 103 insertions(+), 71 deletions(-) diff --git a/startup.lua b/startup.lua index d94be2b..0cfcd7f 100644 --- a/startup.lua +++ b/startup.lua @@ -1,14 +1,48 @@ +--[[ + .startup.boot + delay + description: delays amount before starting the default selection + default: 1.5 + + preload + description : runs before menu is displayed, can be used for password + locking, drive encryption, etc. + example : { [1] = '/path/somefile.lua', [2] = 'path2/another.lua' } + + menu + description: array of menu entries (see .startup.boot for examples) +]] + local colors = _G.colors local os = _G.os local settings = _G.settings local term = _G.term -local bootOptions = { - { prompt = os.version() }, - { prompt = 'Opus' , args = { '/sys/boot/opus.boot' } }, - { prompt = 'Opus Shell' , args = { '/sys/boot/opus.boot', 'sys/apps/shell.lua' } }, - { prompt = 'Opus Kiosk' , args = { '/sys/boot/kiosk.boot' } }, -} +local function loadBootOptions() + if not fs.exists('.startup.boot') then + local f = fs.open('.startup.boot', 'w') + f.write(textutils.serialize({ + delay = 1.5, + preload = { }, + menu = { + { prompt = os.version() }, + { prompt = 'Opus' , args = { '/sys/boot/opus.boot' } }, + { prompt = 'Opus Shell' , args = { '/sys/boot/opus.boot', 'sys/apps/shell.lua' } }, + { prompt = 'Opus Kiosk' , args = { '/sys/boot/kiosk.boot' } }, + }, + })) + f.close() + end + + local f = fs.open('.startup.boot', 'r') + local options = textutils.unserialize(f.readAll()) + f.close() + + return options +end + +local bootOptions = loadBootOptions() + local bootOption = 2 if settings then settings.load('.settings') @@ -17,69 +51,63 @@ end local function startupMenu() local x, y = term.getSize() - local align, selected = 0, 1 + local align, selected = 0, bootOption + local function redraw() local title = "Boot Options:" term.clear() term.setTextColor(colors.white) - term.setCursorPos((x/2)-(#title/2), (y/2)-(#bootOptions/2)-1) + term.setCursorPos((x/2)-(#title/2), (y/2)-(#bootOptions.menu/2)-1) term.write(title) - for i = 1, #bootOptions do - local txt = i..". "..bootOptions[i].prompt - term.setCursorPos((x/2)-(align/2), (y/2)-(#bootOptions/2)+i) + for i, item in pairs(bootOptions.menu) do + local txt = i .. ". " .. item.prompt + term.setCursorPos((x/2)-(align/2), (y/2)-(#bootOptions.menu/2)+i) term.write(txt) end end - for i = 1, #bootOptions do - if (bootOptions[i].prompt):len() > align then - align = (bootOptions[i].prompt):len() + for _, item in pairs(bootOptions.menu) do + if #item.prompt > align then + align = #item.prompt end end redraw() - repeat - term.setCursorPos((x/2)-(align/2)-2, (y/2)-(#bootOptions/2)+selected) - if term.isColor() then - term.setTextColor(colors.yellow) - else - term.setTextColor(colors.lightGray) - end + while true do + term.setCursorPos((x/2)-(align/2)-2, (y/2)-(#bootOptions.menu/2)+selected) + term.setTextColor(term.isColor() and colors.yellow or colors.lightGray) + term.write(">") - local k = ({os.pullEvent()}) - if k[1] == "mouse_scroll" then - if k[2] == 1 then - k = keys.down - else - k = keys.up - end - elseif k[1] == "key" then - k = k[2] - else - k = nil + local event, key = os.pullEvent() + if event == "mouse_scroll" then + key = key == 1 and keys.down or keys.up + elseif event == 'key_up' then + key = nil -- only process key events end - if k then - if k == keys.enter or k == keys.right then - return selected - elseif k == keys.down then - if selected == #bootOptions then - selected = 0 - end - selected = selected+1 - elseif k == keys.up then - if selected == 1 then - selected = #bootOptions+1 - end - selected = selected-1 - elseif k >= keys.one and k <= #bootOptions+1 and k < keys.zero then - selected = k-1 - return selected + + if key == keys.enter or key == keys.right then + return selected + elseif key == keys.down then + if selected == #bootOptions.menu then + selected = 0 + end + selected = selected + 1 + elseif key == keys.up then + if selected == 1 then + selected = #bootOptions.menu + 1 + end + selected = selected - 1 + elseif event == 'char' then + key = tonumber(key) or 0 + if bootOptions.menu[key] then + return key end - local cx, cy = term.getCursorPos() - term.setCursorPos(cx-1, cy) - term.write(" ") end - until true == false + + local cx, cy = term.getCursorPos() + term.setCursorPos(cx-1, cy) + term.write(" ") + end end local function splash() @@ -120,13 +148,17 @@ end term.clear() splash() -local timerId = os.startTimer(1.5) +for _, v in pairs(bootOptions.preload) do + os.run(_ENV, v) +end + +local timerId = os.startTimer(bootOptions.delay) while true do local e, id = os.pullEvent() if e == 'timer' and id == timerId then break end - if e == 'char' then + if e == 'char' or e == 'key' then bootOption = startupMenu() if settings then settings.set('opus.boot_option', bootOption) @@ -138,9 +170,9 @@ end term.clear() term.setCursorPos(1, 1) -if bootOptions[bootOption].args then - os.run(_ENV, table.unpack(bootOptions[bootOption].args)) +if bootOptions.menu[bootOption].args then + os.run(_ENV, table.unpack(bootOptions.menu[bootOption].args)) else - print(bootOptions[bootOption].prompt) + print(bootOptions.menu[bootOption].prompt) end diff --git a/sys/modules/opus/cbor.lua b/sys/modules/opus/cbor.lua index a55df44..95e41ca 100644 --- a/sys/modules/opus/cbor.lua +++ b/sys/modules/opus/cbor.lua @@ -14,7 +14,7 @@ end local setmetatable = setmetatable; local getmetatable = getmetatable; -local dbg_getmetatable = debug.getmetatable; +local dbg_getmetatable = debug and debug.getmetatable; local assert = assert; local error = error; local type = type; diff --git a/sys/modules/opus/entry.lua b/sys/modules/opus/entry.lua index 0029ded..693fe87 100644 --- a/sys/modules/opus/entry.lua +++ b/sys/modules/opus/entry.lua @@ -195,7 +195,7 @@ end function Entry:paste(ie) if #ie.text > 0 then if self.mark.active then - self:delete() + self:delete() end self:insertText(self.pos, ie.text) end @@ -347,16 +347,16 @@ local mappings = { -- [ 'control-y' ] = Entry.paste, -- well this won't work... [ 'mouse_doubleclick' ] = Entry.markWord, - [ 'shift-left' ] = Entry.markLeft, - [ 'shift-right' ] = Entry.markRight, - [ 'mouse_down' ] = Entry.markAnchor, - [ 'mouse_drag' ] = Entry.markTo, - [ 'shift-mouse_click' ] = Entry.markTo, - [ 'control-a' ] = Entry.markAll, - [ 'control-shift-right' ] = Entry.markNextWord, - [ 'control-shift-left' ] = Entry.markPrevWord, - [ 'shift-end' ] = Entry.markEnd, - [ 'shift-home' ] = Entry.markHome, + [ 'shift-left' ] = Entry.markLeft, + [ 'shift-right' ] = Entry.markRight, + [ 'mouse_down' ] = Entry.markAnchor, + [ 'mouse_drag' ] = Entry.markTo, + [ 'shift-mouse_click' ] = Entry.markTo, + [ 'control-a' ] = Entry.markAll, + [ 'control-shift-right' ] = Entry.markNextWord, + [ 'control-shift-left' ] = Entry.markPrevWord, + [ 'shift-end' ] = Entry.markEnd, + [ 'shift-home' ] = Entry.markHome, } function Entry:process(ie) @@ -369,7 +369,7 @@ function Entry:process(ie) local line = self.value local wasMarking = self.mark.continue - self.mark.continue = false + self.mark.continue = false action(self, ie) @@ -378,7 +378,7 @@ function Entry:process(ie) self:updateScroll() if not self.mark.continue and wasMarking then - self:unmark() + self:unmark() end return true From e5a5f76fb33fb4b88051c60978cce2372c1fb6c3 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Wed, 30 Oct 2019 22:49:30 -0600 Subject: [PATCH 218/231] restructure --- sys/apps/PackageManager.lua | 3 + sys/apps/autorun.lua | 4 +- sys/init/5.network.lua | 2 +- sys/init/6.tl3.lua | 1273 ---------------------- sys/lzwfs.lua | 247 +++++ sys/modules/opus/jumper/core/bheap.lua | 175 --- sys/modules/opus/jumper/core/node.lua | 41 - sys/modules/opus/jumper/core/path.lua | 67 -- sys/modules/opus/jumper/core/utils.lua | 57 - sys/modules/opus/jumper/grid.lua | 101 -- sys/modules/opus/jumper/pathfinder.lua | 104 -- sys/modules/opus/jumper/search/astar.lua | 77 -- sys/modules/opus/packages.lua | 23 + sys/modules/opus/pathfind.lua | 256 ----- 14 files changed, 276 insertions(+), 2154 deletions(-) delete mode 100644 sys/init/6.tl3.lua create mode 100644 sys/lzwfs.lua delete mode 100644 sys/modules/opus/jumper/core/bheap.lua delete mode 100644 sys/modules/opus/jumper/core/node.lua delete mode 100644 sys/modules/opus/jumper/core/path.lua delete mode 100644 sys/modules/opus/jumper/core/utils.lua delete mode 100644 sys/modules/opus/jumper/grid.lua delete mode 100644 sys/modules/opus/jumper/pathfinder.lua delete mode 100644 sys/modules/opus/jumper/search/astar.lua delete mode 100644 sys/modules/opus/pathfind.lua diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index 1329ec7..3a3dd8b 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -58,6 +58,9 @@ local page = UI.Page { }, }, statusBar = UI.StatusBar { }, + accelerators = { + [ 'control-q' ] = 'quit', + }, } function page:loadPackages() diff --git a/sys/apps/autorun.lua b/sys/apps/autorun.lua index e8b378f..1274666 100644 --- a/sys/apps/autorun.lua +++ b/sys/apps/autorun.lua @@ -47,8 +47,8 @@ local function runDir(directory) end runDir('sys/autorun') -for name in pairs(Packages:installed()) do - local packageDir = 'packages/' .. name .. '/autorun' +for _, package in pairs(Packages:installedSorted()) do + local packageDir = 'packages/' .. package.name .. '/autorun' runDir(packageDir) end runDir('usr/autorun') diff --git a/sys/init/5.network.lua b/sys/init/5.network.lua index 6526c5f..b02937a 100644 --- a/sys/init/5.network.lua +++ b/sys/init/5.network.lua @@ -39,7 +39,7 @@ local function setModem(dev) end end --- create a psuedo-device named 'wireleess_modem' +-- create a psuedo-device named 'wireless_modem' kernel.hook('device_attach', function(_, eventData) local dev = device[eventData[1]] if dev and dev.type == 'modem' then diff --git a/sys/init/6.tl3.lua b/sys/init/6.tl3.lua deleted file mode 100644 index e1e9ecf..0000000 --- a/sys/init/6.tl3.lua +++ /dev/null @@ -1,1273 +0,0 @@ -if not _G.turtle then - return -end - -local Pathing = require('opus.pathfind') -local Point = require('opus.point') -local synchronized = require('opus.sync').sync -local Util = require('opus.util') - -local os = _G.os -local peripheral = _G.peripheral -local turtle = _G.turtle - -local function noop() end -local headings = Point.headings -local state = { } - -turtle.pathfind = Pathing.pathfind -turtle.point = { x = 0, y = 0, z = 0, heading = 0 } - -function turtle.getState() return state end -function turtle.isAborted() return state.abort end -function turtle.getStatus() return state.status end -function turtle.setStatus(s) state.status = s end - -local function _defaultMove(action) - while not action.move() do - if not state.digPolicy(action) and not state.attackPolicy(action) then - return false - end - end - return true -end - -function turtle.getPoint() return turtle.point end -function turtle.setPoint(pt, isGPS) - turtle.point.x = pt.x - turtle.point.y = pt.y - turtle.point.z = pt.z - if pt.heading then - turtle.point.heading = pt.heading - end - turtle.point.gps = isGPS - return true -end - -function turtle.resetState() - state.abort = false - state.status = 'idle' - state.attackPolicy = noop - state.digPolicy = noop - state.movePolicy = _defaultMove - state.moveCallback = noop - state.blacklist = nil - state.reference = nil -- gps reference when converting to relative coords - Pathing.reset() - return true -end - -function turtle.reset() - turtle.point.x = 0 - turtle.point.y = 0 - turtle.point.z = 0 - turtle.point.heading = 0 -- should be facing - turtle.point.gps = false - - turtle.resetState() - return true -end - -local function _dig(name, inspect, dig) - if name then - local s, b = inspect() - if not s or b.name ~= name then - return false - end - end - return dig() -end - -function turtle.dig(s) - return _dig(s, turtle.inspect, turtle.native.dig) -end - -function turtle.digUp(s) - return _dig(s, turtle.inspectUp, turtle.native.digUp) -end - -function turtle.digDown(s) - return _dig(s, turtle.inspectDown, turtle.native.digDown) -end - -local actions = { - up = { - detect = turtle.native.detectUp, - dig = turtle.digUp, - move = turtle.native.up, - attack = turtle.native.attackUp, - place = turtle.native.placeUp, - drop = turtle.native.dropUp, - suck = turtle.native.suckUp, - compare = turtle.native.compareUp, - inspect = turtle.native.inspectUp, - side = 'top' - }, - down = { - detect = turtle.native.detectDown, - dig = turtle.digDown, - move = turtle.native.down, - attack = turtle.native.attackDown, - place = turtle.native.placeDown, - drop = turtle.native.dropDown, - suck = turtle.native.suckDown, - compare = turtle.native.compareDown, - inspect = turtle.native.inspectDown, - side = 'bottom' - }, - forward = { - detect = turtle.native.detect, - dig = turtle.dig, - move = turtle.native.forward, - attack = turtle.native.attack, - place = turtle.native.place, - drop = turtle.native.drop, - suck = turtle.native.suck, - compare = turtle.native.compare, - inspect = turtle.native.inspect, - side = 'front' - }, - back = { - detect = noop, - dig = noop, - move = turtle.native.back, - attack = noop, - place = noop, - suck = noop, - compare = noop, - side = 'back' - }, -} - -function turtle.getAction(direction) - return actions[direction] -end - -function turtle.getHeadingInfo(heading) - heading = heading or turtle.point.heading - return headings[heading] -end - -function turtle.isTurtleAtSide(side) - local sideType = peripheral.getType(side) - return sideType and sideType == 'turtle' -end - --- [[ Policies ]] -- -turtle.policies = { } - -function turtle.addPolicy(name, policy) - turtle.policies[name] = policy -end - -function turtle.getPolicy(policy) - if type(policy) == 'function' then - return policy - end - local p = turtle.policies[policy] - if not p then - error('Invalid policy: ' .. tostring(policy)) - end - return p -end - --- [[ Basic turtle actions ]] -- -local function inventoryAction(fn, name, qty) - local slots = turtle.getFilledSlots() - local s - for _,slot in pairs(slots) do - if slot.key == name or slot.name == name then - turtle.native.select(slot.index) - if not qty then - s = fn() - else - s = fn(math.min(qty, slot.count)) - qty = qty - slot.count - if qty < 0 then - break - end - end - end - end - if not s then - return false, 'No items found' - end - return s -end - --- [[ Attack ]] -- -local function _attack(action) - if action.attack() then - repeat until not action.attack() - return true - end - return false -end - -function turtle.attack() return _attack(actions.forward) end -function turtle.attackUp() return _attack(actions.up) end -function turtle.attackDown() return _attack(actions.down) end - -turtle.addPolicy('attackNone', noop) -turtle.addPolicy('attack', function(action) - return _attack(action) -end) - -function turtle.setAttackPolicy(policy) state.attackPolicy = policy end - --- [[ Place ]] -- -local function _place(action, indexOrId) - local slot - - if indexOrId then - slot = turtle.getSlot(indexOrId) - if not slot then - return false, 'No items to place' - end - end - - if slot and slot.count == 0 then - return false, 'No items to place' - end - - return Util.tryTimes(3, function() - if slot then - turtle.select(slot.index) - end - local result = { action.place() } - if result[1] then - return true - end - if not state.digPolicy(action) then - state.attackPolicy(action) - end - return table.unpack(result) - end) -end - -function turtle.place(slot) return _place(actions.forward, slot) end -function turtle.placeUp(slot) return _place(actions.up, slot) end -function turtle.placeDown(slot) return _place(actions.down, slot) end - --- [[ Drop ]] -- -local function _drop(action, qtyOrName, qty) - if not qtyOrName or type(qtyOrName) == 'number' then - return action.drop(qtyOrName or 64) - end - return inventoryAction(action.drop, qtyOrName, qty) -end - -function turtle.drop(count, slot) return _drop(actions.forward, count, slot) end -function turtle.dropUp(count, slot) return _drop(actions.up, count, slot) end -function turtle.dropDown(count, slot) return _drop(actions.down, count, slot) end - --- [[ Dig ]] -- -turtle.addPolicy('digNone', noop) - -turtle.addPolicy('dig', function(action) - return action.dig() -end) - -turtle.addPolicy('turtleSafe', function(action) - if action.side == 'back' then - return false - end - if not turtle.isTurtleAtSide(action.side) then - return action.dig() - end - return Util.tryTimes(6, function() - os.sleep(.25) - if not action.detect() then - return true - end - end) -end) - -local function isBlacklisted(b) - if b and state.blacklist then - for _, v in pairs(state.blacklist) do - if b.name:find(v) then - return true - end - end - end -end - -turtle.addPolicy('blacklist', function(action) - if action.side == 'back' then - return false - end - local s, m = action.inspect() - if not isBlacklisted(s and m) then - return action.dig() - end - if s and m and m.name:find('turtle') then - return Util.tryTimes(math.random(3, 6), function() - os.sleep(.25) - if not action.detect() then - return true - end - end) - end -end) - -turtle.addPolicy('digAndDrop', function(action) - if action.detect() then - local slots = turtle.getInventory() - if action.dig() then - turtle.reconcileInventory(slots) - return true - end - end - return false -end) - -function turtle.setDigPolicy(policy) state.digPolicy = policy end - --- [[ Move ]] -- -turtle.addPolicy('moveNone', noop) -turtle.addPolicy('moveDefault', _defaultMove) -turtle.addPolicy('moveAssured', function(action) - if not _defaultMove(action) then - if action.side == 'back' then - return false - end - local oldStatus = state.status - print('assured move: stuck') - state.status = 'stuck' - repeat - os.sleep(1) - until _defaultMove(action) - state.status = oldStatus - end - return true -end) - -function turtle.setMoveCallback(cb) state.moveCallback = cb end -function turtle.clearMoveCallback() state.moveCallback = noop end -function turtle.getMoveCallback() return state.moveCallback end - --- convenience method for setting multiple values -function turtle.set(args) - for k,v in pairs(args) do - - if k == 'attackPolicy' then - turtle.setAttackPolicy(turtle.getPolicy(v)) - - elseif k == 'digPolicy' then - turtle.setDigPolicy(turtle.getPolicy(v)) - - elseif k == 'movePolicy' then - state.movePolicy = turtle.getPolicy(v) - - elseif k == 'movementStrategy' then - turtle.setMovementStrategy(v) - - elseif k == 'pathingBox' then - turtle.setPathingBox(v) - - elseif k == 'point' then - turtle.setPoint(v) - - elseif k == 'moveCallback' then - turtle.setMoveCallback(v) - - elseif k == 'status' then - turtle.setStatus(v) - - elseif k == 'blacklist' then - state.blacklist = v - - elseif k == 'reference' then - state.reference = v - - else - error('Invalid turle.set: ' .. tostring(k)) - end - end -end - --- [[ Fuel ]] -- -if type(turtle.getFuelLevel()) ~= 'number' then - -- Support unlimited fuel - function turtle.getFuelLevel() - return 100000 - end -end - --- override to optionally specify a fuel -function turtle.refuel(qtyOrName, qty) - if not qtyOrName or type(qtyOrName) == 'number' then - return turtle.native.refuel(qtyOrName or 64) - end - return inventoryAction(turtle.native.refuel, qtyOrName, qty or 64) -end - --- [[ Heading ]] -- -function turtle.getHeading() - return turtle.point.heading -end - -function turtle.turnRight() - turtle.setHeading((turtle.point.heading + 1) % 4) - return turtle.point -end - -function turtle.turnLeft() - turtle.setHeading((turtle.point.heading - 1) % 4) - return turtle.point -end - -function turtle.turnAround() - turtle.setHeading((turtle.point.heading + 2) % 4) - return turtle.point -end - -function turtle.setHeading(heading) - if not heading then - return false, 'Invalid heading' - end - - if heading == turtle.point.heading then - return turtle.point - end - - local fi = Point.facings[heading] - if not fi then - return false, 'Invalid heading' - end - - heading = fi.heading % 4 - if heading ~= turtle.point.heading then - while heading < turtle.point.heading do - heading = heading + 4 - end - if heading - turtle.point.heading == 3 then - turtle.native.turnLeft() - turtle.point.heading = (turtle.point.heading - 1) % 4 - state.moveCallback('turn', turtle.point) - else - local turns = heading - turtle.point.heading - while turns > 0 do - turns = turns - 1 - turtle.native.turnRight() - turtle.point.heading = (turtle.point.heading + 1) % 4 - state.moveCallback('turn', turtle.point) - end - end - end - - return turtle.point -end - -function turtle.headTowardsX(dx) - if turtle.point.x ~= dx then - if turtle.point.x > dx then - turtle.setHeading(2) - else - turtle.setHeading(0) - end - end -end - -function turtle.headTowardsZ(dz) - if turtle.point.z ~= dz then - if turtle.point.z > dz then - turtle.setHeading(3) - else - turtle.setHeading(1) - end - end -end - -function turtle.headTowards(pt) - local xd = math.abs(turtle.point.x - pt.x) - local zd = math.abs(turtle.point.z - pt.z) - if xd > zd then - turtle.headTowardsX(pt.x) - else - turtle.headTowardsZ(pt.z) - end -end - --- [[ move ]] -- -function turtle.up() - if state.movePolicy(actions.up) then - turtle.point.y = turtle.point.y + 1 - state.moveCallback('up', turtle.point) - return true, turtle.point - end -end - -function turtle.down() - if state.movePolicy(actions.down) then - turtle.point.y = turtle.point.y - 1 - state.moveCallback('down', turtle.point) - return true, turtle.point - end -end - -function turtle.forward() - if state.movePolicy(actions.forward) then - turtle.point.x = turtle.point.x + headings[turtle.point.heading].xd - turtle.point.z = turtle.point.z + headings[turtle.point.heading].zd - state.moveCallback('forward', turtle.point) - return true, turtle.point - end -end - -function turtle.back() - if state.movePolicy(actions.back) then - turtle.point.x = turtle.point.x - headings[turtle.point.heading].xd - turtle.point.z = turtle.point.z - headings[turtle.point.heading].zd - state.moveCallback('back', turtle.point) - return true, turtle.point - end -end - -local function moveTowardsX(dx) - if not tonumber(dx) then error('moveTowardsX: Invalid arguments') end - local direction = dx - turtle.point.x - local move - - if direction == 0 then - return true - end - - if direction > 0 and turtle.point.heading == 0 or - direction < 0 and turtle.point.heading == 2 then - move = turtle.forward - else - move = turtle.back - end - - repeat - if not move() then - return false - end - until turtle.point.x == dx - return true -end - -local function moveTowardsZ(dz) - local direction = dz - turtle.point.z - local move - - if direction == 0 then - return true - end - - if direction > 0 and turtle.point.heading == 1 or - direction < 0 and turtle.point.heading == 3 then - move = turtle.forward - else - move = turtle.back - end - - repeat - if not move() then - return false - end - until turtle.point.z == dz - return true -end - --- [[ go ]] -- --- 1 turn goto (going backwards if possible) -function turtle.gotoSingleTurn(dx, dy, dz, dh) - dx = dx or turtle.point.x - dy = dy or turtle.point.y - dz = dz or turtle.point.z - - local function gx() - if turtle.point.x ~= dx then - moveTowardsX(dx) - end - if turtle.point.z ~= dz then - if dh and dh % 2 == 1 then - turtle.setHeading(dh) - else - turtle.headTowardsZ(dz) - end - end - end - - local function gz() - if turtle.point.z ~= dz then - moveTowardsZ(dz) - end - if turtle.point.x ~= dx then - if dh and dh % 2 == 0 then - turtle.setHeading(dh) - else - turtle.headTowardsX(dx) - end - end - end - - repeat - local x, z - local y = turtle.point.y - - repeat - x, z = turtle.point.x, turtle.point.z - - if turtle.point.heading % 2 == 0 then - gx() - gz() - else - gz() - gx() - end - until x == turtle.point.x and z == turtle.point.z - - if turtle.point.y ~= dy then - turtle.gotoY(dy) - end - - if turtle.point.x == dx and turtle.point.z == dz and turtle.point.y == dy then - return true - end - - until x == turtle.point.x and z == turtle.point.z and y == turtle.point.y - - return false -end - -local function gotoEx(dx, dy, dz) - -- determine the heading to ensure the least amount of turns - -- first check is 1 turn needed - remaining require 2 turns - if turtle.point.heading == 0 and turtle.point.x <= dx or - turtle.point.heading == 2 and turtle.point.x >= dx or - turtle.point.heading == 1 and turtle.point.z <= dz or - turtle.point.heading == 3 and turtle.point.z >= dz then - -- maintain current heading - -- nop - elseif dz > turtle.point.z and turtle.point.heading == 0 or - dz < turtle.point.z and turtle.point.heading == 2 or - dx < turtle.point.x and turtle.point.heading == 1 or - dx > turtle.point.x and turtle.point.heading == 3 then - turtle.turnRight() - else - turtle.turnLeft() - end - - if (turtle.point.heading % 2) == 1 then - if not turtle.gotoZ(dz) then return false end - if not turtle.gotoX(dx) then return false end - else - if not turtle.gotoX(dx) then return false end - if not turtle.gotoZ(dz) then return false end - end - - if dy then - if not turtle.gotoY(dy) then return false end - end - - return true -end - --- fallback goto - will turn around if was previously moving backwards -local function gotoMultiTurn(dx, dy, dz) - if gotoEx(dx, dy, dz) then - return true - end - - local moved - repeat - local x, y, z = turtle.point.x, turtle.point.y, turtle.point.z - - -- try going the other way - if (turtle.point.heading % 2) == 1 then - turtle.headTowardsX(dx) - else - turtle.headTowardsZ(dz) - end - - if gotoEx(dx, dy, dz) then - return true - end - - if dy then - turtle.gotoY(dy) - end - - moved = x ~= turtle.point.x or y ~= turtle.point.y or z ~= turtle.point.z - until not moved - - return false -end - --- go backwards - turning around if necessary to fight mobs / break blocks -function turtle.goback() - local hi = headings[turtle.point.heading] - return turtle.go({ - x = turtle.point.x - hi.xd, - y = turtle.point.y, - z = turtle.point.z - hi.zd, - heading = turtle.point.heading, - }) -end - -function turtle.gotoYfirst(pt) - if turtle.gotoY(pt.y) then - if turtle.go(pt) then - turtle.setHeading(pt.heading) - return true - end - end -end - -function turtle.go(pt) - if not pt.x and not pt.z and pt.y then - if turtle.gotoY(pt.y) then - turtle.setHeading(pt.heading) - return true - end - return false, 'Failed to reach location' - end - - local dx = pt.x or turtle.point.x - local dz = pt.z or turtle.point.z - local dy, dh = pt.y, pt.heading - if not turtle.gotoSingleTurn(dx, dy, dz, dh) then - if not gotoMultiTurn(dx, dy, dz) then - return false, 'Failed to reach location' - end - end - turtle.setHeading(dh) - return pt -end - --- avoid lint errors --- deprecated -turtle['goto'] = turtle.go -turtle['_goto'] = turtle.go - --- TODO: localize these goto functions -function turtle.gotoX(dx) - turtle.headTowardsX(dx) - - while turtle.point.x ~= dx do - if not turtle.forward() then - return false - end - end - return true -end - -function turtle.gotoZ(dz) - turtle.headTowardsZ(dz) - - while turtle.point.z ~= dz do - if not turtle.forward() then - return false - end - end - return true -end - -function turtle.gotoY(dy) - while turtle.point.y > dy do - if not turtle.down() then - return false - end - end - - while turtle.point.y < dy do - if not turtle.up() then - return false - end - end - return true -end - --- [[ Inventory ]] -- -function turtle.getSlot(indexOrId, slots) - if type(indexOrId) == 'string' then - slots = slots or turtle.getInventory() - local _,c = string.gsub(indexOrId, ':', '') - if c == 2 then -- combined id and dmg .. ie. minecraft:coal:0 - return Util.find(slots, 'key', indexOrId) - end - return Util.find(slots, 'name', indexOrId) - end - - local detail = turtle.getItemDetail(indexOrId) - if detail then - return { - name = detail.name, - damage = detail.damage, - count = detail.count, - key = detail.name .. ':' .. detail.damage, - - index = indexOrId, - - -- deprecate - qty = detail.count, - dmg = detail.damage, - id = detail.name, - } - end - - -- inconsistent return value - -- null is returned if indexOrId is a string and no item is present - return { - qty = 0, -- deprecate - count = 0, - index = indexOrId, - } -end - -function turtle.select(indexOrId) - if type(indexOrId) == 'number' then - return turtle.native.select(indexOrId) - end - - local s = turtle.getSlot(indexOrId) - if s then - turtle.native.select(s.index) - return s - end - - return false, 'Inventory does not contain item' -end - -function turtle.getInventory(slots) - slots = slots or { } - for i = 1, 16 do - slots[i] = turtle.getSlot(i) - end - return slots -end - -function turtle.getSummedInventory() - local slots = turtle.getFilledSlots() - local t = { } - for _,slot in pairs(slots) do - local entry = t[slot.key] - if not entry then - entry = { - count = 0, - damage = slot.damage, - name = slot.name, - key = slot.key, - - -- deprecate - qty = 0, - dmg = slot.dmg, - id = slot.id, - } - t[slot.key] = entry - end - entry.qty = entry.qty + slot.qty - entry.count = entry.qty - end - return t -end - -function turtle.has(item, count) - if item:match('.*:%d') then - local slot = turtle.getSummedInventory()[item] - return slot and slot.count >= (count or 1) - end - local slot = turtle.getSlot(item) - return slot and slot.count >= (count or 1) -end - -function turtle.getFilledSlots(startSlot) - startSlot = startSlot or 1 - - local slots = { } - for i = startSlot, 16 do - local count = turtle.getItemCount(i) - if count > 0 then - slots[i] = turtle.getSlot(i) - end - end - return slots -end - -function turtle.eachFilledSlot(fn) - local slots = turtle.getFilledSlots() - for _,slot in pairs(slots) do - fn(slot) - end -end - -function turtle.emptyInventory(dropAction) - dropAction = dropAction or turtle.native.drop - turtle.eachFilledSlot(function(slot) - turtle.select(slot.index) - dropAction() - end) - turtle.select(1) -end - -function turtle.reconcileInventory(slots, dropAction) - dropAction = dropAction or turtle.native.drop - for _,s in pairs(slots) do - local qty = turtle.getItemCount(s.index) - if qty > s.qty then - turtle.select(s.index) - dropAction(qty-s.qty, s) - end - end -end - -function turtle.selectSlotWithItems(startSlot) - startSlot = startSlot or 1 - for i = startSlot, 16 do - if turtle.getItemCount(i) > 0 then - turtle.select(i) - return i - end - end -end - -function turtle.selectSlotWithQuantity(qty, startSlot) - startSlot = startSlot or 1 - - for i = startSlot, 16 do - if turtle.getItemCount(i) == qty then - turtle.select(i) - return i - end - end -end - -function turtle.selectOpenSlot(startSlot) - return turtle.selectSlotWithQuantity(0, startSlot) -end - -function turtle.condense() - local slots = turtle.getInventory() - - for i = 1, 16 do - if slots[i].count < 64 then - for j = 16, i + 1, -1 do - if slots[j].count > 0 and (slots[i].count == 0 or slots[i].key == slots[j].key) then - turtle.select(j) - if turtle.transferTo(i) then - local transferred = turtle.getItemCount(i) - slots[i].count - slots[j].count = slots[j].count - transferred - slots[i].count = slots[i].count + transferred - slots[i].key = slots[j].key - if slots[j].count == 0 then - slots[j].key = nil - end - if slots[i].count == 64 then - break - end - else - break - end - end - end - end - end - turtle.select(1) - return true -end - -function turtle.getItemCount(idOrName) - if type(idOrName) == 'number' then - return turtle.native.getItemCount(idOrName) - end - local slots = turtle.getFilledSlots() - local count = 0 - for _,slot in pairs(slots) do - if slot.key == idOrName or slot.name == idOrName then - count = count + slot.count - end - end - return count -end - --- [[ Equipment ]] -- -function turtle.equip(side, item) - if item then - if not turtle.select(item) then - return false, 'Unable to equip ' .. item - end - end - - if side == 'left' then - return turtle.equipLeft() - end - return turtle.equipRight() -end - -function turtle.isEquipped(item) - if peripheral.getType('left') == item then - return 'left' - elseif peripheral.getType('right') == item then - return 'right' - end -end - -function turtle.unequip(side) - if not turtle.selectSlotWithQuantity(0) then - return false, 'No slots available' - end - return turtle.equip(side) -end - --- deprecate -function turtle.run(fn, ...) - local args = { ... } - local s, m - - if type(fn) == 'string' then - fn = turtle[fn] - end - - synchronized(turtle, function() - turtle.resetState() - s, m = pcall(function() fn(table.unpack(args)) end) - turtle.resetState() - if not s and m then - _G.printError(m) - end - end) - - return s, m -end - -function turtle.abort(abort) - state.abort = abort - if abort then - os.queueEvent('turtle_abort') - end -end - --- [[ Pathing ]] -- -function turtle.setPersistent(isPersistent) - if isPersistent then - Pathing.setBlocks({ }) - else - Pathing.setBlocks() - end -end - -function turtle.setPathingBox(box) - Pathing.setBox(box) -end - -function turtle.addWorldBlock(pt) - Pathing.addBlock(pt) -end - -function turtle.addWorldBlocks(pts) - Util.each(pts, function(pt) - Pathing.addBlock(pt) - end) -end - -local movementStrategy = turtle.pathfind - -function turtle.setMovementStrategy(strategy) - if strategy == 'pathing' then - movementStrategy = turtle.pathfind - elseif strategy == 'goto' then - movementStrategy = turtle.go - else - error('Invalid movement strategy') - end -end - -function turtle.faceAgainst(pt, options) -- 4 sided - options = options or { } - options.dest = { } - - for i = 0, 3 do - local hi = Point.facings[i] - table.insert(options.dest, { - x = pt.x + hi.xd, - z = pt.z + hi.zd, - y = pt.y + hi.yd, - heading = (hi.heading + 2) % 4, - }) - end - - return movementStrategy(Point.closest(turtle.point, options.dest), options) -end - --- move against this point --- if the point does not contain a heading, then the turtle --- will face the block (if on same plane) --- if above or below, the heading is undetermined unless specified -function turtle.moveAgainst(pt, options) -- 6 sided - options = options or { } - options.dest = { } - - for i = 0, 5 do - local hi = turtle.getHeadingInfo(i) - local heading, direction - if i < 4 then - heading = (hi.heading + 2) % 4 - direction = 'forward' - elseif i == 4 then - direction = 'down' - elseif i == 5 then - direction = 'up' - end - - table.insert(options.dest, { - x = pt.x + hi.xd, - z = pt.z + hi.zd, - y = pt.y + hi.yd, - direction = direction, - heading = pt.heading or heading, - }) - end - - return movementStrategy(Point.closest(turtle.point, options.dest), options) -end - -local actionsAt = { - detect = { - up = turtle.detectUp, - down = turtle.detectDown, - forward = turtle.detect, - }, - dig = { - up = turtle.digUp, - down = turtle.digDown, - forward = turtle.dig, - }, - move = { - up = turtle.moveUp, - down = turtle.moveDown, - forward = turtle.move, - }, - attack = { - up = turtle.attackUp, - down = turtle.attackDown, - forward = turtle.attack, - }, - place = { - up = turtle.placeUp, - down = turtle.placeDown, - forward = turtle.place, - }, - drop = { - up = turtle.dropUp, - down = turtle.dropDown, - forward = turtle.drop, - }, - suck = { - up = turtle.suckUp, - down = turtle.suckDown, - forward = turtle.suck, - }, - compare = { - up = turtle.compareUp, - down = turtle.compareDown, - forward = turtle.compare, - }, - inspect = { - up = turtle.inspectUp, - down = turtle.inspectDown, - forward = turtle.inspect, - }, -} - --- pt = { x,y,z,heading,direction } --- direction should only be up or down if provided --- heading can be provided to tell which way to face during action --- ex: place a block at the point from above facing east -local function _actionAt(action, pt, ...) - if not pt.heading and not pt.direction then - local msg - pt, msg = turtle.moveAgainst(pt) - if pt then - return action[pt.direction](...) - end - return pt, msg - end - - local reversed = - { [0] = 2, [1] = 3, [2] = 0, [3] = 1, [4] = 5, [5] = 4, } - local dir = reversed[headings[pt.direction or pt.heading].heading] - local apt = { x = pt.x + headings[dir].xd, - y = pt.y + headings[dir].yd, - z = pt.z + headings[dir].zd, } - local direction - - -- ex: place a block at this point, from above, facing east - if dir < 4 then - apt.heading = (dir + 2) % 4 - direction = 'forward' - elseif dir == 4 then - apt.heading = pt.heading - direction = 'down' - elseif dir == 5 then - apt.heading = pt.heading - direction = 'up' - end - - if movementStrategy(apt) then - return action[direction](...) - end -end - -local function _actionDownAt(action, pt, ...) - pt = Util.shallowCopy(pt) - pt.direction = Point.DOWN - return _actionAt(action, pt, ...) -end - -local function _actionUpAt(action, pt, ...) - pt = Util.shallowCopy(pt) - pt.direction = Point.UP - return _actionAt(action, pt, ...) -end - -local function _actionForwardAt(action, pt, ...) - if turtle.faceAgainst(pt) then - return action.forward(...) - end -end - -function turtle.detectAt(pt) return _actionAt(actionsAt.detect, pt) end -function turtle.detectDownAt(pt) return _actionDownAt(actionsAt.detect, pt) end -function turtle.detectForwardAt(pt) return _actionForwardAt(actionsAt.detect, pt) end -function turtle.detectUpAt(pt) return _actionUpAt(actionsAt.detect, pt) end - -function turtle.digAt(pt, ...) return _actionAt(actionsAt.dig, pt, ...) end -function turtle.digDownAt(pt, ...) return _actionDownAt(actionsAt.dig, pt, ...) end -function turtle.digForwardAt(pt, ...) return _actionForwardAt(actionsAt.dig, pt, ...) end -function turtle.digUpAt(pt, ...) return _actionUpAt(actionsAt.dig, pt, ...) end - -function turtle.attackAt(pt) return _actionAt(actionsAt.attack, pt) end -function turtle.attackDownAt(pt) return _actionDownAt(actionsAt.attack, pt) end -function turtle.attackForwardAt(pt) return _actionForwardAt(actionsAt.attack, pt) end -function turtle.attackUpAt(pt) return _actionUpAt(actionsAt.attack, pt) end - -function turtle.placeAt(pt, arg, dir) return _actionAt(actionsAt.place, pt, arg, dir) end -function turtle.placeDownAt(pt, arg) return _actionDownAt(actionsAt.place, pt, arg) end -function turtle.placeForwardAt(pt, arg) return _actionForwardAt(actionsAt.place, pt, arg) end -function turtle.placeUpAt(pt, arg) return _actionUpAt(actionsAt.place, pt, arg) end - -function turtle.dropAt(pt, ...) return _actionAt(actionsAt.drop, pt, ...) end -function turtle.dropDownAt(pt, ...) return _actionDownAt(actionsAt.drop, pt, ...) end -function turtle.dropForwardAt(pt, ...) return _actionForwardAt(actionsAt.drop, pt, ...) end -function turtle.dropUpAt(pt, ...) return _actionUpAt(actionsAt.drop, pt, ...) end - -function turtle.suckAt(pt, qty) return _actionAt(actionsAt.suck, pt, qty or 64) end -function turtle.suckDownAt(pt, qty) return _actionDownAt(actionsAt.suck, pt, qty or 64) end -function turtle.suckForwardAt(pt, qty) return _actionForwardAt(actionsAt.suck, pt, qty or 64) end -function turtle.suckUpAt(pt, qty) return _actionUpAt(actionsAt.suck, pt, qty or 64) end - -function turtle.compareAt(pt) return _actionAt(actionsAt.compare, pt) end -function turtle.compareDownAt(pt) return _actionDownAt(actionsAt.compare, pt) end -function turtle.compareForwardAt(pt) return _actionForwardAt(actionsAt.compare, pt) end -function turtle.compareUpAt(pt) return _actionUpAt(actionsAt.compare, pt) end - -function turtle.inspectAt(pt) return _actionAt(actionsAt.inspect, pt) end -function turtle.inspectDownAt(pt) return _actionDownAt(actionsAt.inspect, pt) end -function turtle.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspect, pt) end -function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end - -turtle.reset() diff --git a/sys/lzwfs.lua b/sys/lzwfs.lua new file mode 100644 index 0000000..ac2ddb8 --- /dev/null +++ b/sys/lzwfs.lua @@ -0,0 +1,247 @@ +-- see: https://github.com/Rochet2/lualzw +-- MIT License - Copyright (c) 2016 Rochet2 + +-- Transparent file system compression for non-binary files using lzw + +-- Files that are compressed will have the first bytes in file set to 'LZWC'. +-- If a file does not benefit from compression, the contents will not be altered. + +-- Allow exclusions for files that shouldn't be compressed +-- Also allow for future types of exclusions using bit operations +-- 1 is reserved for compression exclusion +-- fs.addException('startup.lua', 1) + +-- To renable compression for a file +-- fs.removeException('startup.lua', 1) + +-- Restores file system +-- fs.restore() + +local char = string.char +local type = type +local sub = string.sub +local tconcat = table.concat +local tinsert = table.insert + +local SIGC = 'LZWC' +local IGNORE_COMPRESSION = 1 -- support other bits as well + +local basedictcompress = {} +local basedictdecompress = {} +for i = 0, 255 do + local ic, iic = char(i), char(i, 0) + basedictcompress[ic] = iic + basedictdecompress[iic] = ic +end + +local native = { open = fs.open } +fs.exceptions = fs.exceptions or { } + +local function dictAddA(str, dict, a, b) + if a >= 256 then + a, b = 0, b+1 + if b >= 256 then + dict = {} + b = 1 + end + end + dict[str] = char(a,b) + a = a+1 + return dict, a, b +end + +local function compress(input) + if type(input) ~= "string" then + error ("string expected, got "..type(input)) + end + local len = #input + if len <= 1 then + return input + end + + local dict = {} + local a, b = 0, 1 + + local result = { SIGC } + local resultlen = 1 + local n = 2 + local word = "" + for i = 1, len do + local c = sub(input, i, i) + local wc = word..c + if not (basedictcompress[wc] or dict[wc]) then + local write = basedictcompress[word] or dict[word] + if not write then + error "algorithm error, could not fetch word" + end + result[n] = write + resultlen = resultlen + #write + n = n+1 + if len <= resultlen then + return input + end + dict, a, b = dictAddA(wc, dict, a, b) + word = c + else + word = wc + end + end + result[n] = basedictcompress[word] or dict[word] + resultlen = resultlen+#result[n] + if len <= resultlen then + return input + end + return tconcat(result) +end + +local function dictAddB(str, dict, a, b) + if a >= 256 then + a, b = 0, b+1 + if b >= 256 then + dict = {} + b = 1 + end + end + dict[char(a,b)] = str + a = a+1 + return dict, a, b +end + +local function decompress(input) + if type(input) ~= "string" then + error( "string expected, got "..type(input)) + end + + if #input <= 1 then + return input + end + + local control = sub(input, 1, 4) + if control ~= SIGC then + return input + end + input = sub(input, 5) + local len = #input + + if len < 2 then + error("invalid input - not a compressed string") + end + + local dict = {} + local a, b = 0, 1 + + local result = {} + local n = 1 + local last = sub(input, 1, 2) + result[n] = basedictdecompress[last] or dict[last] + n = n+1 + for i = 3, len, 2 do + local code = sub(input, i, i+1) + local lastStr = basedictdecompress[last] or dict[last] + if not lastStr then + error( "could not find last from dict. Invalid input?") + end + local toAdd = basedictdecompress[code] or dict[code] + if toAdd then + result[n] = toAdd + n = n+1 + dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) + else + local tmp = lastStr..sub(lastStr, 1, 1) + result[n] = tmp + n = n+1 + dict, a, b = dictAddB(tmp, dict, a, b) + end + last = code + end + return tconcat(result) +end + +function split(str, pattern) + pattern = pattern or "(.-)\n" + local t = {} + local function helper(line) tinsert(t, line) return "" end + helper((str:gsub(pattern, helper))) + return t +end + +function fs.open(fname, flags) + if flags == 'r' then + local f, err = native.open(fname, 'rb') + if not f then + return f, err + end + + local ctr = 0 + local lines + return { + readLine = function() + if not lines then + lines = split(decompress(f.readAll())) + end + ctr = ctr + 1 + return lines[ctr] + end, + readAll = function() + return decompress(f.readAll()) + end, + close = function() + f.close() + end, + } + elseif flags == 'w' or flags == 'a' then + if bit.band(fs.exceptions[fs.combine(fname, '')] or 0, IGNORE_COMPRESSION) == IGNORE_COMPRESSION then + return native.open(fname, flags) + end + + local c = { } + + if flags == 'a' then + local f = fs.open(fname, 'r') + if f then + tinsert(c, f.readAll()) + f.close() + end + end + + local f, err = native.open(fname, 'wb') + if not f then + return f, err + end + + return { + write = function(str) + tinsert(c, str) + end, + writeLine = function(str) + tinsert(c, str) + tinsert(c, '\n') + end, + flush = function() + -- this isn't gonna work... + // f.write(compress(tconcat(c))) + f.flush(); + end, + close = function() + f.write(compress(tconcat(c))) + f.close() + end, + } + end + + return native.open(fname, flags) +end + +function fs.addException(fname, mode) + fname = fs.combine(fname, '') + fs.exceptions[fname] = bit.bor(fs.exceptions[fname] or 0, mode) +end + +function fs.removeException(fname, mode) + fname = fs.combine(fname, '') + fs.exceptions[fname] = bit.bxor(fs.exceptions[fname] or 0, mode) +end + +function fs.restore() + fs.open = native.open +end diff --git a/sys/modules/opus/jumper/core/bheap.lua b/sys/modules/opus/jumper/core/bheap.lua deleted file mode 100644 index c58ce2f..0000000 --- a/sys/modules/opus/jumper/core/bheap.lua +++ /dev/null @@ -1,175 +0,0 @@ ---- A light implementation of Binary heaps data structure. --- While running a search, some search algorithms (Astar, Dijkstra, Jump Point Search) have to maintains --- a list of nodes called __open list__. Retrieve from this list the lowest cost node can be quite slow, --- as it normally requires to skim through the full set of nodes stored in this list. This becomes a real --- problem especially when dozens of nodes are being processed (on large maps). --- --- The current module implements a binary heap --- data structure, from which the search algorithm will instantiate an open list, and cache the nodes being --- examined during a search. As such, retrieving the lower-cost node is faster and globally makes the search end --- up quickly. --- --- This module is internally used by the library on purpose. --- It should normally not be used explicitely, yet it remains fully accessible. --- - ---[[ - Notes: - This lighter implementation of binary heaps, based on : - https://github.com/Yonaba/Binary-Heaps ---]] - -if (...) then - - -- Dependency - local Utils = require((...):gsub('%.bheap$','.utils')) - - -- Local reference - local floor = math.floor - - -- Default comparison function - local function f_min(a,b) return a < b end - - -- Percolates up - local function percolate_up(heap, index) - if index == 1 then return end - local pIndex - if index <= 1 then return end - if index%2 == 0 then - pIndex = index/2 - else pIndex = (index-1)/2 - end - if not heap._sort(heap._heap[pIndex], heap._heap[index]) then - heap._heap[pIndex], heap._heap[index] = - heap._heap[index], heap._heap[pIndex] - percolate_up(heap, pIndex) - end - end - - -- Percolates down - local function percolate_down(heap,index) - local lfIndex,rtIndex,minIndex - lfIndex = 2*index - rtIndex = lfIndex + 1 - if rtIndex > heap._size then - if lfIndex > heap._size then return - else minIndex = lfIndex end - else - if heap._sort(heap._heap[lfIndex],heap._heap[rtIndex]) then - minIndex = lfIndex - else - minIndex = rtIndex - end - end - if not heap._sort(heap._heap[index],heap._heap[minIndex]) then - heap._heap[index],heap._heap[minIndex] = heap._heap[minIndex],heap._heap[index] - percolate_down(heap,minIndex) - end - end - - -- Produces a new heap - local function newHeap(template,comp) - return setmetatable({_heap = {}, - _sort = comp or f_min, _size = 0}, - template) - end - - - --- The `heap` class.
- -- This class is callable. - -- _Therefore,_ heap(...) _is used to instantiate new heaps_. - -- @type heap - local heap = setmetatable({}, - {__call = function(self,...) - return newHeap(self,...) - end}) - heap.__index = heap - - --- Checks if a `heap` is empty - -- @class function - -- @treturn bool __true__ of no item is queued in the heap, __false__ otherwise - -- @usage - -- if myHeap:empty() then - -- print('Heap is empty!') - -- end - function heap:empty() - return (self._size==0) - end - - --- Clears the `heap` (removes all items queued in the heap) - -- @class function - -- @treturn heap self (the calling `heap` itself, can be chained) - -- @usage myHeap:clear() - function heap:clear() - self._heap = {} - self._size = 0 - self._sort = self._sort or f_min - return self - end - - --- Adds a new item in the `heap` - -- @class function - -- @tparam value item a new value to be queued in the heap - -- @treturn heap self (the calling `heap` itself, can be chained) - -- @usage - -- myHeap:push(1) - -- -- or, with chaining - -- myHeap:push(1):push(2):push(4) - function heap:push(item) - if item then - self._size = self._size + 1 - self._heap[self._size] = item - percolate_up(self, self._size) - end - return self - end - - --- Pops from the `heap`. - -- Removes and returns the lowest cost item (with respect to the comparison function being used) from the `heap`. - -- @class function - -- @treturn value a value previously pushed into the heap - -- @usage - -- while not myHeap:empty() do - -- local lowestValue = myHeap:pop() - -- ... - -- end - function heap:pop() - local root - if self._size > 0 then - root = self._heap[1] - self._heap[1] = self._heap[self._size] - self._heap[self._size] = nil - self._size = self._size-1 - if self._size>1 then - percolate_down(self, 1) - end - end - return root - end - - --- Restores the `heap` property. - -- Reorders the `heap` with respect to the comparison function being used. - -- When given argument __item__ (a value existing in the `heap`), will sort from that very item in the `heap`. - -- Otherwise, the whole `heap` will be cheacked. - -- @class function - -- @tparam[opt] value item the modified value - -- @treturn heap self (the calling `heap` itself, can be chained) - -- @usage myHeap:heapify() - function heap:heapify(item) - if self._size == 0 then return end - if item then - local i = Utils.indexOf(self._heap,item) - if i then - percolate_down(self, i) - percolate_up(self, i) - end - return - end - for i = floor(self._size/2),1,-1 do - percolate_down(self,i) - end - return self - end - - return heap -end \ No newline at end of file diff --git a/sys/modules/opus/jumper/core/node.lua b/sys/modules/opus/jumper/core/node.lua deleted file mode 100644 index 09d1db4..0000000 --- a/sys/modules/opus/jumper/core/node.lua +++ /dev/null @@ -1,41 +0,0 @@ ---- The Node class. --- The `node` represents a cell (or a tile) on a collision map. Basically, for each single cell (tile) --- in the collision map passed-in upon initialization, a `node` object will be generated --- and then cached within the `grid`. --- --- In the following implementation, nodes can be compared using the `<` operator. The comparison is --- made with regards of their `f` cost. From a given node being examined, the `pathfinder` will expand the search --- to the next neighbouring node having the lowest `f` cost. See `core.bheap` for more details. --- -if (...) then - - local Node = {} - Node.__index = Node - - function Node:new(x,y,z) - return setmetatable({x = x, y = y, z = z }, Node) - end - - -- Enables the use of operator '<' to compare nodes. - -- Will be used to sort a collection of nodes in a binary heap on the basis of their F-cost - function Node.__lt(A,B) return (A._f < B._f) end - - function Node:getX() return self.x end - function Node:getY() return self.y end - function Node:getZ() return self.z end - - --- Clears temporary cached attributes of a `node`. - -- Deletes the attributes cached within a given node after a pathfinding call. - -- This function is internally used by the search algorithms, so you should not use it explicitely. - function Node:reset() - self._g, self._h, self._f = nil, nil, nil - self._opened, self._closed, self._parent = nil, nil, nil - return self - end - - return setmetatable(Node, - {__call = function(_,...) - return Node:new(...) - end} - ) -end \ No newline at end of file diff --git a/sys/modules/opus/jumper/core/path.lua b/sys/modules/opus/jumper/core/path.lua deleted file mode 100644 index f02c41b..0000000 --- a/sys/modules/opus/jumper/core/path.lua +++ /dev/null @@ -1,67 +0,0 @@ ---- The Path class. --- The `path` class is a structure which represents a path (ordered set of nodes) from a start location to a goal. --- An instance from this class would be a result of a request addressed to `Pathfinder:getPath`. --- --- This module is internally used by the library on purpose. --- It should normally not be used explicitely, yet it remains fully accessible. --- - -if (...) then - - local t_remove = table.remove - - local Path = {} - Path.__index = Path - - function Path:new() - return setmetatable({_nodes = {}}, Path) - end - - --- Iterates on each single `node` along a `path`. At each step of iteration, - -- returns the `node` plus a count value. Aliased as @{Path:nodes} - -- @usage - -- for node, count in p:iter() do - -- ... - -- end - function Path:nodes() - local i = 1 - return function() - if self._nodes[i] then - i = i+1 - return self._nodes[i-1],i-1 - end - end - end - - --- `Path` compression modifier. Given a `path`, eliminates useless nodes to return a lighter `path` - -- consisting of straight moves. Does the opposite of @{Path:fill} - -- @class function - -- @treturn path self (the calling `path` itself, can be chained) - -- @see Path:fill - -- @usage p:filter() - function Path:filter() - local i = 2 - local xi,yi,zi,dx,dy,dz, olddx, olddy, olddz - xi,yi,zi = self._nodes[i].x, self._nodes[i].y, self._nodes[i].z - dx, dy,dz = xi - self._nodes[i-1].x, yi-self._nodes[i-1].y, zi-self._nodes[i-1].z - while true do - olddx, olddy, olddz = dx, dy, dz - if self._nodes[i+1] then - i = i+1 - xi, yi, zi = self._nodes[i].x, self._nodes[i].y, self._nodes[i].z - dx, dy, dz = xi - self._nodes[i-1].x, yi - self._nodes[i-1].y, zi - self._nodes[i-1].z - if olddx == dx and olddy == dy and olddz == dz then - t_remove(self._nodes, i-1) - i = i - 1 - end - else break end - end - return self - end - - return setmetatable(Path, - {__call = function(_,...) - return Path:new(...) - end - }) -end \ No newline at end of file diff --git a/sys/modules/opus/jumper/core/utils.lua b/sys/modules/opus/jumper/core/utils.lua deleted file mode 100644 index ab5f764..0000000 --- a/sys/modules/opus/jumper/core/utils.lua +++ /dev/null @@ -1,57 +0,0 @@ --- Various utilities for Jumper top-level modules - -if (...) then - - -- Dependencies - local _PATH = (...):gsub('%.utils$','') - local Path = require (_PATH .. '.path') - - -- Local references - local pairs = pairs - local t_insert = table.insert - - -- Raw array items count - local function arraySize(t) - local count = 0 - for _ in pairs(t) do - count = count+1 - end - return count - end - - -- Extract a path from a given start/end position - local function traceBackPath(finder, node, startNode) - local path = Path:new() - path._grid = finder._grid - while true do - if node._parent then - t_insert(path._nodes,1,node) - node = node._parent - else - t_insert(path._nodes,1,startNode) - return path - end - end - end - - -- Lookup for value in a table - local indexOf = function(t,v) - for i = 1,#t do - if t[i] == v then return i end - end - return nil - end - - -- Is i out of range - local function outOfRange(i,low,up) - return (i< low or i > up) - end - - return { - arraySize = arraySize, - indexOf = indexOf, - outOfRange = outOfRange, - traceBackPath = traceBackPath - } - -end diff --git a/sys/modules/opus/jumper/grid.lua b/sys/modules/opus/jumper/grid.lua deleted file mode 100644 index 6cfc53a..0000000 --- a/sys/modules/opus/jumper/grid.lua +++ /dev/null @@ -1,101 +0,0 @@ ---- The Grid class. --- Implementation of the `grid` class. --- The `grid` is a implicit graph which represents the 2D --- world map layout on which the `pathfinder` object will run. --- During a search, the `pathfinder` object needs to save some critical values. --- These values are cached within each `node` --- object, and the whole set of nodes are tight inside the `grid` object itself. - -if (...) then - - -- Dependencies - local _PATH = (...):gsub('%.grid$','') - - -- Local references - local Utils = require (_PATH .. '.core.utils') - local Node = require (_PATH .. '.core.node') - - -- Local references - local setmetatable = setmetatable - - -- Offsets for straights moves - local straightOffsets = { - {x = 1, y = 0, z = 0} --[[W]], {x = -1, y = 0, z = 0}, --[[E]] - {x = 0, y = 1, z = 0} --[[S]], {x = 0, y = -1, z = 0}, --[[N]] - {x = 0, y = 0, z = 1} --[[U]], {x = 0, y = -0, z = -1}, --[[D]] - } - - local Grid = {} - Grid.__index = Grid - - function Grid:new(dim) - local newGrid = { } - newGrid._min_x, newGrid._max_x = dim.x, dim.ex - newGrid._min_y, newGrid._max_y = dim.y, dim.ey - newGrid._min_z, newGrid._max_z = dim.z, dim.ez - newGrid._nodes = { } - newGrid._width = (newGrid._max_x-newGrid._min_x)+1 - newGrid._height = (newGrid._max_y-newGrid._min_y)+1 - newGrid._length = (newGrid._max_z-newGrid._min_z)+1 - return setmetatable(newGrid,Grid) - end - - function Grid:isWalkableAt(x, y, z) - local node = self:getNodeAt(x,y,z) - return node and node.walkable ~= 1 - end - - function Grid:getWidth() - return self._width - end - - function Grid:getHeight() - return self._height - end - - function Grid:getNodes() - return self._nodes - end - - function Grid:getBounds() - return self._min_x, self._min_y, self._min_z, self._max_x, self._max_y, self._max_z - end - - --- Returns neighbours. The returned value is an array of __walkable__ nodes neighbouring a given `node`. - -- @treturn {node,...} an array of nodes neighbouring a given node - function Grid:getNeighbours(node) - local neighbours = {} - for i = 1,#straightOffsets do - local n = self:getNodeAt( - node.x + straightOffsets[i].x, - node.y + straightOffsets[i].y, - node.z + straightOffsets[i].z - ) - if n and self:isWalkableAt(n.x, n.y, n.z) then - neighbours[#neighbours+1] = n - end - end - - return neighbours - end - - function Grid:getNodeAt(x,y,z) - if not x or not y or not z then return end - if Utils.outOfRange(x,self._min_x,self._max_x) then return end - if Utils.outOfRange(y,self._min_y,self._max_y) then return end - if Utils.outOfRange(z,self._min_z,self._max_z) then return end - - -- inefficient - if not self._nodes[y] then self._nodes[y] = {} end - if not self._nodes[y][x] then self._nodes[y][x] = {} end - if not self._nodes[y][x][z] then self._nodes[y][x][z] = Node:new(x,y,z) end - return self._nodes[y][x][z] - end - - return setmetatable(Grid,{ - __call = function(self,...) - return self:new(...) - end - }) - -end diff --git a/sys/modules/opus/jumper/pathfinder.lua b/sys/modules/opus/jumper/pathfinder.lua deleted file mode 100644 index 0ff2844..0000000 --- a/sys/modules/opus/jumper/pathfinder.lua +++ /dev/null @@ -1,104 +0,0 @@ ---[[ - The following License applies to all files within the jumper directory. - - Note that this is only a partial copy of the full jumper code base. Also, - the code was modified to support 3D maps. ---]] - ---[[ -This work is under MIT-LICENSE -Copyright (c) 2012-2013 Roland Yonaba. - --- https://opensource.org/licenses/MIT - ---]] - -local _VERSION = "" -local _RELEASEDATE = "" - -if (...) then - - -- Dependencies - local _PATH = (...):gsub('%.pathfinder$','') - local Utils = require (_PATH .. '.core.utils') - - -- Internalization - local pairs = pairs - local assert = assert - local setmetatable = setmetatable - - --- Finders (search algorithms implemented). Refers to the search algorithms actually implemented in Jumper. - --
  • [A*](http://en.wikipedia.org/wiki/A*_search_algorithm)
  • - local Finders = { - ['ASTAR'] = require (_PATH .. '.search.astar'), - } - - -- Will keep track of all nodes expanded during the search - -- to easily reset their properties for the next pathfinding call - local toClear = {} - - -- Performs a traceback from the goal node to the start node - -- Only happens when the path was found - - local Pathfinder = {} - Pathfinder.__index = Pathfinder - - function Pathfinder:new(heuristic) - local newPathfinder = {} - setmetatable(newPathfinder, Pathfinder) - self._finder = Finders.ASTAR - self._heuristic = heuristic - return newPathfinder - end - - function Pathfinder:setGrid(grid) - self._grid = grid - return self - end - - --- Calculates a `path`. Returns the `path` from start to end location - -- Both locations must exist on the collision map. The starting location can be unwalkable. - -- @treturn path a path (array of nodes) when found, otherwise nil - -- @usage local path = myFinder:getPath(1,1,5,5) - function Pathfinder:getPath(startX, startY, startZ, ih, endX, endY, endZ, oh) - self:reset() - local startNode = self._grid:getNodeAt(startX, startY, startZ) - local endNode = self._grid:getNodeAt(endX, endY, endZ) - if not startNode or not endNode then - return nil - end - - startNode.heading = ih - endNode.heading = oh - - assert(startNode, ('Invalid location [%d, %d, %d]'):format(startX, startY, startZ)) - assert(endNode and self._grid:isWalkableAt(endX, endY, endZ), - ('Invalid or unreachable location [%d, %d, %d]'):format(endX, endY, endZ)) - local _endNode = self._finder(self, startNode, endNode, toClear) - if _endNode then - return Utils.traceBackPath(self, _endNode, startNode) - end - return nil - end - - --- Resets the `pathfinder`. This function is called internally between - -- successive pathfinding calls, so you should not - -- use it explicitely, unless under specific circumstances. - -- @class function - -- @treturn pathfinder self (the calling `pathfinder` itself, can be chained) - -- @usage local path, len = myFinder:getPath(1,1,5,5) - function Pathfinder:reset() - for node in pairs(toClear) do node:reset() end - toClear = {} - return self - end - - -- Returns Pathfinder class - Pathfinder._VERSION = _VERSION - Pathfinder._RELEASEDATE = _RELEASEDATE - return setmetatable(Pathfinder,{ - __call = function(self,...) - return self:new(...) - end - }) -end diff --git a/sys/modules/opus/jumper/search/astar.lua b/sys/modules/opus/jumper/search/astar.lua deleted file mode 100644 index c92dabc..0000000 --- a/sys/modules/opus/jumper/search/astar.lua +++ /dev/null @@ -1,77 +0,0 @@ --- Astar algorithm --- This actual implementation of A-star is based on --- [Nash A. & al. pseudocode](http://aigamedev.com/open/tutorials/theta-star-any-angle-paths/) - -if (...) then - - -- Internalization - local huge = math.huge - - -- Dependancies - local _PATH = (...):match('(.+)%.search.astar$') - local Heap = require (_PATH.. '.core.bheap') - - -- Updates G-cost - local function computeCost(node, neighbour, heuristic) - local mCost, heading = heuristic(neighbour, node) -- Heuristics.EUCLIDIAN(neighbour, node) - - if node._g + mCost < neighbour._g then - neighbour._parent = node - neighbour._g = node._g + mCost - neighbour.heading = heading - end - end - - -- Updates vertex node-neighbour - local function updateVertex(openList, node, neighbour, endNode, heuristic) - local oldG = neighbour._g - computeCost(node, neighbour, heuristic) - if neighbour._g < oldG then - if neighbour._opened then neighbour._opened = false end - neighbour._h = heuristic(endNode, neighbour) - neighbour._f = neighbour._g + neighbour._h - openList:push(neighbour) - neighbour._opened = true - end - end - - -- Calculates a path. - -- Returns the path from location `` to location ``. - return function (finder, startNode, endNode, toClear) - local openList = Heap() - startNode._g = 0 - startNode._h = finder._heuristic(endNode, startNode) - startNode._f = startNode._g + startNode._h - openList:push(startNode) - toClear[startNode] = true - startNode._opened = true - - while not openList:empty() do - local node = openList:pop() - node._closed = true - if node == endNode then return node end - local neighbours = finder._grid:getNeighbours(node) - for i = 1,#neighbours do - local neighbour = neighbours[i] - if not neighbour._closed then - toClear[neighbour] = true - if not neighbour._opened then - neighbour._g = huge - neighbour._parent = nil - end - updateVertex(openList, node, neighbour, endNode, finder._heuristic) - end - end - - --[[ - printf('x:%d y:%d z:%d g:%d', node.x, node.y, node.z, node._g) - for i = 1,#neighbours do - local n = neighbours[i] - printf('x:%d y:%d z:%d f:%f g:%f h:%d', n.x, n.y, n.z, n._f, n._g, n.heading or -1) - end - --]] - - end - return nil - end -end diff --git a/sys/modules/opus/packages.lua b/sys/modules/opus/packages.lua index 0c5187a..8b0f5e1 100644 --- a/sys/modules/opus/packages.lua +++ b/sys/modules/opus/packages.lua @@ -20,6 +20,29 @@ function Packages:installed() return list end +function Packages:installedSorted() + local list = { } + + for k, v in pairs(self.installed()) do + v.name = k + v.deps = { } + table.insert(list, v) + for _, v2 in pairs(v.required or { }) do + v.deps[v2] = true + end + end + + table.sort(list, function(a, b) + return not not (b.deps and b.deps[a.name]) + end) + + table.sort(list, function(a, b) + return not (a.deps and a.deps[b.name]) + end) + + return list +end + function Packages:list() if not fs.exists('usr/config/packages') then self:downloadList() diff --git a/sys/modules/opus/pathfind.lua b/sys/modules/opus/pathfind.lua deleted file mode 100644 index 06c12f1..0000000 --- a/sys/modules/opus/pathfind.lua +++ /dev/null @@ -1,256 +0,0 @@ -local Grid = require('opus.jumper.grid') -local Pathfinder = require('opus.jumper.pathfinder') -local Point = require('opus.point') -local Util = require('opus.util') - -local turtle = _G.turtle - -local function addBlock(grid, b, dim) - if Point.inBox(b, dim) then - local node = grid:getNodeAt(b.x, b.y, b.z) - if node then - node.walkable = 1 - end - end -end - --- map shrinks/grows depending upon blocks encountered --- the map will encompass any blocks encountered, the turtle position, and the destination -local function mapDimensions(dest, blocks, boundingBox, dests) - local box = Point.makeBox(turtle.point, turtle.point) - - Point.expandBox(box, dest) - - for _,d in pairs(dests) do - Point.expandBox(box, d) - end - - for _,b in pairs(blocks) do - Point.expandBox(box, b) - end - - -- expand one block out in all directions - if boundingBox then - box.x = math.max(box.x - 1, boundingBox.x) - box.z = math.max(box.z - 1, boundingBox.z) - box.y = math.max(box.y - 1, boundingBox.y) - box.ex = math.min(box.ex + 1, boundingBox.ex) - box.ez = math.min(box.ez + 1, boundingBox.ez) - box.ey = math.min(box.ey + 1, boundingBox.ey) - else - box.x = box.x - 1 - box.z = box.z - 1 - box.y = box.y - 1 - box.ex = box.ex + 1 - box.ez = box.ez + 1 - box.ey = box.ey + 1 - end - - return box -end - -local function nodeToPoint(node) - return { x = node.x, y = node.y, z = node.z, heading = node.heading } -end - -local function heuristic(n, node) - return Point.calculateMoves(node, n) --- { x = node.x, y = node.y, z = node.z, heading = node.heading }, --- { x = n.x, y = n.y, z = n.z, heading = n.heading }) -end - -local function dimsAreEqual(d1, d2) - return d1.ex == d2.ex and - d1.ey == d2.ey and - d1.ez == d2.ez and - d1.x == d2.x and - d1.y == d2.y and - d1.z == d2.z -end - --- turtle sensor returns blocks in relation to the world - not turtle orientation --- so cannot figure out block location unless we know our orientation in the world --- really kinda dumb since it returns the coordinates as offsets of our location --- instead of true coordinates -local function addSensorBlocks(blocks, sblocks) - for _,b in pairs(sblocks) do - if b.type ~= 'AIR' then - local pt = { x = turtle.point.x, y = turtle.point.y + b.y, z = turtle.point.z } - pt.x = pt.x - b.x - pt.z = pt.z - b.z -- this will only work if we were originally facing west - local found = false - for _,ob in pairs(blocks) do - if pt.x == ob.x and pt.y == ob.y and pt.z == ob.z then - found = true - break - end - end - if not found then - table.insert(blocks, pt) - end - end - end -end - -local function selectDestination(pts, box, grid) - while #pts > 0 do - local pt = Point.closest(turtle.point, pts) - if box and not Point.inBox(pt, box) then - Util.removeByValue(pts, pt) - else - if grid:isWalkableAt(pt.x, pt.y, pt.z) then - return pt - end - Util.removeByValue(pts, pt) - end - end -end - -local function updateCanvas(path) - local t = { } - for node in path:nodes() do - table.insert(t, { x = node.x, y = node.y, z = node.z }) - end - os.queueEvent('canvas', { - type = 'canvas_path', - data = t, - }) -end - -local function pathTo(dest, options) - local blocks = options.blocks or turtle.getState().blocks or { } - local dests = options.dest or { dest } -- support alternative destinations - local box = options.box or turtle.getState().box - local lastDim - local grid - - if box then - box = Point.normalizeBox(box) - end - - -- Creates a pathfinder object - local finder = Pathfinder(heuristic) - - while turtle.point.x ~= dest.x or turtle.point.z ~= dest.z or turtle.point.y ~= dest.y do - - -- map expands as we encounter obstacles - local dim = mapDimensions(dest, blocks, box, dests) - - -- reuse map if possible - if not lastDim or not dimsAreEqual(dim, lastDim) then - -- Creates a grid object - grid = Grid(dim) - finder:setGrid(grid) - - lastDim = dim - end - for _,b in pairs(blocks) do - addBlock(grid, b, dim) - end - - dest = selectDestination(dests, box, grid) - if not dest then - return false, 'failed to reach destination' - end - if turtle.point.x == dest.x and turtle.point.z == dest.z and turtle.point.y == dest.y then - break - end - - -- Define start and goal locations coordinates - local startPt = turtle.point - - -- Calculates the path, and its length - local path = finder:getPath( - startPt.x, startPt.y, startPt.z, turtle.point.heading, - dest.x, dest.y, dest.z, dest.heading) - - if not path then - Util.removeByValue(dests, dest) - else - updateCanvas(path) - - path:filter() - - for node in path:nodes() do - local pt = nodeToPoint(node) - - if turtle.isAborted() then - return false, 'aborted' - end - ---if this is the next to last node ---and we are traveling up or down, then the ---heading for this node should be the heading of the last node ---or, maybe.. ---if last node is up or down (or either?) - - -- use single turn method so the turtle doesn't turn around - -- when encountering obstacles - --if not turtle.gotoSingleTurn(pt.x, pt.y, pt.z, pt.heading) then - pt.heading = nil - if not turtle.go(pt) then - local bpt = Point.nearestTo(turtle.point, pt) - - if turtle.getFuelLevel() == 0 then - return false, 'Out of fuel' - end - table.insert(blocks, bpt) - os.queueEvent('canvas', { - type = 'canvas_barrier', - data = { bpt }, - }) - -- really need to check if the block we ran into was a turtle. - -- if so, this block should be temporary (1-2 secs) - - --local side = turtle.getSide(turtle.point, pt) - --if turtle.isTurtleAtSide(side) then - -- pt.timestamp = os.clock() + ? - --end - -- if dim has not changed, then need to update grid with - -- walkable = nil (after time has elapsed) - - --if device.turtlesensorenvironment then - -- addSensorBlocks(blocks, device.turtlesensorenvironment.sonicScan()) - --end - break - end - end - end - end - - if dest.heading then - turtle.setHeading(dest.heading) - end - return dest -end - -return { - pathfind = function(dest, options) - options = options or { } - --if not options.blocks and turtle.gotoPoint(dest) then - -- return dest - --end - return pathTo(dest, options) - end, - - -- set a global bounding box - -- box can be overridden by passing box in pathfind options - setBox = function(box) - turtle.getState().box = box - end, - - setBlocks = function(blocks) - turtle.getState().blocks = blocks - end, - - addBlock = function(block) - if turtle.getState().blocks then - table.insert(turtle.getState().blocks, block) - end - end, - - reset = function() - turtle.getState().box = nil - turtle.getState().blocks = nil - end, -} From aaab059cee6647668aedee9dd690306fc0ae30c5 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 1 Nov 2019 16:35:58 -0600 Subject: [PATCH 219/231] prepare for lock screen --- sys/init/7.multishell.lua | 3 ++- sys/kernel.lua | 4 ++++ sys/modules/opus/ui/tween.lua | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sys/init/7.multishell.lua b/sys/init/7.multishell.lua index b6ada5d..d8b722a 100644 --- a/sys/init/7.multishell.lua +++ b/sys/init/7.multishell.lua @@ -264,7 +264,7 @@ kernel.hook('multishell_redraw', function() write(currentTab.sx - 1, ' ' .. currentTab.title:sub(1, currentTab.width - 1) .. ' ', _colors.focusBackgroundColor, _colors.focusTextColor) - if not currentTab.isOverview then + if not currentTab.noTerminate then write(w, closeInd, _colors.backgroundColor, _colors.focusTextColor) end end @@ -340,6 +340,7 @@ kernel.hook('kernel_ready', function() overviewId = multishell.openTab({ path = config.launcher or 'sys/apps/Overview.lua', isOverview = true, + noTerminate = true, focused = true, title = '+', env = env, diff --git a/sys/kernel.lua b/sys/kernel.lua index 62ab6bc..a817d23 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -179,6 +179,10 @@ function kernel.run(args) end function kernel.raise(uid) + if kernel.getFocused() and kernel.getFocused().pinned then + return false + end + local routine = Util.find(kernel.routines, 'uid', uid) if routine then diff --git a/sys/modules/opus/ui/tween.lua b/sys/modules/opus/ui/tween.lua index 7d0a13c..22601de 100644 --- a/sys/modules/opus/ui/tween.lua +++ b/sys/modules/opus/ui/tween.lua @@ -7,7 +7,7 @@ local tween = { Copyright (c) 2014 Enrique GarcĂ­a Cota, Yuichi Tateno, Emmanuel Oga - Licence details: https://opensource.org/licenses/MIT + license details: https://opensource.org/licenses/MIT ]] } From 5c35a8383e06719f7b3559df962bce5b699c8cac Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 1 Nov 2019 22:37:08 -0600 Subject: [PATCH 220/231] lock computer --- startup.lua | 31 +++++++++++++++++-------------- sys/init/2.vfs.lua | 10 +++++----- sys/lzwfs.lua | 9 ++++++--- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/startup.lua b/startup.lua index 0cfcd7f..b6381d1 100644 --- a/startup.lua +++ b/startup.lua @@ -13,10 +13,13 @@ description: array of menu entries (see .startup.boot for examples) ]] -local colors = _G.colors -local os = _G.os -local settings = _G.settings -local term = _G.term +local colors = _G.colors +local fs = _G.fs +local keys = _G.keys +local os = _G.os +local settings = _G.settings +local term = _G.term +local textutils = _G.textutils local function loadBootOptions() if not fs.exists('.startup.boot') then @@ -87,19 +90,19 @@ local function startupMenu() if key == keys.enter or key == keys.right then return selected - elseif key == keys.down then - if selected == #bootOptions.menu then - selected = 0 + elseif key == keys.down then + if selected == #bootOptions.menu then + selected = 0 end selected = selected + 1 - elseif key == keys.up then - if selected == 1 then - selected = #bootOptions.menu + 1 + elseif key == keys.up then + if selected == 1 then + selected = #bootOptions.menu + 1 end selected = selected - 1 elseif event == 'char' then key = tonumber(key) or 0 - if bootOptions.menu[key] then + if bootOptions.menu[key] then return key end end @@ -145,13 +148,13 @@ local function splash() term.write(str) end -term.clear() -splash() - for _, v in pairs(bootOptions.preload) do os.run(_ENV, v) end +term.clear() +splash() + local timerId = os.startTimer(bootOptions.delay) while true do local e, id = os.pullEvent() diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index 0ddc672..62f5b4d 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -1,3 +1,5 @@ +local fs = _G.fs + if fs.native then return end @@ -7,8 +9,6 @@ local Util = require('opus.util') -- TODO: support getDrive for virtual nodes -local fs = _G.fs - fs.native = Util.shallowCopy(fs) local fstypes = { } @@ -16,7 +16,7 @@ local nativefs = { } for k,fn in pairs(fs) do if type(fn) == 'function' then - nativefs[k] = function(node, ...) + nativefs[k] = function(_, ...) return fn(...) end end @@ -340,8 +340,8 @@ function fs.unmount(path) end end -function fs.registerType(name, fs) - fstypes[name] = fs +function fs.registerType(name, vfs) + fstypes[name] = vfs end function fs.getTypes() diff --git a/sys/lzwfs.lua b/sys/lzwfs.lua index ac2ddb8..c1e9088 100644 --- a/sys/lzwfs.lua +++ b/sys/lzwfs.lua @@ -11,7 +11,7 @@ -- 1 is reserved for compression exclusion -- fs.addException('startup.lua', 1) --- To renable compression for a file +-- To renable compression for a file -- fs.removeException('startup.lua', 1) -- Restores file system @@ -23,6 +23,9 @@ local sub = string.sub local tconcat = table.concat local tinsert = table.insert +local bit = _G.bit +local fs = _G.fs + local SIGC = 'LZWC' local IGNORE_COMPRESSION = 1 -- support other bits as well @@ -157,7 +160,7 @@ local function decompress(input) return tconcat(result) end -function split(str, pattern) +local function split(str, pattern) pattern = pattern or "(.-)\n" local t = {} local function helper(line) tinsert(t, line) return "" end @@ -219,7 +222,7 @@ function fs.open(fname, flags) end, flush = function() -- this isn't gonna work... - // f.write(compress(tconcat(c))) + -- f.write(compress(tconcat(c))) f.flush(); end, close = function() From fba2d48a4b9d5134e794ec04a1de2d45529b4a28 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 2 Nov 2019 12:23:40 -0600 Subject: [PATCH 221/231] minor fixes for user errors --- sys/modules/opus/fs/linkfs.lua | 3 +++ sys/modules/opus/ui/canvas.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/modules/opus/fs/linkfs.lua b/sys/modules/opus/fs/linkfs.lua index 38cceac..79ec13d 100644 --- a/sys/modules/opus/fs/linkfs.lua +++ b/sys/modules/opus/fs/linkfs.lua @@ -19,6 +19,9 @@ function linkfs.mount(_, source) error('Source is required') end source = fs.combine(source, '') + if not fs.exists(source) then + error('Source is missing') + end if fs.isDir(source) then return { source = source, diff --git a/sys/modules/opus/ui/canvas.lua b/sys/modules/opus/ui/canvas.lua index 260ad89..75e1792 100644 --- a/sys/modules/opus/ui/canvas.lua +++ b/sys/modules/opus/ui/canvas.lua @@ -152,7 +152,7 @@ function Canvas:write(x, y, text, bg, fg) bg = _rep(self.palette[bg], #text) end if fg then - fg = _rep(self.palette[fg], #text) + fg = _rep(self.palette[fg] or self.palette[1], #text) end self:blit(x, y, text, bg, fg) end From f2cf20c27426988809a2ef8dc406ccaf4c7db1a7 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 5 Nov 2019 11:18:21 -0700 Subject: [PATCH 222/231] cleanup --- sys/lzwfs.lua | 250 -------------------------------------------------- 1 file changed, 250 deletions(-) delete mode 100644 sys/lzwfs.lua diff --git a/sys/lzwfs.lua b/sys/lzwfs.lua deleted file mode 100644 index c1e9088..0000000 --- a/sys/lzwfs.lua +++ /dev/null @@ -1,250 +0,0 @@ --- see: https://github.com/Rochet2/lualzw --- MIT License - Copyright (c) 2016 Rochet2 - --- Transparent file system compression for non-binary files using lzw - --- Files that are compressed will have the first bytes in file set to 'LZWC'. --- If a file does not benefit from compression, the contents will not be altered. - --- Allow exclusions for files that shouldn't be compressed --- Also allow for future types of exclusions using bit operations --- 1 is reserved for compression exclusion --- fs.addException('startup.lua', 1) - --- To renable compression for a file --- fs.removeException('startup.lua', 1) - --- Restores file system --- fs.restore() - -local char = string.char -local type = type -local sub = string.sub -local tconcat = table.concat -local tinsert = table.insert - -local bit = _G.bit -local fs = _G.fs - -local SIGC = 'LZWC' -local IGNORE_COMPRESSION = 1 -- support other bits as well - -local basedictcompress = {} -local basedictdecompress = {} -for i = 0, 255 do - local ic, iic = char(i), char(i, 0) - basedictcompress[ic] = iic - basedictdecompress[iic] = ic -end - -local native = { open = fs.open } -fs.exceptions = fs.exceptions or { } - -local function dictAddA(str, dict, a, b) - if a >= 256 then - a, b = 0, b+1 - if b >= 256 then - dict = {} - b = 1 - end - end - dict[str] = char(a,b) - a = a+1 - return dict, a, b -end - -local function compress(input) - if type(input) ~= "string" then - error ("string expected, got "..type(input)) - end - local len = #input - if len <= 1 then - return input - end - - local dict = {} - local a, b = 0, 1 - - local result = { SIGC } - local resultlen = 1 - local n = 2 - local word = "" - for i = 1, len do - local c = sub(input, i, i) - local wc = word..c - if not (basedictcompress[wc] or dict[wc]) then - local write = basedictcompress[word] or dict[word] - if not write then - error "algorithm error, could not fetch word" - end - result[n] = write - resultlen = resultlen + #write - n = n+1 - if len <= resultlen then - return input - end - dict, a, b = dictAddA(wc, dict, a, b) - word = c - else - word = wc - end - end - result[n] = basedictcompress[word] or dict[word] - resultlen = resultlen+#result[n] - if len <= resultlen then - return input - end - return tconcat(result) -end - -local function dictAddB(str, dict, a, b) - if a >= 256 then - a, b = 0, b+1 - if b >= 256 then - dict = {} - b = 1 - end - end - dict[char(a,b)] = str - a = a+1 - return dict, a, b -end - -local function decompress(input) - if type(input) ~= "string" then - error( "string expected, got "..type(input)) - end - - if #input <= 1 then - return input - end - - local control = sub(input, 1, 4) - if control ~= SIGC then - return input - end - input = sub(input, 5) - local len = #input - - if len < 2 then - error("invalid input - not a compressed string") - end - - local dict = {} - local a, b = 0, 1 - - local result = {} - local n = 1 - local last = sub(input, 1, 2) - result[n] = basedictdecompress[last] or dict[last] - n = n+1 - for i = 3, len, 2 do - local code = sub(input, i, i+1) - local lastStr = basedictdecompress[last] or dict[last] - if not lastStr then - error( "could not find last from dict. Invalid input?") - end - local toAdd = basedictdecompress[code] or dict[code] - if toAdd then - result[n] = toAdd - n = n+1 - dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) - else - local tmp = lastStr..sub(lastStr, 1, 1) - result[n] = tmp - n = n+1 - dict, a, b = dictAddB(tmp, dict, a, b) - end - last = code - end - return tconcat(result) -end - -local function split(str, pattern) - pattern = pattern or "(.-)\n" - local t = {} - local function helper(line) tinsert(t, line) return "" end - helper((str:gsub(pattern, helper))) - return t -end - -function fs.open(fname, flags) - if flags == 'r' then - local f, err = native.open(fname, 'rb') - if not f then - return f, err - end - - local ctr = 0 - local lines - return { - readLine = function() - if not lines then - lines = split(decompress(f.readAll())) - end - ctr = ctr + 1 - return lines[ctr] - end, - readAll = function() - return decompress(f.readAll()) - end, - close = function() - f.close() - end, - } - elseif flags == 'w' or flags == 'a' then - if bit.band(fs.exceptions[fs.combine(fname, '')] or 0, IGNORE_COMPRESSION) == IGNORE_COMPRESSION then - return native.open(fname, flags) - end - - local c = { } - - if flags == 'a' then - local f = fs.open(fname, 'r') - if f then - tinsert(c, f.readAll()) - f.close() - end - end - - local f, err = native.open(fname, 'wb') - if not f then - return f, err - end - - return { - write = function(str) - tinsert(c, str) - end, - writeLine = function(str) - tinsert(c, str) - tinsert(c, '\n') - end, - flush = function() - -- this isn't gonna work... - -- f.write(compress(tconcat(c))) - f.flush(); - end, - close = function() - f.write(compress(tconcat(c))) - f.close() - end, - } - end - - return native.open(fname, flags) -end - -function fs.addException(fname, mode) - fname = fs.combine(fname, '') - fs.exceptions[fname] = bit.bor(fs.exceptions[fname] or 0, mode) -end - -function fs.removeException(fname, mode) - fname = fs.combine(fname, '') - fs.exceptions[fname] = bit.bxor(fs.exceptions[fname] or 0, mode) -end - -function fs.restore() - fs.open = native.open -end From e9717c4def8fbede084fee4a95994104cb450acd Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 7 Nov 2019 18:00:54 -0700 Subject: [PATCH 223/231] Events shows all + tweaks --- sys/apps/Files.lua | 1 + sys/kernel.lua | 21 ++++++++++++++++----- sys/modules/opus/array.lua | 9 +++++++++ sys/modules/opus/fs/ramfs.lua | 4 ++++ 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 9f17255..f254a97 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -20,6 +20,7 @@ local config = Config.load('Files', { }) config.associations = config.associations or { nft = 'pain', + txt = 'edit', } local copied = { } diff --git a/sys/kernel.lua b/sys/kernel.lua index a817d23..b2ef8a8 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -1,5 +1,6 @@ _G.requireInjector(_ENV) +local Array = require('opus.array') local Terminal = require('opus.terminal') local Util = require('opus.util') @@ -55,7 +56,7 @@ end function kernel.unhook(event, fn) local eventHooks = kernel.hooks[event] if eventHooks then - Util.removeByValue(eventHooks, fn) + Array.removeByValue(eventHooks, fn) if #eventHooks == 0 then kernel.hooks[event] = nil end @@ -107,7 +108,7 @@ function Routine:resume(event, ...) error(result, -1) end if coroutine.status(self.co) == 'dead' then - Util.removeByValue(kernel.routines, self) + Array.removeByValue(kernel.routines, self) if #kernel.routines > 0 then switch(kernel.routines[1]) end @@ -188,7 +189,7 @@ function kernel.raise(uid) if routine then local previous = kernel.routines[1] if routine ~= previous then - Util.removeByValue(kernel.routines, routine) + Array.removeByValue(kernel.routines, routine) table.insert(kernel.routines, 1, routine) end @@ -211,7 +212,7 @@ function kernel.lower(uid) end end - Util.removeByValue(kernel.routines, routine) + Array.removeByValue(kernel.routines, routine) table.insert(kernel.routines, routine) return true end @@ -229,7 +230,17 @@ end function kernel.event(event, eventData) local stopPropagation - local eventHooks = kernel.hooks[event] + local eventHooks = kernel.hooks['*'] + if eventHooks then + for i = #eventHooks, 1, -1 do + stopPropagation = eventHooks[i](event, eventData) + if stopPropagation then + break + end + end + end + + eventHooks = kernel.hooks[event] if eventHooks then for i = #eventHooks, 1, -1 do stopPropagation = eventHooks[i](event, eventData) diff --git a/sys/modules/opus/array.lua b/sys/modules/opus/array.lua index b6ba255..f0aa73f 100644 --- a/sys/modules/opus/array.lua +++ b/sys/modules/opus/array.lua @@ -10,4 +10,13 @@ function Array.filter(it, f) return ot end +function Array.removeByValue(t, e) + for k,v in pairs(t) do + if v == e then + table.remove(t, k) + break + end + end +end + return Array diff --git a/sys/modules/opus/fs/ramfs.lua b/sys/modules/opus/fs/ramfs.lua index 0d943a8..1ed2f7a 100644 --- a/sys/modules/opus/fs/ramfs.lua +++ b/sys/modules/opus/fs/ramfs.lua @@ -48,6 +48,10 @@ function ramfs.getDrive() return 'ram' end +function ramfs.getFreeSpace() + return math.huge +end + function ramfs.list(node, dir) if node.nodes and node.mountPoint == dir then local files = { } From 6d8d62d309accc6a0af4c5b4f33b6c1d011a9d9c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 7 Nov 2019 22:50:11 -0700 Subject: [PATCH 224/231] tweaks --- sys/apps/system/cloud.lua | 2 +- sys/apps/system/diskusage.lua | 1 + sys/init/2.vfs.lua | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/apps/system/cloud.lua b/sys/apps/system/cloud.lua index e40d924..221c828 100644 --- a/sys/apps/system/cloud.lua +++ b/sys/apps/system/cloud.lua @@ -11,7 +11,7 @@ if _G.http.websocket then local tab = UI.Tab { tabTitle = 'Cloud', - description = 'Cloud catcher options', + description = 'Cloud Catcher options', key = UI.TextEntry { x = 3, ex = -3, y = 2, limit = 32, diff --git a/sys/apps/system/diskusage.lua b/sys/apps/system/diskusage.lua index fb958f5..98b8516 100644 --- a/sys/apps/system/diskusage.lua +++ b/sys/apps/system/diskusage.lua @@ -10,6 +10,7 @@ local peripheral = _G.peripheral local NftImages = { blank = '\0308\0317\153\153\153\153\153\153\153\153\010\0307\0318\153\153\153\153\153\153\153\153\010\0308\0317\153\153\153\153\153\153\153\153\010\0307\0318\153\153\153\153\153\153\153\153\010\0308\0317\153\153\153\153\153\153\153\153', drive = '\030 \031 \030b\031b\128\0308\0318\128\128\030f\149\030b\149\031 \139\010\030 \031 \030b\031b\128\128\128\128\128\128\010\030 \031 \030b\031b\128\0300\0317____\030b\031b\128\010\030 \031 \030b\031b\128\0300\0317____\030b\031b\128', + ram = '\030 \031 \128\0318\144\144\144\144\144\031 \128\010\0308\031 \157\0307\0317\128\128\128\128\128\030 \0318\145\010\030 \0318\136\0307\0317\128\0307\0310RAM\0307\128\030 \0318\132\010\0308\031 \157\0307\0317\128\128\128\128\128\030 \0318\145\010\030 \031 \128\0318\129\129\129\129\129\031 \128', rom = '\030 \031 \128\0318\144\144\144\144\144\031 \128\010\0308\031 \157\0307\0317\128\128\128\128\128\030 \0318\145\010\030 \0318\136\0307\0317\128\0307\0310ROM\0307\128\030 \0318\132\010\0308\031 \157\0307\0317\128\128\128\128\128\030 \0318\145\010\030 \031 \128\0318\129\129\129\129\129\031 \128', hdd = '\030 \031 \0307\0317\128\0300\135\131\139\0307\128\010\030 \031 \0300\0317\149\0310\128\0307\131\0300\128\0307\149\010\030 \031 \0307\0310\130\0300\0317\144\0308\0310\133\0307\159\129\010\030 \031 \0308\0317\149\129\142\159\0307\128\010\030 \031 \030 \0317\143\143\143\143\143', } diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index 62f5b4d..5b3c5f9 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -220,6 +220,8 @@ function fs.find(spec) -- not optimized -- local files = node.fs.find(node, spec) local files = { } -- method from https://github.com/N70/deltaOS/blob/dev/vfs + + -- REVISIT - see globbing in shellex package local function recurse_spec(results, path, spec) local segment = spec:match('([^/]*)'):gsub('/', '') local pattern = '^' .. segment:gsub("[%.%[%]%(%)%%%+%-%?%^%$]","%%%1"):gsub("%z","%%z"):gsub("%*","[^/]-") .. '$' @@ -303,7 +305,8 @@ function fs.loadTab(path) local mounts = Util.readFile(path) if mounts then for _,l in ipairs(Util.split(mounts)) do - if l:sub(1, 1) ~= '#' then + l = Util.trim(l) + if #l > 0 and l:sub(1, 1) ~= '#' then local s, m = pcall(function() fs.mount(table.unpack(Util.matches(l))) end) From 57ea46dde7e9161f7d8acc70d1c7e8f4fd23ef10 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 8 Nov 2019 19:54:41 -0700 Subject: [PATCH 225/231] alternatives --- sys/apps/Files.lua | 3 +- sys/apps/Overview.lua | 7 +++-- sys/apps/network/telnet.lua | 3 +- sys/modules/opus/alternate.lua | 52 ++++++++++++++++++++++++++++++++++ sys/modules/opus/util.lua | 6 ++-- 5 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 sys/modules/opus/alternate.lua diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index f254a97..b39ddd9 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -1,3 +1,4 @@ +local Alt = require('opus.alternate') local Config = require('opus.config') local Event = require('opus.event') local pastebin = require('opus.http.pastebin') @@ -353,7 +354,7 @@ function Browser:eventHandler(event) self:setStatus('Started cloud edit') elseif event.type == 'shell' then - self:run('sys/apps/shell.lua') + self:run(Alt.get('shell')) elseif event.type == 'refresh' then self:updateDirectory(self.dir) diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 8cd2c92..92c09bf 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -1,3 +1,4 @@ +local Alt = require('opus.alternate') local class = require('opus.class') local Config = require('opus.config') local Event = require('opus.event') @@ -420,13 +421,13 @@ function page:eventHandler(event) shell.switchTab(shell.openTab(event.button.app.run)) elseif event.type == 'shell' then - shell.switchTab(shell.openTab('sys/apps/shell.lua')) + shell.switchTab(shell.openTab(Alt.get('shell'))) elseif event.type == 'lua' then - shell.switchTab(shell.openTab('sys/apps/Lua.lua')) + shell.switchTab(shell.openTab(Alt.get('lua'))) elseif event.type == 'files' then - shell.switchTab(shell.openTab('sys/apps/Files.lua')) + shell.switchTab(shell.openTab(Alt.get('files'))) elseif event.type == 'focus_change' then if event.focused.parent.UIElement == 'Icon' then diff --git a/sys/apps/network/telnet.lua b/sys/apps/network/telnet.lua index 8bd11de..9aec83c 100644 --- a/sys/apps/network/telnet.lua +++ b/sys/apps/network/telnet.lua @@ -1,3 +1,4 @@ +local Alt = require('opus.alternate') local Event = require('opus.event') local Socket = require('opus.socket') local Util = require('opus.util') @@ -46,7 +47,7 @@ local function telnetHost(socket, mode) title = mode .. ' client', hidden = true, co = coroutine.create(function() - Util.run(_ENV, 'sys/apps/shell.lua', table.unpack(termInfo.program)) + Util.run(_ENV, Alt.get('shell'), table.unpack(termInfo.program)) if socket.queue then socket:write(socket.queue) end diff --git a/sys/modules/opus/alternate.lua b/sys/modules/opus/alternate.lua new file mode 100644 index 0000000..532fc20 --- /dev/null +++ b/sys/modules/opus/alternate.lua @@ -0,0 +1,52 @@ +local Config = require('opus.config') +local Util = require('opus.util') + +local function getConfig() + return Config.load('alternate', { + default = { + shell = 'sys/apps/shell.lua', + lua = 'sys/apps/Lua.lua', + files = 'sys/apps/Files.lua', + }, + choices = { + shell = { + 'sys/apps/shell.lua', + 'rom/programs/shell', + }, + lua = { + 'sys/apps/Lua.lua', + 'rom/programs/lua.lua', + }, + files = { + 'sys/apps/Files.lua', + } + } + }) +end + +local Alt = { } + +function Alt.get(key) + return getConfig().default[key] +end + +function Alt.set(key, value) + local config = getConfig() + + config.default[key] = value + Config.update('alternate', config) +end + +function Alt.addChoice(key, value) + local config = getConfig() + + if not config.choices[key] then + config.choices[key] = { } + end + if not Util.contains(config.choices[key], value) then + config.choices[key] = value + Config.update('alternate', config) + end +end + +return Alt diff --git a/sys/modules/opus/util.lua b/sys/modules/opus/util.lua index 4604199..564b9f8 100644 --- a/sys/modules/opus/util.lua +++ b/sys/modules/opus/util.lua @@ -621,17 +621,17 @@ end -- http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76 function Util.trim(s) - return s:find'^%s*$' and '' or s:match'^%s*(.*%S)' + return s:find('^%s*$') and '' or s:match('^%s*(.*%S)') end -- trim whitespace from left end of string function Util.triml(s) - return s:match'^%s*(.*)' + return s:match('^%s*(.*)') end -- trim whitespace from right end of string function Util.trimr(s) - return s:find'^%s*$' and '' or s:match'^(.*%S)' + return s:find('^%s*$') and '' or s:match('^(.*%S)') end -- end http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76 From 9ef4d9ef64d17ddaf774c32cd078d442824b3b7c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 9 Nov 2019 21:15:07 -0700 Subject: [PATCH 226/231] package manager install/uninstall directives --- sys/apps/package.lua | 26 ++++++++++++++++++++++++++ sys/modules/opus/alternate.lua | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/sys/apps/package.lua b/sys/apps/package.lua index 3d95c17..d1d963e 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -9,6 +9,12 @@ local term = _G.term local args = { ... } local action = table.remove(args, 1) +local function makeSandbox() + local sandbox = setmetatable(Util.shallowCopy(_ENV), { __index = _G }) + _G.requireInjector(sandbox) + return sandbox +end + local function Syntax(msg) _G.printError(msg) print('\nSyntax: Package list | install [name] ... | update [name] | uninstall [name]') @@ -71,6 +77,17 @@ local function install(name, isUpdate, ignoreDeps) end showProgress() end) + + if not isUpdate then + if manifest.install then + local s, m = pcall(function() + load(manifest.install, 'install', nil, makeSandbox()) + end) + if not s and m then + _G.printError(m) + end + end + end end if action == 'list' then @@ -121,6 +138,15 @@ if action == 'uninstall' then if not Packages:isInstalled(name) then error('Package is not installed') end + local manifest = Packages:getManifest(name) + if manifest.uninstall then + local s, m = pcall(function() + load(manifest.uninstall, 'uninstall', nil, makeSandbox()) + end) + if not s and m then + _G.printError(m) + end + end local packageDir = fs.combine('packages', name) fs.delete(packageDir) print('removed: ' .. packageDir) diff --git a/sys/modules/opus/alternate.lua b/sys/modules/opus/alternate.lua index 532fc20..33e668b 100644 --- a/sys/modules/opus/alternate.lua +++ b/sys/modules/opus/alternate.lua @@ -44,7 +44,7 @@ function Alt.addChoice(key, value) config.choices[key] = { } end if not Util.contains(config.choices[key], value) then - config.choices[key] = value + table.insert(config.choices[key], value) Config.update('alternate', config) end end From 340e37da820c336a9753e83db5c32d9a573b61c4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 9 Nov 2019 22:01:48 -0700 Subject: [PATCH 227/231] package manager wip --- sys/apps/package.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/apps/package.lua b/sys/apps/package.lua index d1d963e..61c07af 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -81,7 +81,7 @@ local function install(name, isUpdate, ignoreDeps) if not isUpdate then if manifest.install then local s, m = pcall(function() - load(manifest.install, 'install', nil, makeSandbox()) + load(manifest.install, 'install', nil, makeSandbox())() end) if not s and m then _G.printError(m) @@ -141,7 +141,7 @@ if action == 'uninstall' then local manifest = Packages:getManifest(name) if manifest.uninstall then local s, m = pcall(function() - load(manifest.uninstall, 'uninstall', nil, makeSandbox()) + load(manifest.uninstall, 'uninstall', nil, makeSandbox())() end) if not s and m then _G.printError(m) From 4a6af34d7ca766649eeb5512cdb4d240f53f0b88 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 9 Nov 2019 22:26:11 -0700 Subject: [PATCH 228/231] alternative updates --- sys/modules/opus/alternate.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sys/modules/opus/alternate.lua b/sys/modules/opus/alternate.lua index 33e668b..b7e4024 100644 --- a/sys/modules/opus/alternate.lua +++ b/sys/modules/opus/alternate.lua @@ -1,3 +1,4 @@ +local Array = require('opus.array') local Config = require('opus.config') local Util = require('opus.util') @@ -33,10 +34,22 @@ end function Alt.set(key, value) local config = getConfig() + Alt.addChoice(key, value) + config.default[key] = value Config.update('alternate', config) end +function Alt.remove(key, value) + local config = getConfig() + + Array.removeByValue(config.choices[key], value) + if config.default[key] == value then + config.default[key] = config.choices[key][1] + end + Config.update('alternate', config) +end + function Alt.addChoice(key, value) local config = getConfig() From 8a5d30a441c95119e428cba8fa94660ec7f0c9b4 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 9 Nov 2019 22:33:16 -0700 Subject: [PATCH 229/231] oops --- sys/modules/opus/alternate.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/modules/opus/alternate.lua b/sys/modules/opus/alternate.lua index b7e4024..595d210 100644 --- a/sys/modules/opus/alternate.lua +++ b/sys/modules/opus/alternate.lua @@ -32,10 +32,9 @@ function Alt.get(key) end function Alt.set(key, value) - local config = getConfig() - Alt.addChoice(key, value) + local config = getConfig() config.default[key] = value Config.update('alternate', config) end From c9fd7efc2694bd116a8264308f5115718605e31a Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 9 Nov 2019 22:56:36 -0700 Subject: [PATCH 230/231] alternative optimize --- sys/modules/opus/alternate.lua | 70 +++++++++++++--------------------- 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/sys/modules/opus/alternate.lua b/sys/modules/opus/alternate.lua index 595d210..6f0d24f 100644 --- a/sys/modules/opus/alternate.lua +++ b/sys/modules/opus/alternate.lua @@ -3,62 +3,46 @@ local Config = require('opus.config') local Util = require('opus.util') local function getConfig() - return Config.load('alternate', { - default = { - shell = 'sys/apps/shell.lua', - lua = 'sys/apps/Lua.lua', - files = 'sys/apps/Files.lua', - }, - choices = { - shell = { - 'sys/apps/shell.lua', - 'rom/programs/shell', - }, - lua = { - 'sys/apps/Lua.lua', - 'rom/programs/lua.lua', - }, - files = { - 'sys/apps/Files.lua', - } - } - }) + return Config.load('alternate', { + shell = { + 'sys/apps/shell.lua', + 'rom/programs/shell', + }, + lua = { + 'sys/apps/Lua.lua', + 'rom/programs/lua.lua', + }, + files = { + 'sys/apps/Files.lua', + } + }) end local Alt = { } function Alt.get(key) - return getConfig().default[key] + return getConfig()[key][1] end function Alt.set(key, value) - Alt.addChoice(key, value) - - local config = getConfig() - config.default[key] = value - Config.update('alternate', config) + local config = getConfig() + Array.removeByValue(config[key], value) + table.insert(config[key], 1, value) + Config.update('alternate', config) end function Alt.remove(key, value) - local config = getConfig() - - Array.removeByValue(config.choices[key], value) - if config.default[key] == value then - config.default[key] = config.choices[key][1] - end - Config.update('alternate', config) + local config = getConfig() + Array.removeByValue(config[key], value) + Config.update('alternate', config) end -function Alt.addChoice(key, value) - local config = getConfig() - - if not config.choices[key] then - config.choices[key] = { } - end - if not Util.contains(config.choices[key], value) then - table.insert(config.choices[key], value) - Config.update('alternate', config) - end +function Alt.add(key, value) + local config = getConfig() + if not Util.contains(config[key], value) then + table.insert(config[key], value) + Config.update('alternate', config) + end end return Alt From 674c6af50902f2b324e1c4509a0e91cd72bb1846 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 10 Nov 2019 15:58:36 -0700 Subject: [PATCH 231/231] alternate support --- sys/apps/ShellLauncher.lua | 5 ++- sys/apps/package.lua | 35 ++++++++------- sys/apps/system/alternate.lua | 80 ++++++++++++++++++++++++++++++++++ sys/autorun/hotkeys.lua | 2 +- sys/autorun/log.lua | 1 + sys/modules/opus/alternate.lua | 2 +- 6 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 sys/apps/system/alternate.lua diff --git a/sys/apps/ShellLauncher.lua b/sys/apps/ShellLauncher.lua index d905653..f2eebb7 100644 --- a/sys/apps/ShellLauncher.lua +++ b/sys/apps/ShellLauncher.lua @@ -1,8 +1,11 @@ +local Alt = require('opus.alternate') + local kernel = _G.kernel local os = _G.os local shell = _ENV.shell local launcherTab = kernel.getCurrent() +launcherTab.noFocus = true kernel.hook('kernel_focus', function(_, eventData) local focusTab = eventData and eventData[1] @@ -17,7 +20,7 @@ kernel.hook('kernel_focus', function(_, eventData) end end if nextTab == launcherTab then - shell.switchTab(shell.openTab('sys/apps/shell.lua')) + shell.switchTab(shell.openTab(Alt.get('shell'))) else shell.switchTab(nextTab.uid) end diff --git a/sys/apps/package.lua b/sys/apps/package.lua index 61c07af..b5fdba3 100644 --- a/sys/apps/package.lua +++ b/sys/apps/package.lua @@ -41,6 +41,21 @@ local function progress(max) end end +local function runScript(script) + if script then + local s, m = pcall(function() + local fn, m = load(script, 'script', nil, makeSandbox()) + if not fn then + error(m) + end + fn() + end) + if not s and m then + _G.printError(m) + end + end +end + local function install(name, isUpdate, ignoreDeps) local manifest = Packages:downloadManifest(name) or error('Invalid package') @@ -79,14 +94,7 @@ local function install(name, isUpdate, ignoreDeps) end) if not isUpdate then - if manifest.install then - local s, m = pcall(function() - load(manifest.install, 'install', nil, makeSandbox())() - end) - if not s and m then - _G.printError(m) - end - end + runScript(manifest.install) end end @@ -138,15 +146,10 @@ if action == 'uninstall' then if not Packages:isInstalled(name) then error('Package is not installed') end + local manifest = Packages:getManifest(name) - if manifest.uninstall then - local s, m = pcall(function() - load(manifest.uninstall, 'uninstall', nil, makeSandbox())() - end) - if not s and m then - _G.printError(m) - end - end + runScript(manifest.uninstall) + local packageDir = fs.combine('packages', name) fs.delete(packageDir) print('removed: ' .. packageDir) diff --git a/sys/apps/system/alternate.lua b/sys/apps/system/alternate.lua new file mode 100644 index 0000000..6894428 --- /dev/null +++ b/sys/apps/system/alternate.lua @@ -0,0 +1,80 @@ +local Array = require('opus.array') +local Config = require('opus.config') +local UI = require('opus.ui') + +local colors = _G.colors + +local tab = UI.Tab { + tabTitle = 'Preferred', + description = 'Select preferred applications', + apps = UI.ScrollingGrid { + x = 2, y = 2, + ex = 12, ey = -3, + columns = { + { key = 'name' }, + }, + sortColumn = 'name', + disableHeader = true, + }, + choices = UI.Grid { + x = 14, y = 2, + ex = -2, ey = -3, + disableHeader = true, + columns = { + { key = 'file' }, + } + }, + statusBar = UI.StatusBar { + values = 'Double-click to set as preferred' + }, +} + +function tab.choices:getRowTextColor(row) + if row == self.values[1] then + return colors.yellow + end + return UI.Grid.getRowTextColor(self, row) +end + +function tab:updateChoices() + local app = self.apps:getSelected().name + local choices = { } + for _, v in pairs(self.config[app]) do + table.insert(choices, { file = v }) + end + self.choices:setValues(choices) + self.choices:draw() +end + +function tab:enable() + self.config = Config.load('alternate') + + local apps = { } + for k, _ in pairs(self.config) do + table.insert(apps, { name = k }) + end + self.apps:setValues(apps) + + self:updateChoices() + + UI.Tab.enable(self) +end + +function tab:eventHandler(event) + if event.type == 'grid_focus_row' and event.element == self.apps then + self:updateChoices() + + elseif event.type == 'grid_select' and event.element == self.choices then + local app = self.apps:getSelected().name + Array.removeByValue(self.config[app], event.selected.file) + table.insert(self.config[app], 1, event.selected.file) + self:updateChoices() + Config.update('alternate', self.config) + + else + return UI.Tab.eventHandler(self, event) + end + return true +end + +return tab diff --git a/sys/autorun/hotkeys.lua b/sys/autorun/hotkeys.lua index 5c6b539..cbd93bf 100644 --- a/sys/autorun/hotkeys.lua +++ b/sys/autorun/hotkeys.lua @@ -42,7 +42,7 @@ keyboard.addHotkey('control-tab', function() return a.uid < b.uid end for _,tab in Util.spairs(tabs, compareTab) do - if not tab.hidden then + if not tab.hidden and not tab.noFocus then table.insert(visibleTabs, tab) end end diff --git a/sys/autorun/log.lua b/sys/autorun/log.lua index 4f53ed4..91bb193 100644 --- a/sys/autorun/log.lua +++ b/sys/autorun/log.lua @@ -54,6 +54,7 @@ if multishell and multishell.openTab then multishell.openTab({ title = 'System Log', fn = systemLog, + noTerminate = true, hidden = true, }) else diff --git a/sys/modules/opus/alternate.lua b/sys/modules/opus/alternate.lua index 6f0d24f..101de58 100644 --- a/sys/modules/opus/alternate.lua +++ b/sys/modules/opus/alternate.lua @@ -6,7 +6,7 @@ local function getConfig() return Config.load('alternate', { shell = { 'sys/apps/shell.lua', - 'rom/programs/shell', + 'rom/programs/shell.lua', }, lua = { 'sys/apps/Lua.lua',