From cdea6e4aed34f174fb93cc5c6bc41f5300a15e57 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 31 Mar 2020 10:08:07 -0600 Subject: [PATCH 01/12] canvas overhaul --- ccemux/etc/apps.db | 12 +++ ccemux/system/ccemux.lua | 8 +- common/Appstore.lua | 112 ++++++++-------------- common/Follow.lua | 1 - common/etc/apps.db | 2 +- ignore/passthrough.lua | 174 ++++++++++++++++++++++++++++++++++ ignore/twm.lua | 62 ++++-------- lzwfs/system/lzwfs.lua | 13 ++- milo/MiloRemote.lua | 2 +- milo/core/machines.lua | 6 +- milo/plugins/item/infoTab.lua | 2 +- milo/plugins/remote/setup.lua | 20 ++-- milo/plugins/statsView.lua | 1 + monitor/mwm.lua | 5 +- recipeBook/recipeBook.lua | 4 +- screenSaver/system/saver.lua | 15 +-- secure/system/secure.lua | 15 +-- swshop/shopTab.lua | 2 +- 18 files changed, 296 insertions(+), 160 deletions(-) create mode 100644 ccemux/etc/apps.db create mode 100644 ignore/passthrough.lua diff --git a/ccemux/etc/apps.db b/ccemux/etc/apps.db new file mode 100644 index 0000000..081f9f7 --- /dev/null +++ b/ccemux/etc/apps.db @@ -0,0 +1,12 @@ +{ + [ "emu_config" ] = { + title = "Config", + category = "CCEmuX", + run = "emu config", + }, + [ "emu_data" ] = { + title = "Data", + category = "CCEmuX", + run = "emu data", + }, +} diff --git a/ccemux/system/ccemux.lua b/ccemux/system/ccemux.lua index 0948583..f05df3d 100644 --- a/ccemux/system/ccemux.lua +++ b/ccemux/system/ccemux.lua @@ -9,7 +9,7 @@ local tab = UI.Tab { tabTitle = 'CCEmuX', description = 'CCEmuX peripherals', form = UI.Form { - x = 2, ex = -2, y = 1, ey = 4, + x = 2, ex = -2, y = 2, ey = 5, values = { side = 'bottom', type = 'wireless_modem', @@ -28,7 +28,7 @@ local tab = UI.Tab { }, }, drive_id = UI.TextEntry { - x = 20, y = 3, + x = 19, y = 3, formKey = 'drive_id', shadowText = 'id', width = 5, @@ -36,13 +36,13 @@ local tab = UI.Tab { transform = 'number', }, add = UI.Button { - x = 28, y = 3, + x = -6, y = 3, width = 5, text = 'Add', event = 'form_ok', help = 'Add items to turtle to add to filter', }, }, grid = UI.Grid { - x = 3, ex = -3, y = 6, ey = -2, + x = 2, ex = -2, y = 7, ey = -2, columns = { { heading = 'Side', key = 'side', width = 8 }, { heading = 'Type', key = 'type' }, diff --git a/common/Appstore.lua b/common/Appstore.lua index a94c93f..67dfb36 100644 --- a/common/Appstore.lua +++ b/common/Appstore.lua @@ -8,10 +8,10 @@ local http = _G.http local multishell = _ENV.multishell local os = _G.os local shell = _ENV.shell +local colors = _G.colors local REGISTRY_DIR = 'usr/.registry' - -- FIX SOMEDAY local function registerApp(app, key) app.key = SHA.compute(key) @@ -27,7 +27,6 @@ local function unregisterApp(key) end end - local sandboxEnv = Util.shallowCopy(_ENV) setmetatable(sandboxEnv, { __index = _G }) @@ -36,21 +35,10 @@ UI:configure('Appstore', ...) local APP_DIR = 'usr/apps' -local sources = { - - { text = "STD Default", - event = 'source', - url = "http://pastebin.com/raw/zVws7eLq" }, --stock ---[[ - { text = "Discover", - event = 'source', - generateName = true, - url = "http://pastebin.com/raw/9bXfCz6M" }, --owned by dannysmc95 - - { text = "Opus", - event = 'source', - url = "http://pastebin.com/raw/ajQ91Rmn" }, -]] +local source = { + text = "STD Default", + event = 'source', + url = "http://pastebin.com/raw/zVws7eLq", } shell.setDir(APP_DIR) @@ -87,14 +75,14 @@ local function runApp(app, checkExists, ...) error('Failed to download') end - local fn = loadstring(program, app.name) + fn = _G.loadstring(program, app.name) if not fn then error('Failed to download') end - setfenv(fn, sandboxEnv) - fn(unpack(args)) + _G.setfenv(fn, sandboxEnv) + fn(table.unpack(args)) end end @@ -134,16 +122,16 @@ local viewApp = function(app) return true end -local getSourceListing = function(source) +local getSourceListing = function() local contents = http.get(source.url) if contents then - local fn = loadstring(contents.readAll(), source.text) + local fn = _G.loadstring(contents.readAll(), source.text) contents.close() local env = { std = { } } setmetatable(env, { __index = _G }) - setfenv(fn, env) + _G.setfenv(fn, env) fn() if env.contextualGet then @@ -172,9 +160,28 @@ local getSourceListing = function(source) end end +getSourceListing() + +if not source.storeURLs then + error('Unable to download application list') +end + +local buttons = { } +for k,v in Util.spairs(source.storeCatagoryNames, + function(a, b) return a:lower() < b:lower() end) do + + if v ~= 'Operating System' then + table.insert(buttons, { + text = v, + event = 'category', + index = k, + }) + end +end +source.index, source.name = Util.first(source.storeCatagoryNames) + local appPage = UI.Page { menuBar = UI.MenuBar { --- showBackButton = not pocket, buttons = { { text = '\027', event = 'back' }, { text = 'Install', event = 'install' }, @@ -213,7 +220,7 @@ function appPage.container.viewport:draw() end end -function appPage:enable(source, app) +function appPage:enable(app) self.source = source self.app = app UI.Page.enable(self) @@ -293,8 +300,7 @@ end local categoryPage = UI.Page { menuBar = UI.MenuBar { buttons = { - { text = 'Catalog', dropdown = sources }, - { text = 'Category', name = 'categoryButton', dropdown = { } }, + { text = 'Category', name = 'categoryButton', dropdown = buttons }, }, }, grid = UI.ScrollingGrid { @@ -309,62 +315,21 @@ local categoryPage = UI.Page { l = 'lua', [ 'control-q' ] = 'quit', }, + source = source, } -function categoryPage:setCategory(source, name, index) +function categoryPage:setCategory(name, index) self.grid.values = { } for _,v in pairs(source.storeURLs) do if index == 0 or index == v.catagory then table.insert(self.grid.values, v) end end - self.statusBar:setStatus(string.format('%s: %s', source.text, name)) + self.statusBar:setStatus(string.format('%s: %s', self.source.text, name)) self.grid:update() self.grid:setIndex(1) end -function categoryPage:setSource(source) - - if not source.categoryMenu then - - self.statusBar:setStatus('Loading...') - self.statusBar:draw() - self:sync() - - getSourceListing(source) - - if not source.storeURLs then - error('Unable to download application list') - end - - local buttons = { } - for k,v in Util.spairs(source.storeCatagoryNames, - function(a, b) return a:lower() < b:lower() end) do - - if v ~= 'Operating System' then - table.insert(buttons, { - text = v, - event = 'category', - index = k, - }) - end - end - - source.categoryMenu = UI.DropMenu({ - buttons = buttons, - }) - source.index, source.name = Util.first(source.storeCatagoryNames) - - categoryPage.menuBar.categoryButton:add({ - categoryMenu = source.categoryMenu - }) - end - - self.source = source - self.menuBar.categoryButton.dropmenu = source.categoryMenu - categoryPage:setCategory(source, source.name, source.index) -end - function categoryPage.grid:sortCompare(a, b) return a.ltitle < b.ltitle end @@ -377,9 +342,8 @@ function categoryPage.grid:getRowTextColor(row, selected) end function categoryPage:eventHandler(event) - if event.type == 'grid_select' or event.type == 'select' then - UI:setPage(appPage, self.source, self.grid:getSelected()) + UI:setPage(appPage, self.grid:getSelected()) elseif event.type == 'category' then self:setCategory(self.source, event.button.text, event.button.index) @@ -401,7 +365,7 @@ function categoryPage:eventHandler(event) end print("Retrieving catalog list") -categoryPage:setSource(sources[1]) +categoryPage:setCategory(source.name, source.index) UI:setPage(categoryPage) UI:pullEvents() diff --git a/common/Follow.lua b/common/Follow.lua index 3ad0007..cd9afb2 100644 --- a/common/Follow.lua +++ b/common/Follow.lua @@ -42,7 +42,6 @@ local page = UI.Page { }, range = UI.SlideOut { y = -7, height = 7, - backgroundColor = colors.cyan, titleBar = UI.TitleBar { event = 'cancel', title = 'Enter range', diff --git a/common/etc/apps.db b/common/etc/apps.db index d12829c..f434ef9 100644 --- a/common/etc/apps.db +++ b/common/etc/apps.db @@ -57,7 +57,7 @@ category = "Apps", requires = "advancedComputer", iconExt = "\030 \031 \128\030d\159\030 \031d\140\030d\031 \155\030 \0315\140\0305\031 \155\030 \128\010\030 \031d\136\145\0315\136\145\031d\153\031 \128\0315\153\010\030 \031 \128\031d\130\140\134\0315\140\134\031 \128", - run = "packages/common/hexedit.lua", + run = "fileui --exec=hexedit.lua", }, [ "fb1c39e9f4f3c2628ad173ab401a6e4e4baf783d" ] = { title = "Sounds", diff --git a/ignore/passthrough.lua b/ignore/passthrough.lua new file mode 100644 index 0000000..dae7403 --- /dev/null +++ b/ignore/passthrough.lua @@ -0,0 +1,174 @@ +local _rep = string.rep +local _sub = string.sub +local colors = _G.colors + +local palette = { } + +for n = 1, 16 do + palette[2 ^ (n - 1)] = _sub("0123456789abcdef", n, n) +end + +local swindow = { } + +function swindow.createPassthrough(parent, wx, wy, width, height) + local window = { } + local cx, cy = 1, 1 + local blink = false + local fg = colors.white + local bg = colors.black + + local function crop(text, x) + local w = #text + + if x < 1 then + text = _sub(text, 2 - x) + w = w + x - 1 + x = 1 + end + + if x + w - 1 > width then + text = _sub(text, 1, width - x + 1) + end + + return text + end + + local function blit(text, fg, bg) + parent.setCursorPos(cx + wx - 1, cy + wy - 1) + parent.blit(text, fg, bg) + cx = cx + #text + end + + function window.write(text) + if cy > 0 and cy <= height then + text = crop(tostring(text), cx) + if #text > 0 then + --parent.setCursorPos(cx + wx - 1, cy + wy - 1) + blit(text, _rep(palette[fg], #text), _rep(palette[bg], #text)) + end + end + end + + function window.blit(text, fg, bg) + if cy > 0 and cy <= height then + text = crop(tostring(text), cx) + if #text > 0 then + blit(text, crop(tostring(fg), cx), crop(tostring(bg), cx)) + end + end + end + + function window.clear() + local filler = _rep(' ', width) + for i = 1, height do + parent.setCursorPos(wx, i + wy - 1) + parent.write(filler) + end + end + + function window.clearLine() + if cy > 0 and cy <= height then + local filler = _rep(' ', width) + parent.setCursorPos(cx + wx - 1, cy + wy - 1) + parent.write(filler) + end + end + + function window.getCursorPos() + return cx, cy + end + + function window.setCursorPos(x, y) + cx = math.floor(x) + cy = math.floor(y) + parent.setCursorPos(cx + wx - 1, cy + wy - 1) + end + + function window.setCursorBlink(b) + blink = b + parent.setCursorBlink(b) + end + + function window.getCursorBlink() + return blink + end + + window.isColor = parent.isColor + window.isColour = parent.isColour + window.setPaletteColour = parent.setPaletteColour + window.setPaletteColor = parent.setPaletteColor + window.getPaletteColour = parent.getPaletteColour + window.getPaletteColor = parent.getPaletteColour + window.setBackgroundColor = parent.setBackgroundColor + window.setBackgroundColour = parent.setBackgroundColor + window.getBackgroundColor = parent.getBackgroundColor + window.getBackgroundColour = parent.getBackgroundColor + window.setVisible = parent.setVisible + window.redraw = function() end --parent.redraw + + function window.getTextColor() + return fg + end + window.getTextColour = window.getTextColor + + function window.setTextColor(textColor) + fg = textColor + parent.setTextColor(fg) + end + window.setTextColour = window.setTextColor + + function window.restoreCursor() + parent.setCursorPos(cx + wx - 1, cy + wy - 1) + parent.setTextColor(fg) + parent.setCursorBlink(blink) + end + + function window.getSize() + return width, height + end + + function window.scroll( n ) + if n ~= 0 then + local lines = { } + for i = 1, height do + lines[i] = { parent.getLine(wy + i - 1) } + end + + for newY = 1, height do + local y = newY + n + parent.setCursorPos(wx, wy + newY - 1) + if y >= 1 and y <= height then + parent.blit(table.unpack(lines[y])) + else + parent.blit( + _rep(' ', width), + _rep(palette[fg], width), + _rep(palette[bg], width)) + end + end + parent.setCursorPos(cx + wx - 1, cy + wy - 1) + end + end + + function window.getLine(y) + local t, tc, bc = parent.getLine(y + cy - 1) + return t:sub(1, width), tc:sub(1, width), bc:sub(1, width) + end + + function window.getPosition() + return wx, wy + end + + function window.reposition(nNewX, nNewY, nNewWidth, nNewHeight, newParent) + wx = nNewX + wy = nNewY + width = nNewWidth + height = nNewHeight + + window.restoreCursor() + end + + return window +end + +return swindow diff --git a/ignore/twm.lua b/ignore/twm.lua index 24f908a..07bfc3e 100644 --- a/ignore/twm.lua +++ b/ignore/twm.lua @@ -4,42 +4,21 @@ local Util = require('opus.util') local colors = _G.colors local os = _G.os -local peripheral = _G.peripheral local printError = _G.printError -local shell = _ENV.shell local term = _G.term local window = _G.window -local function syntax() - printError('Syntax:') - error('mwm [--config=filename] [monitor]') -end - -local args = Util.parse(...) local UID = 0 local multishell = { } local processes = { } local parentTerm = term.current() -local sessionFile = args.config or 'usr/config/mwm' -local monName = args[1] +local sessionFile = 'usr/config/twm' local running -local parentMon +local parentMon = term.current() local defaultEnv = Util.shallowCopy(_ENV) defaultEnv.multishell = multishell -if monName == 'terminal' then - parentMon = term.current() -elseif monName then - parentMon = peripheral.wrap(monName) or syntax() -else - parentMon = peripheral.find('monitor') or syntax() -end - -if parentMon.setTextScale then - parentMon.setTextScale(.5) -end - local monDim, termDim = { }, { } monDim.width, monDim.height = parentMon.getSize() termDim.width, termDim.height = parentTerm.getSize() @@ -73,13 +52,10 @@ local function write(win, x, y, text) end local function redraw() - --monitor.clear() monitor.canvas:dirty() - --monitor.setBackgroundColor(colors.gray) monitor.canvas:clear(colors.gray) - for k, process in ipairs(processes) do + for _, process in ipairs(processes) do process.container.canvas:dirty() - process:focus(k == #processes) end end @@ -112,7 +88,8 @@ function Process:new(args) height = args.height + 1, path = args.path, args = args.args or { }, - title = args.title or 'shell', + title = args.title or 'shell', + timestamp = os.clock(), isMoving = false, isResizing = false, }, { __index = Process }) @@ -155,20 +132,12 @@ function Process:new(args) end function Process:focus(focused) - if focused then - self.container.setBackgroundColor(colors.yellow) - else - self.container.setBackgroundColor(colors.lightGray) - end + self.container.setBackgroundColor(focused and colors.yellow or colors.lightGray) self.container.setTextColor(colors.black) write(self.container, 1, 1, string.rep(' ', self.width)) write(self.container, 2, 1, self.title) write(self.container, self.width - 1, 1, '*') write(self.container, self.width - 3, 1, '\029') - - if focused then - self.window.restoreCursor() - end end function Process:drawSizers() @@ -188,17 +157,18 @@ function Process:adjustDimensions() self.y = math.min(self.y, monDim.height - self.height + 1) end -function Process:reposition() +function Process:reposition(resizing) self:adjustDimensions() self.container.reposition(self.x, self.y, self.width, self.height) - self.container.setBackgroundColor(colors.black) - self.container.clear() self.window.reposition(1, 2, self.width, self.height - 1) if self.window ~= self.terminal then if self.terminal.reposition then -- ?? self.terminal.reposition(1, 1, self.width, self.height - 1) end - end + end + if resizing then + self:focus(self == processes[#processes]) + end redraw() end @@ -225,7 +195,7 @@ function Process:resize(x, y) self.height = y - self.isResizing.y + self.isResizing.h self.width = x - self.isResizing.x + self.isResizing.w - self:reposition() + self:reposition(true) self:resume('term_resize') self:drawSizers() multishell.saveSession(sessionFile) @@ -278,7 +248,8 @@ function multishell.setFocus(uid) process.container.canvas:raise() process:focus(true) - process.container.canvas:dirty() + process.container.canvas:dirty() + process.window.restoreCursor() end return true end @@ -423,14 +394,15 @@ function multishell.start() elseif focused.isMoving then focused.x = event[3] - focused.isMoving.x + focused.isMoving.ox focused.y = event[4] - focused.isMoving.y + focused.isMoving.oy - focused:reposition() + focused:reposition(false) end end elseif event[1] == 'char' or event[1] == 'key' or event[1] == 'key_up' or - event[1] == 'paste' then + event[1] == 'paste' or + event[1] == 'mouse_scroll' then local focused = processes[#processes] if focused then diff --git a/lzwfs/system/lzwfs.lua b/lzwfs/system/lzwfs.lua index 2c76f30..3f0a7a2 100644 --- a/lzwfs/system/lzwfs.lua +++ b/lzwfs/system/lzwfs.lua @@ -16,16 +16,19 @@ local config = Config.load('lzwfs', { local tab = UI.Tab { tabTitle = 'Compression', description = 'Disk compression', + [1] = UI.Window { + x = 2, y = 2, ex = -2, ey = 6, + }, label1 = UI.Text { - x = 2, y = 2, + x = 3, y = 3, value = 'Enable compression', }, checkbox = UI.Checkbox { - x = 20, y = 2, + x = 21, y = 3, value = config.enabled }, entry = UI.TextEntry { - x = 2, y = 4, ex = -2, + x = 3, y = 5 , ex = -3, limit = 256, shadowText = 'enter new path', accelerators = { @@ -34,7 +37,7 @@ local tab = UI.Tab { help = 'add a new path', }, grid = UI.Grid { - x = 2, ex = -2, y = 6, ey = -5, + x = 2, ex = -2, y = 8, ey = -5, disableHeader = true, columns = { { key = 'value' } }, autospace = true, @@ -45,7 +48,7 @@ local tab = UI.Tab { }, }, button = UI.Button { - x = -9, ex = -2, y = -3, + x = -8, ex = -2, y = -3, text = 'Apply', event = 'apply', }, diff --git a/milo/MiloRemote.lua b/milo/MiloRemote.lua index e85de5c..bf628cf 100644 --- a/milo/MiloRemote.lua +++ b/milo/MiloRemote.lua @@ -517,7 +517,7 @@ local function loadDirectory(dir) }) end end - page.menuBar.config:add({ dropmenu = UI.DropMenu { buttons = dropdown } }) + page.menuBar.config.dropdown = dropdown end local programDir = fs.getDir(shell.getRunningProgram()) diff --git a/milo/core/machines.lua b/milo/core/machines.lua index 844e491..99c61b5 100644 --- a/milo/core/machines.lua +++ b/milo/core/machines.lua @@ -241,6 +241,7 @@ The settings will take effect immediately!]], notification = UI.Notification { }, filter = UI.SlideOut { backgroundColor = colors.cyan, + noFill = true, menuBar = UI.MenuBar { buttons = { { text = 'Save', event = 'save' }, @@ -248,7 +249,8 @@ The settings will take effect immediately!]], }, }, grid = UI.ScrollingGrid { - x = 2, ex = -6, y = 2, ey = -6, + x = 2, ex = -6, y = 3, ey = -7, + disableHeader = true, columns = { { heading = 'Name', key = 'displayName' }, }, @@ -262,7 +264,7 @@ The settings will take effect immediately!]], text = '-', event = 'remove_entry', help = 'Remove', }, form = UI.Form { - x = 2, y = -4, height = 3, + x = 2, y = -5, height = 3, margin = 1, manualControls = true, [1] = UI.Checkbox { diff --git a/milo/plugins/item/infoTab.lua b/milo/plugins/item/infoTab.lua index 7ae99c7..76ce95c 100644 --- a/milo/plugins/item/infoTab.lua +++ b/milo/plugins/item/infoTab.lua @@ -8,7 +8,7 @@ local infoTab = UI.Tab { index = 4, backgroundColor = colors.cyan, textArea = UI.TextArea { - x = 2, ex = -2, y = 2, + x = 2, ex = -2, y = 2, ey = -2, }, } diff --git a/milo/plugins/remote/setup.lua b/milo/plugins/remote/setup.lua index 5d12d21..1ea8de3 100644 --- a/milo/plugins/remote/setup.lua +++ b/milo/plugins/remote/setup.lua @@ -15,7 +15,7 @@ local setup = UI.SlideOut { title = 'Remote Setup', }, form = UI.Form { - x = 2, ex = -2, y = 2, ey = -1, + y = 2, ey = -1, [1] = UI.TextEntry { formLabel = 'Server', formKey = 'server', help = 'ID for the server', @@ -40,15 +40,15 @@ local setup = UI.SlideOut { formLabel = 'Run on startup', formKey = 'runOnStartup', help = 'Run this program on startup' }, - info = UI.TextArea { - x = 1, ex = -1, y = 6, ey = -4, - textColor = colors.yellow, - marginLeft = 0, - marginRight = 0, - value = [[The Milo turtle must connect to a manipulator with a ]] .. - [[bound introspection module. The neural interface must ]] .. - [[also have an introspection module.]], - }, + }, + info = UI.TextArea { + x = 2, ex = -2, y = 8, ey = -4, + textColor = colors.yellow, + marginLeft = 0, + marginRight = 0, + value = [[The Milo turtle must connect to a manipulator with a ]] .. + [[bound introspection module. The neural interface must ]] .. + [[also have an introspection module.]], }, statusBar = UI.StatusBar { backgroundColor = colors.cyan, diff --git a/milo/plugins/statsView.lua b/milo/plugins/statsView.lua index 9f9c0a2..4f70601 100644 --- a/milo/plugins/statsView.lua +++ b/milo/plugins/statsView.lua @@ -86,6 +86,7 @@ local function createPage(node) [1] = UI.Tab { tabTitle = 'Overview', backgroundColor = colors.black, + noFill = true, onlineLabel = UI.Text { x = 2, y = 2, value = 'Storage Status', diff --git a/monitor/mwm.lua b/monitor/mwm.lua index a1e5eb1..a397606 100644 --- a/monitor/mwm.lua +++ b/monitor/mwm.lua @@ -121,7 +121,10 @@ function Process:new(args) self.terminal = self.window self.container.canvas.parent = monitor.canvas - table.insert(monitor.canvas.layers, 1, self.container.canvas) + if not monitor.canvas.children then + monitor.canvas.children = { } + end + table.insert(monitor.canvas.children, 1, self.container.canvas) self.container.canvas:setVisible(true) --self.container.getSize = self.window.getSize diff --git a/recipeBook/recipeBook.lua b/recipeBook/recipeBook.lua index 3aa67c3..4922929 100644 --- a/recipeBook/recipeBook.lua +++ b/recipeBook/recipeBook.lua @@ -61,12 +61,12 @@ local page = UI.Page { autospace = true, }, add = UI.SlideOut { - backgroundColor = colors.cyan, + height = 9, y = -9, titleBar = UI.TitleBar { title = 'Add a new book', }, form = UI.Form { - x = 2, ex = -2, y = 2, ey = -1, + y = 2, [1] = UI.TextEntry { formLabel = 'Name', formKey = 'name', shadowText = 'Friendly name', diff --git a/screenSaver/system/saver.lua b/screenSaver/system/saver.lua index b8fa7a3..2813173 100644 --- a/screenSaver/system/saver.lua +++ b/screenSaver/system/saver.lua @@ -9,20 +9,23 @@ local config = Config.load('saver', { local tab = UI.Tab { tabTitle = 'Screen Saver', description = 'Screen saver', + [1] = UI.Window { + x = 2, y = 2, ex = -2, ey = 5, + }, label1 = UI.Text { - x = 2, y = 3, + x = 3, y = 3, value = 'Enabled', }, checkbox = UI.Checkbox { - x = 20, y = 3, + x = 21, y = 3, value = config.enabled }, label2 = UI.Text { - x = 2, y = 4, + x = 3, y = 4, value = 'Timeout', }, timeout = UI.TextEntry { - x = 20, y = 4, width = 6, + x = 21, y = 4, width = 6, limit = 4, transform = 'number', value = config.timeout, @@ -31,8 +34,8 @@ local tab = UI.Tab { }, }, button = UI.Button { - x = 20, y = 6, - text = 'Update', + x = -8, ex = -2, y = -2, + text = 'Apply', event = 'update', }, } diff --git a/secure/system/secure.lua b/secure/system/secure.lua index 113ad9b..9fd0137 100644 --- a/secure/system/secure.lua +++ b/secure/system/secure.lua @@ -9,20 +9,23 @@ local config = Config.load('secure', { local tab = UI.Tab { tabTitle = 'Secure', description = 'Secure options', + [1] = UI.Window { + x = 2, y = 2, ex = -2, ey = 5, + }, label1 = UI.Text { - x = 2, y = 3, + x = 3, y = 3, value = 'Screen Locking', }, checkbox = UI.Checkbox { - x = 20, y = 3, + x = 21, y = 3, value = config.enabled }, label2 = UI.Text { - x = 2, y = 4, + x = 3, y = 4, value = 'Lock timeout', }, timeout = UI.TextEntry { - x = 20, y = 4, width = 6, + x = 21, y = 4, width = 6, limit = 4, transform = 'number', value = config.timeout, @@ -31,8 +34,8 @@ local tab = UI.Tab { }, }, button = UI.Button { - x = 20, y = 6, - text = 'Update', + x = -8, ex = -2, y = -2, + text = 'Apply', event = 'update', }, } diff --git a/swshop/shopTab.lua b/swshop/shopTab.lua index 6bfabb5..63e3220 100644 --- a/swshop/shopTab.lua +++ b/swshop/shopTab.lua @@ -10,7 +10,7 @@ local shopTab = UI.Tab { tabTitle = 'Store', index = 2, form = UI.Form { - x = 2, ex = -2, y = 1, ey = -2, + x = 2, ex = -2, y = 2, ey = -2, manualControls = true, [1] = UI.TextEntry { formLabel = 'Name', formKey = 'name', -- 2.49.1 From 6bb4149113b3a3794ad2f55216a5e4437da61995 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 2 Apr 2020 21:29:28 -0600 Subject: [PATCH 02/12] editor 2.0 --- common/edit.lua | 645 +++++++++++++++++++++++----------- screenSaver/autorun/saver.lua | 2 +- 2 files changed, 439 insertions(+), 208 deletions(-) diff --git a/common/edit.lua b/common/edit.lua index f74bdb6..31cb96d 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -1,4 +1,4 @@ -local input = require('opus.input') +local UI = require('opus.ui') local colors = _G.colors local fs = _G.fs @@ -8,45 +8,25 @@ local shell = _ENV.shell local term = _G.term local textutils = _G.textutils -shell.setCompletionFunction(shell.getRunningProgram(), function(_, index, text) - if index == 1 then - return fs.complete(text, shell.dir(), true, false) - end -end) - -local tArgs = { ... } -if #tArgs == 0 then - error( "Usage: edit " ) -end - --- Error checking -local sPath = shell.resolve(tArgs[1]) -local bReadOnly = fs.isReadOnly(sPath) -if fs.exists(sPath) and fs.isDir(sPath) then - error( "Cannot edit a directory." ) -end - -if multishell then - multishell.setTitle(multishell.getCurrent(), fs.getName(sPath)) -end - local x, y = 1, 1 local w, h = term.getSize() local scrollX = 0 local scrollY = 0 local lastPos = { x = 1, y = 1 } local tLines = { } -local bRunning = true -local sStatus = "" -local isError local fileInfo local lastAction - +local actions +local sStatus = '' +local lastSave local dirty = { y = 1, ey = h } local mark = { } local searchPattern local undo = { chain = { }, pointer = 0 } local complete = { } +local page + +h = h - 2 local color = { textColor = '0', @@ -93,7 +73,7 @@ local keyMapping = { [ 'scroll_down' ] = 'scroll_down', [ 'control-down' ] = 'scroll_down', [ 'mouse_click' ] = 'go_to', - [ 'control-l' ] = 'goto_line', + [ 'control-g' ] = 'goto_line', -- marking [ 'shift-up' ] = 'mark_up', @@ -108,6 +88,7 @@ local keyMapping = { [ 'shift-end' ] = 'mark_end', [ 'shift-home' ] = 'mark_home', [ 'mouse_down' ] = 'mark_anchor', + [ 'mouse_doubleclick' ] = 'mark_current_word', -- editing delete = 'delete', @@ -126,6 +107,7 @@ local keyMapping = { -- file [ 'control-s' ] = 'save', + [ 'control-S' ] = 'save_as', [ 'control-q' ] = 'exit', [ 'control-enter' ] = 'run', @@ -135,18 +117,325 @@ local keyMapping = { [ 'control-n' ] = 'find_next', -- misc - [ 'control-g' ] = 'status', +-- [ 'control-g' ] = 'status', [ 'control-r' ] = 'refresh', - [ 'control' ] = 'menu', +} + +page = UI.Page { + menuBar = UI.MenuBar { + transitionHint = 'slideLeft', + buttons = { + { text = 'File', dropdown = { + { text = 'Save ^s', event = 'menu_action', action = 'save' }, + { text = 'Save As... ^S', event = 'menu_action', action = 'save_as', noFocus = true }, + { spacer = true }, + { text = 'Run', event = 'menu_action', action = 'run' }, + { spacer = true }, + { text = 'Quit ^q', event = 'menu_action', action = 'exit', noFocus = true }, + } }, + { text = 'Edit', dropdown = { + { text = 'Cut ^x', event = 'menu_action', action = 'cut' }, + { text = 'Copy ^c', event = 'menu_action', action = 'copy' }, + { text = 'Paste ^V', event = 'paste_internal' }, + { spacer = true }, + { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt', noFocus = true }, + { text = 'Find Next ^n', event = 'menu_action', action = 'find_next' }, + { spacer = true }, + { text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line', noFocus = true }, + { text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' }, + + } }, + }, + }, + gotoLine = UI.SlideOut { + x = -15, height = 1, y = -2, + noFill = true, + close = UI.Button { + x = -1, + backgroundColor = colors.cyan, + backgroundFocusColor = colors.cyan, + text = 'x', + event = 'slide_hide', + noPadding = true, + }, + label = UI.Text { + x = 2, + value = 'Line', + }, + lineNo = UI.TextEntry { + x = 7, width = 7, + limit = 5, + backgroundFocusColor = colors.gray, + backgroundColor = colors.gray, + transform = 'number', + accelerators = { + [ 'enter' ] = 'accept', + }, + }, + disable = function(self) + UI.SlideOut.disable(self) + self:setFocus(page.editor) + end, + show = function(self) + self.lineNo:reset() + UI.SlideOut.show(self) + self:addTransition('slideLeft', { easing = 'outBounce' }) + end, + eventHandler = function(self, event) + if event.type == 'accept' then + if self.lineNo.value then + actions.process('go_to', 1, self.lineNo.value) + end + self:hide() + return true + end + return UI.SlideOut.eventHandler(self, event) + end, + }, + search = UI.SlideOut { + x = -20, height = 1, y = -2, + noFill = true, + close = UI.Button { + x = -1, + backgroundColor = colors.cyan, + backgroundFocusColor = colors.cyan, + text = 'x', + event = 'slide_hide', + noPadding = true, + }, + label = UI.Text { + x = 2, + value = 'Find', + }, + search = UI.TextEntry { + x = 7, width = 12, + limit = 512, + markBackgroundColor = colors.lightGray, + backgroundFocusColor = colors.gray, + backgroundColor = colors.gray, + accelerators = { + [ 'enter' ] = 'accept', + }, + }, + disable = function(self) + UI.SlideOut.disable(self) + self:setFocus(page.editor) + end, + show = function(self) + self.search:markAll() + UI.SlideOut.show(self) + self:addTransition('slideLeft', { easing = 'outBounce' }) + end, + eventHandler = function(self, event) + if event.type == 'accept' then + local text = self.search.value + if text and #text > 0 then + searchPattern = text:lower() + if searchPattern then + actions.unmark() + actions.process('find', searchPattern, x) + end + end + self:hide() + return true + end + return UI.SlideOut.eventHandler(self, event) + end, + }, + save_as = UI.SlideOut { + x = -24, height = 1, y = -2, + noFill = true, + close = UI.Button { + x = -1, + backgroundColor = colors.cyan, + backgroundFocusColor = colors.cyan, + text = 'x', + event = 'slide_hide', + noPadding = true, + }, + label = UI.Text { + x = 2, + value = 'Save', + }, + filename = UI.TextEntry { + x = 7, width = 16, + limit = 512, + markBackgroundColor = colors.lightGray, + backgroundFocusColor = colors.gray, + backgroundColor = colors.gray, + accelerators = { + [ 'enter' ] = 'accept', + }, + }, + disable = function(self) + UI.SlideOut.disable(self) + self:setFocus(page.editor) + end, + show = function(self) + self.filename.value = fileInfo.abspath + if self.filename.value then + self.filename:setPosition(#self.filename.value) + end + UI.SlideOut.show(self) + self:addTransition('slideLeft', { easing = 'outBounce' }) + end, + eventHandler = function(self, event) + if event.type == 'accept' then + local text = self.filename.value + if text and #text > 0 then + actions.save(shell.resolve(text)) + end + self:hide() + return true + end + return UI.SlideOut.eventHandler(self, event) + end, + }, + quit = UI.SlideOut { + x = -26, height = 1, y = -2, + noFill = true, + close = UI.Button { + x = -1, + backgroundColor = colors.cyan, + backgroundFocusColor = colors.cyan, + text = 'x', + event = 'slide_hide', + noPadding = true, + }, + label = UI.Text { + x = 2, + value = 'Save', + }, + save = UI.Button { + x = 7, + text = 'Yes', + backgroundColor = colors.cyan, + event = 'save_yes', + }, + quit = UI.Button { + x = 13, + text = 'No', + backgroundColor = colors.cyan, + event = 'save_no', + }, + cancel = UI.Button { + x = 18, + text = 'Cancel', + backgroundColor = colors.cyan, + event = 'save_cancel', + }, + disable = function(self) + UI.SlideOut.disable(self) + self:setFocus(page.editor) + end, + show = function(self) + UI.SlideOut.show(self) + self:addTransition('slideLeft', { easing = 'outBounce' }) + end, + eventHandler = function(self, event) + if event.type == 'save_yes' then + if actions.save() then + UI:quit() + end + elseif event.type == 'save_no' then + UI:quit() + elseif event.type == 'save_cancel' then + self:hide() + end + return UI.SlideOut.eventHandler(self, event) + end, + }, + editor = UI.Window { + y = 2, ey = -2, + backgroundColor = colors.black, + transitionHint = 'slideRight', + focus = function(self) + if self.focused then + page.editor:setCursorPos(x - scrollX, y - scrollY) + self:setCursorBlink(true) + else + self:setCursorBlink(false) + end + end, + resize = function(self) + UI.Window.resize(self) + + w, h = self.width, self.height + actions.setCursor(x, y) + actions.dirty_all() + actions.redraw() + end, + draw = function() + actions.redraw() + end, + eventHandler = function(_, event) + if event.ie then + local action, param, param2 + local ie = event.ie + + if ie.code == 'char' then + action = keyMapping.char + param = ie.ch + + elseif ie.code == "mouse_click" or + ie.code == 'mouse_drag' or + --ie.code == 'mouse_up' or + ie.code == 'mouse_down' or + ie.code == 'mouse_doubleclick' then + + action = keyMapping[ie.code] + param = ie.x + scrollX + param2 = ie.y + scrollY + + elseif event.type == 'paste' then + action = keyMapping.paste + param = event.text + + else + action = keyMapping[ie.code] + end + + if action then + actions.process(action, param, param2) + return true + end + end + end, + }, + statusBar = UI.StatusBar { + transitionHint = 'slideLeft', + backgroundColor = colors.gray, + columns = { + { key = 'general' }, + { key = 'pos', width = 6, fg = colors.orange }, + }, + }, + enable = function(self) + UI.Page.enable(self) + self:setFocus(page.editor) + end, + eventHandler = function(self, event) + if event.type == 'paste_internal' then + self:setFocus(page.editor) + os.queueEvent('clipboard_paste') + return true + + elseif event.type == 'menu_action' then + actions.process(event.element.action) + if not event.element.noFocus then -- hacky + self:setFocus(self.editor) + end + return true + end + return UI.Page.eventHandler(self, event) + end, } local messages = { - menu = '^s: save, ^q: quit, ^enter: run', wrapped = 'search hit BOTTOM, continuing at TOP', } if w < 32 then messages = { - menu = '^s = save, ^q = quit', wrapped = 'search wrapped', } end @@ -166,23 +455,30 @@ local function getFileInfo(path) else fi.isReadOnly = fs.isReadOnly(fi.abspath) end - +_G._p = fi return fi end local function setStatus(pattern, ...) sStatus = string.format(pattern, ...) + page.statusBar.textColor = colors.white + page.statusBar:setValue('general', sStatus) + page.statusBar:draw() end local function setError(pattern, ...) - setStatus(pattern, ...) - isError = true + sStatus = string.format(pattern, ...) + page.statusBar.textColor = color.highlightColor + page.statusBar:setValue('general', sStatus) + page.statusBar:draw() end local function load(path) + fileInfo = getFileInfo(path) + tLines = {} - if fs.exists(path) then - local file = io.open(path, "r") + if fs.exists(fileInfo.abspath) then + local file = io.open(fileInfo.abspath, "r") local sLine = file:read() while sLine do table.insert(tLines, sLine) @@ -195,8 +491,6 @@ local function load(path) table.insert(tLines, '') end - fileInfo = getFileInfo(tArgs[1]) - local name = fileInfo.path if w < 32 then name = fs.getName(fileInfo.path) @@ -275,7 +569,7 @@ local tKeywords = { ["while"] = true, } -local function writeHighlighted(sLine, ny) +local function writeHighlighted(sLine, ny, dy) local buffer = { fg = '', text = '', @@ -314,7 +608,7 @@ local function writeHighlighted(sLine, ny) end buffer.fg = buffer.fg .. '7' - buffer.text = buffer.text .. '.' + buffer.text = buffer.text .. '\183' if mark.active and ny >= mark.y and ny <= mark.ey then local sx = 1 @@ -326,73 +620,61 @@ local function writeHighlighted(sLine, ny) ex = mark.ex end buffer.bg = string.rep('f', sx - 1) .. - string.rep('7', ex - sx) .. - string.rep('f', #buffer.text - ex + 1) + string.rep('7', ex - sx) .. + string.rep('f', #buffer.text - ex + 1) else buffer.bg = string.rep('f', #buffer.text) end - term.blit(buffer.text, buffer.fg, buffer.bg) + page.editor:blit(1 - scrollX, dy, buffer.text, buffer.bg, buffer.fg) end local function redraw() if dirty.y > 0 then - term.setBackgroundColor(color.bgColor) for dy = 1, h do local sLine = tLines[dy + scrollY] if sLine ~= nil then if dy + scrollY >= dirty.y and dy + scrollY <= dirty.ey then - term.setCursorPos(1 - scrollX, dy) - term.clearLine() - writeHighlighted(sLine, dy + scrollY) + page.editor:clearLine(dy) + writeHighlighted(sLine, dy + scrollY, dy) end else - term.setCursorPos(1 - scrollX, dy) - term.clearLine() + page.editor:clearLine(dy) end end end -- Draw status - if #sStatus > 0 then - if isError then - term.setTextColor(colors.white) - term.setBackgroundColor(color.errorBackground) - else - term.setTextColor(color.highlightColor) - term.setBackgroundColor(colors.gray) - end - term.setCursorPos(1, h) - term.clearLine() - term.write(string.format(' %s ', sStatus)) + if #sStatus == 0 then + page.statusBar:setValue('general', '') + page.statusBar:draw() end if not (w < 32 and #sStatus > 0) then - local modifiedIndicator = ' ' - if undo.chain[1] then + local modifiedIndicator = '' + if undo.chain[#undo.chain] ~= lastSave then modifiedIndicator = '*' end - local str = string.format(' %d:%d %s', + local str = string.format(' %d:%d%s', y, x, modifiedIndicator) - term.setTextColor(color.highlightColor) - term.setBackgroundColor(colors.gray) - term.setCursorPos(w - #str + 1, h) - term.write(str) + + page.statusBar:setValue('pos', str) + page.statusBar.columns[2].width = #str + page.statusBar:adjustWidth() + page.statusBar:draw() end - term.setTextColor(color.cursorColor) - term.setCursorPos(x - scrollX, y - scrollY) + if page.editor.focused then + page.editor:setCursorPos(x - scrollX, y - scrollY) + end dirty.y, dirty.ey = 0, 0 if #sStatus > 0 then sStatus = '' - dirty.y = scrollY + h - dirty.ey = dirty.y end - isError = false end local function nextWord(line, cx) @@ -407,52 +689,12 @@ local function nextWord(line, cx) end end -local function hacky_read() - local _oldSetCursorPos = term.setCursorPos - local _oldGetCursorPos = term.getCursorPos - - term.setCursorPos = function(cx) - return _oldSetCursorPos(cx, h) - end - term.getCursorPos = function() - local cx = _oldGetCursorPos() - return cx, 1 - end - - local s, m = pcall(function() return _G.read() end) - term.setCursorPos = _oldSetCursorPos - term.getCursorPos = _oldGetCursorPos - if s then - return m - end - if m == 'Terminated' then - bRunning = false - end - return '' -end - -local actions -local __actions = { - - input = function(prompt) - term.setTextColor(color.highlightColor) - term.setBackgroundColor(colors.gray) - term.setCursorPos(1, h) - term.clearLine() - term.write(prompt) - local str = hacky_read() - term.setCursorBlink(true) - input:reset() - term.setCursorPos(x - scrollX, y - scrollY) - actions.dirty_line(scrollY + h) - return str - end, - +actions = { undo = function() local last = table.remove(undo.chain) if last then undo.active = true - actions[last.action](unpack(last.args)) + actions[last.action](table.unpack(last.args)) undo.active = false else setStatus('Already at oldest change') @@ -461,7 +703,7 @@ local __actions = { addUndo = function(entry) local last = undo.chain[#undo.chain] - if last and last.action == entry.action then + if last and last.action == entry.action and not last.saved then if last.action == 'deleteText' then if last.args[3] == entry.args[1] and last.args[4] == entry.args[2] then @@ -537,18 +779,8 @@ local __actions = { setStatus('refreshed') end, - menu = function() - setStatus(messages.menu) - mark.continue = mark.active - end, - goto_line = function() - local lineNo = tonumber(actions.input('Line: ')) - if lineNo then - actions.go_to(1, lineNo) - else - setStatus('Invalid line number') - end + page.gotoLine:show() end, find = function(pattern, sx) @@ -581,36 +813,44 @@ local __actions = { end, find_prompt = function() - local text = actions.input('/') - if #text > 0 then - searchPattern = text:lower() - if searchPattern then - actions.unmark() - actions.find(searchPattern, x) + page.search:show() + end, + + save = function(filename) + filename = filename or fileInfo.abspath + if fs.isReadOnly(filename) then + setError("Access denied") + else + local ok = save(filename) + if ok then + lastSave = undo.chain[#undo.chain] + fileInfo = getFileInfo(filename) + if multishell then + multishell.setTitle(multishell.getCurrent(), fileInfo.path) + end + setStatus('"%s" %dL, %dC written', + fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) + return true + else + setError("Error saving to %s", filename) end end end, - save = function() - if bReadOnly then - setError("Access denied") - else - local ok = save(sPath) - if ok then - setStatus('"%s" %dL, %dC written', - fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) - else - setError("Error saving to %s", sPath) - end - end + save_as = function() + page.save_as:show() end, exit = function() - bRunning = false + if undo.chain[#undo.chain] ~= lastSave then + page.quit:show() + else + UI:quit() + end end, run = function() - input:reset() + --input:reset() local sTempPath = "/.temp" local ok = save(sTempPath) if ok then @@ -744,6 +984,26 @@ local __actions = { actions.mark_finish() end, + mark_current_word = function(cx, cy) + local index = 1 + actions.go_to(cx, cy) + while true do + local s, e = tLines[y]:find('%w+', index) + if not s or s - 1 > x then + break + end + if x >= s and x <= e then + x = s + actions.mark_begin() + x = e + 1 + actions.mark_finish() + x, y = cx, cy + break + end + index = e + 1 + end + end, + mark_backword = function() actions.mark_begin() actions.backword() @@ -791,8 +1051,8 @@ local __actions = { if screenY < 1 then scrollY = y - 1 actions.dirty_all() - elseif screenY > h - 1 then - scrollY = y - (h - 1) + elseif screenY > h then + scrollY = y - h actions.dirty_all() end end, @@ -828,11 +1088,11 @@ local __actions = { end, pageUp = function() - actions.go_to(x, y - (h - 1)) + actions.go_to(x, y - h) end, pageDown = function() - actions.go_to(x, y + (h - 1)) + actions.go_to(x, y + h) end, home = function() @@ -1059,54 +1319,19 @@ local __actions = { end, scroll_down = function() - local nMaxScroll = #tLines - (h-1) + local nMaxScroll = #tLines - h if scrollY < nMaxScroll then scrollY = scrollY + 1 actions.dirty_all() end mark.continue = mark.active end, -} -actions = __actions + redraw = function() + redraw() + end, -load(sPath) -term.setCursorBlink(true) -redraw() - -while bRunning do - local sEvent, param, param2, param3 = os.pullEventRaw() - local action - - if sEvent == 'terminate' then - action = 'exit' - elseif sEvent == 'multishell_focus' then -- opus only event - input:reset() - elseif sEvent == "mouse_click" or - sEvent == 'mouse_drag' or - sEvent == 'mouse_up' or - sEvent == 'mouse_down' then - local ie = input:translate(sEvent, param, param2, param3) - if param3 < h or sEvent == 'mouse_drag' then - if ie.code then - action = keyMapping[ie.code] - param = param2 + scrollX - param2 = param3 + scrollY - end - end - else - local ie = input:translate(sEvent, param, param2) - if ie then - if ie.ch and #ie.ch == 1 then - action = keyMapping.char - param = ie.ch - else - action = keyMapping[ie.code] - end - end - end - - if action then + process = function(action, param, param2) if not actions[action] then error('Invaid action: ' .. action) end @@ -1115,9 +1340,7 @@ while bRunning do mark.continue = false actions[action](param, param2) - if action ~= 'menu' then - lastAction = action - end + lastAction = action if x ~= lastPos.x or y ~= lastPos.y then actions.setCursor() @@ -1126,19 +1349,27 @@ while bRunning do actions.unmark() end - redraw() + actions.redraw() + end, +} - elseif sEvent == "term_resize" then - w,h = term.getSize() - actions.setCursor(x, y) - actions.dirty_all() - redraw() - end +local tArgs = { ... } +if #tArgs == 0 then + error( "Usage: edit " ) end --- Cleanup -term.setBackgroundColor(colors.black) -term.setTextColor(colors.white) -term.clear() -term.setCursorBlink(false) -term.setCursorPos(1, 1) +-- Error checking +local sPath = shell.resolve(tArgs[1]) +if fs.exists(sPath) and fs.isDir(sPath) then + error( "Cannot edit a directory." ) +end + +load(tArgs[1]) + +if multishell then + multishell.setTitle(multishell.getCurrent(), fs.getName(sPath)) +end + +UI:setPage(page) +UI:start() + diff --git a/screenSaver/autorun/saver.lua b/screenSaver/autorun/saver.lua index 274b82f..db33bc6 100644 --- a/screenSaver/autorun/saver.lua +++ b/screenSaver/autorun/saver.lua @@ -11,7 +11,7 @@ if not multishell then end local config = Config.load('saver', { - enabled = true, + enabled = false, timeout = 60, random = true, specific = nil, -- 2.49.1 From f655cc5965f360955eab7df728966493c25ad2f6 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 3 Apr 2020 18:56:55 -0600 Subject: [PATCH 03/12] more tweaks --- common/edit.lua | 154 ++++++++++++++++-------------------------------- 1 file changed, 50 insertions(+), 104 deletions(-) diff --git a/common/edit.lua b/common/edit.lua index 31cb96d..90c213f 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -17,7 +17,6 @@ local tLines = { } local fileInfo local lastAction local actions -local sStatus = '' local lastSave local dirty = { y = 1, ey = h } local mark = { } @@ -26,29 +25,25 @@ local undo = { chain = { }, pointer = 0 } local complete = { } local page -h = h - 2 +h = h - 1 local color = { - textColor = '0', - keywordColor = '4', - commentColor = 'd', - stringColor = 'e', - bgColor = colors.black, - highlightColor = colors.orange, - cursorColor = colors.lime, - errorBackground = colors.red, + textColor = '0', + keywordColor = '4', + commentColor = 'd', + stringColor = 'e', + statusColor = colors.gray, + panelColor = colors.cyan, } if not term.isColor() then color = { - textColor = '0', - keywordColor = '8', - commentColor = '8', - stringColor = '8', - bgColor = colors.black, - highlightColor = colors.lightGray, - cursorColor = colors.white, - errorBackground = colors.gray, + textColor = '0', + keywordColor = '8', + commentColor = '8', + stringColor = '8', + statusColor = colors.white, + panelColor = colors.white, } end @@ -117,11 +112,12 @@ local keyMapping = { [ 'control-n' ] = 'find_next', -- misc --- [ 'control-g' ] = 'status', + [ 'control-i' ] = 'status', [ 'control-r' ] = 'refresh', } page = UI.Page { + backgroundColor = color.panelColor, menuBar = UI.MenuBar { transitionHint = 'slideLeft', buttons = { @@ -136,24 +132,28 @@ page = UI.Page { { text = 'Edit', dropdown = { { text = 'Cut ^x', event = 'menu_action', action = 'cut' }, { text = 'Copy ^c', event = 'menu_action', action = 'copy' }, - { text = 'Paste ^V', event = 'paste_internal' }, + { text = 'Paste ^V', event = 'menu_action', action = 'paste_internal' }, { spacer = true }, { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt', noFocus = true }, { text = 'Find Next ^n', event = 'menu_action', action = 'find_next' }, { spacer = true }, { text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line', noFocus = true }, { text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' }, - } }, }, + status = UI.Text { + textColor = color.statusColor, + x = -11, width = 10, + align = 'right', + }, }, gotoLine = UI.SlideOut { x = -15, height = 1, y = -2, noFill = true, close = UI.Button { x = -1, - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = color.panelColor, + backgroundFocusColor = color.panelColor, text = 'x', event = 'slide_hide', noPadding = true, @@ -197,8 +197,8 @@ page = UI.Page { noFill = true, close = UI.Button { x = -1, - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = color.panelColor, + backgroundFocusColor = color.panelColor, text = 'x', event = 'slide_hide', noPadding = true, @@ -247,8 +247,8 @@ page = UI.Page { noFill = true, close = UI.Button { x = -1, - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = color.panelColor, + backgroundFocusColor = color.panelColor, text = 'x', event = 'slide_hide', noPadding = true, @@ -296,8 +296,8 @@ page = UI.Page { noFill = true, close = UI.Button { x = -1, - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = color.panelColor, + backgroundFocusColor = color.panelColor, text = 'x', event = 'slide_hide', noPadding = true, @@ -309,19 +309,19 @@ page = UI.Page { save = UI.Button { x = 7, text = 'Yes', - backgroundColor = colors.cyan, + backgroundColor = color.panelColor, event = 'save_yes', }, quit = UI.Button { x = 13, text = 'No', - backgroundColor = colors.cyan, + backgroundColor = color.panelColor, event = 'save_no', }, cancel = UI.Button { x = 18, text = 'Cancel', - backgroundColor = colors.cyan, + backgroundColor = color.panelColor, event = 'save_cancel', }, disable = function(self) @@ -346,7 +346,7 @@ page = UI.Page { end, }, editor = UI.Window { - y = 2, ey = -2, + y = 2, backgroundColor = colors.black, transitionHint = 'slideRight', focus = function(self) @@ -402,25 +402,13 @@ page = UI.Page { end end, }, - statusBar = UI.StatusBar { - transitionHint = 'slideLeft', - backgroundColor = colors.gray, - columns = { - { key = 'general' }, - { key = 'pos', width = 6, fg = colors.orange }, - }, - }, + notification = UI.Notification { }, enable = function(self) UI.Page.enable(self) self:setFocus(page.editor) end, eventHandler = function(self, event) - if event.type == 'paste_internal' then - self:setFocus(page.editor) - os.queueEvent('clipboard_paste') - return true - - elseif event.type == 'menu_action' then + if event.type == 'menu_action' then actions.process(event.element.action) if not event.element.noFocus then -- hacky self:setFocus(self.editor) @@ -431,15 +419,6 @@ page = UI.Page { end, } -local messages = { - wrapped = 'search hit BOTTOM, continuing at TOP', -} -if w < 32 then - messages = { - wrapped = 'search wrapped', - } -end - local function getFileInfo(path) local abspath = shell.resolve(path) @@ -455,22 +434,16 @@ local function getFileInfo(path) else fi.isReadOnly = fs.isReadOnly(fi.abspath) end -_G._p = fi + return fi end local function setStatus(pattern, ...) - sStatus = string.format(pattern, ...) - page.statusBar.textColor = colors.white - page.statusBar:setValue('general', sStatus) - page.statusBar:draw() + page.notification:info(string.format(pattern, ...)) end local function setError(pattern, ...) - sStatus = string.format(pattern, ...) - page.statusBar.textColor = color.highlightColor - page.statusBar:setValue('general', sStatus) - page.statusBar:draw() + page.notification:error(string.format(pattern, ...)) end local function load(path) @@ -492,9 +465,6 @@ local function load(path) end local name = fileInfo.path - if w < 32 then - name = fs.getName(fileInfo.path) - end if fileInfo.isNew then if not fileInfo.dirExists then setStatus('"%s" [New DIRECTORY]', name) @@ -578,12 +548,7 @@ local function writeHighlighted(sLine, ny, dy) local function tryWrite(line, regex, fgcolor) local match = line:match(regex) if match then - local fg - if type(fgcolor) == "string" then - fg = fgcolor - else - fg = fgcolor(match) - end + local fg = type(fgcolor) == "string" and fgcolor or fgcolor(match) buffer.text = buffer.text .. match buffer.fg = buffer.fg .. string.rep(fg, #match) return line:sub(#match + 1) @@ -611,10 +576,7 @@ local function writeHighlighted(sLine, ny, dy) buffer.text = buffer.text .. '\183' if mark.active and ny >= mark.y and ny <= mark.ey then - local sx = 1 - if ny == mark.y then - sx = mark.x - end + local sx = ny == mark.y and mark.x or 1 local ex = #buffer.text if ny == mark.ey then ex = mark.ex @@ -646,35 +608,15 @@ local function redraw() end end - -- Draw status - if #sStatus == 0 then - page.statusBar:setValue('general', '') - page.statusBar:draw() - end - - if not (w < 32 and #sStatus > 0) then - local modifiedIndicator = '' - if undo.chain[#undo.chain] ~= lastSave then - modifiedIndicator = '*' - end - - local str = string.format(' %d:%d%s', - y, x, modifiedIndicator) - - page.statusBar:setValue('pos', str) - page.statusBar.columns[2].width = #str - page.statusBar:adjustWidth() - page.statusBar:draw() - end + local modifiedIndicator = undo.chain[#undo.chain] == lastSave and '' or '*' + page.menuBar.status.value = string.format(' %d:%d%s', y, x, modifiedIndicator) + page.menuBar.status:draw() if page.editor.focused then page.editor:setCursorPos(x - scrollX, y - scrollY) end dirty.y, dirty.ey = 0, 0 - if #sStatus > 0 then - sStatus = '' - end end local function nextWord(line, cx) @@ -703,7 +645,7 @@ actions = { addUndo = function(entry) local last = undo.chain[#undo.chain] - if last and last.action == entry.action and not last.saved then + if last and last.action == entry.action then if last.action == 'deleteText' then if last.args[3] == entry.args[1] and last.args[4] == entry.args[2] then @@ -790,10 +732,10 @@ actions = { if ny > nLines then ny = ny - nLines end - local nx = tLines[ny]:lower():find(pattern, sx) + local nx = tLines[ny]:lower():find(pattern, sx, true) if nx then if ny < y or ny == y and nx <= x then - setStatus(messages.wrapped) + setStatus('search hit BOTTOM, continuing at TOP') end actions.go_to(nx, ny) actions.mark_to(nx + #pattern, ny) @@ -1305,6 +1247,10 @@ actions = { end end, + paste_internal = function() + os.queueEvent('clipboard_paste') + end, + go_to = function(cx, cy) y = math.min(math.max(cy, 1), #tLines) x = math.min(math.max(cx, 1), #tLines[y] + 1) -- 2.49.1 From 0a7ec352cc7c76258c9531f52171d184377d415e Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sat, 4 Apr 2020 20:55:29 -0600 Subject: [PATCH 04/12] more editor work --- common/edit.lua | 223 ++++++++++++++++++++++++++------------------- common/etc/apps.db | 8 ++ 2 files changed, 136 insertions(+), 95 deletions(-) diff --git a/common/edit.lua b/common/edit.lua index 90c213f..e413221 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -23,7 +23,6 @@ local mark = { } local searchPattern local undo = { chain = { }, pointer = 0 } local complete = { } -local page h = h - 1 @@ -116,28 +115,31 @@ local keyMapping = { [ 'control-r' ] = 'refresh', } -page = UI.Page { +local page = UI.Page { backgroundColor = color.panelColor, menuBar = UI.MenuBar { transitionHint = 'slideLeft', buttons = { { text = 'File', dropdown = { + { text = 'New ', event = 'menu_action', action = 'file_new' }, + { text = 'Open ', event = 'menu_action', action = 'file_open' }, + { spacer = true }, { text = 'Save ^s', event = 'menu_action', action = 'save' }, - { text = 'Save As... ^S', event = 'menu_action', action = 'save_as', noFocus = true }, + { text = 'Save As... ^S', event = 'menu_action', action = 'save_as' }, { spacer = true }, { text = 'Run', event = 'menu_action', action = 'run' }, { spacer = true }, - { text = 'Quit ^q', event = 'menu_action', action = 'exit', noFocus = true }, + { text = 'Quit ^q', event = 'menu_action', action = 'exit' }, } }, { text = 'Edit', dropdown = { { text = 'Cut ^x', event = 'menu_action', action = 'cut' }, { text = 'Copy ^c', event = 'menu_action', action = 'copy' }, { text = 'Paste ^V', event = 'menu_action', action = 'paste_internal' }, { spacer = true }, - { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt', noFocus = true }, + { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt' }, { text = 'Find Next ^n', event = 'menu_action', action = 'find_next' }, { spacer = true }, - { text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line', noFocus = true }, + { text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line' }, { text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' }, } }, }, @@ -172,10 +174,6 @@ page = UI.Page { [ 'enter' ] = 'accept', }, }, - disable = function(self) - UI.SlideOut.disable(self) - self:setFocus(page.editor) - end, show = function(self) self.lineNo:reset() UI.SlideOut.show(self) @@ -217,10 +215,6 @@ page = UI.Page { [ 'enter' ] = 'accept', }, }, - disable = function(self) - UI.SlideOut.disable(self) - self:setFocus(page.editor) - end, show = function(self) self.search:markAll() UI.SlideOut.show(self) @@ -267,10 +261,6 @@ page = UI.Page { [ 'enter' ] = 'accept', }, }, - disable = function(self) - UI.SlideOut.disable(self) - self:setFocus(page.editor) - end, show = function(self) self.filename.value = fileInfo.abspath if self.filename.value then @@ -283,7 +273,7 @@ page = UI.Page { if event.type == 'accept' then local text = self.filename.value if text and #text > 0 then - actions.save(shell.resolve(text)) + actions.save('/' .. text) end self:hide() return true @@ -291,7 +281,7 @@ page = UI.Page { return UI.SlideOut.eventHandler(self, event) end, }, - quit = UI.SlideOut { + unsaved = UI.SlideOut { x = -26, height = 1, y = -2, noFill = true, close = UI.Button { @@ -306,13 +296,13 @@ page = UI.Page { x = 2, value = 'Save', }, - save = UI.Button { + yes = UI.Button { x = 7, text = 'Yes', backgroundColor = color.panelColor, event = 'save_yes', }, - quit = UI.Button { + no = UI.Button { x = 13, text = 'No', backgroundColor = color.panelColor, @@ -324,34 +314,52 @@ page = UI.Page { backgroundColor = color.panelColor, event = 'save_cancel', }, - disable = function(self) - UI.SlideOut.disable(self) - self:setFocus(page.editor) - end, - show = function(self) + show = function(self, action) + self.action = action UI.SlideOut.show(self) self:addTransition('slideLeft', { easing = 'outBounce' }) end, eventHandler = function(self, event) if event.type == 'save_yes' then if actions.save() then - UI:quit() + self:hide() + actions.process(self.action) end elseif event.type == 'save_no' then - UI:quit() + actions.process(self.action, true) + self:hide() elseif event.type == 'save_cancel' then self:hide() end return UI.SlideOut.eventHandler(self, event) end, }, + file_open = UI.FileSelect { + modal = true, + enable = function() end, + transitionHint = 'expandUp', + show = function(self) + UI.FileSelect.enable(self, fs.getDir(fileInfo.abspath)) + self:focusFirst() + self:draw() + end, + eventHandler = function(self, event) + if event.type == 'select_cancel' then + self:disable() + elseif event.type == 'select_file' then + self:disable() + actions.process('open', event.file) + end + return UI.FileSelect.eventHandler(self, event) + end, + }, editor = UI.Window { y = 2, backgroundColor = colors.black, transitionHint = 'slideRight', focus = function(self) if self.focused then - page.editor:setCursorPos(x - scrollX, y - scrollY) + self:setCursorPos(x - scrollX, y - scrollY) self:setCursorBlink(true) else self:setCursorBlink(false) @@ -380,6 +388,7 @@ page = UI.Page { elseif ie.code == "mouse_click" or ie.code == 'mouse_drag' or --ie.code == 'mouse_up' or + ie.code == 'shift-mouse_click' or ie.code == 'mouse_down' or ie.code == 'mouse_doubleclick' then @@ -405,14 +414,17 @@ page = UI.Page { notification = UI.Notification { }, enable = function(self) UI.Page.enable(self) - self:setFocus(page.editor) + self:setFocus(self.editor) + end, + checkFocus = function(self) + if not self.focused or not self.focused.enabled then + -- if no current focus, set it to the editor + self:setFocus(self.editor) + end end, eventHandler = function(self, event) if event.type == 'menu_action' then actions.process(event.element.action) - if not event.element.noFocus then -- hacky - self:setFocus(self.editor) - end return true end return UI.Page.eventHandler(self, event) @@ -435,6 +447,10 @@ local function getFileInfo(path) fi.isReadOnly = fs.isReadOnly(fi.abspath) end + if multishell then + multishell.setTitle(multishell.getCurrent(), fs.getName(fi.path)) + end + return fi end @@ -446,40 +462,6 @@ local function setError(pattern, ...) page.notification:error(string.format(pattern, ...)) end -local function load(path) - fileInfo = getFileInfo(path) - - tLines = {} - if fs.exists(fileInfo.abspath) then - local file = io.open(fileInfo.abspath, "r") - local sLine = file:read() - while sLine do - table.insert(tLines, sLine) - sLine = file:read() - end - file:close() - end - - if #tLines == 0 then - table.insert(tLines, '') - end - - local name = fileInfo.path - if fileInfo.isNew then - if not fileInfo.dirExists then - setStatus('"%s" [New DIRECTORY]', name) - else - setStatus('"%s" [New File]', name) - end - elseif fileInfo.isReadOnly then - setStatus('"%s" [readonly] %dL, %dC', - name, #tLines, fs.getSize(fileInfo.abspath)) - else - setStatus('"%s" %dL, %dC', - name, #tLines, fs.getSize(fileInfo.abspath)) - end -end - local function save( _sPath ) -- Create intervening folder local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() ) @@ -758,6 +740,76 @@ actions = { page.search:show() end, + file_open = function(force) + if not force and undo.chain[#undo.chain] ~= lastSave then + page.unsaved:show('file_open') + else + page.file_open:show('file_open') + end + end, + + file_new = function(force) + if not force and undo.chain[#undo.chain] ~= lastSave then + page.unsaved:show('file_new') + else + actions.open('/untitled.txt') + end + end, + + open = function(filename) + if not actions.load(filename) then + setError('Unable to load file') + end + end, + + load = function(path) + if fs.exists(path) and fs.isDir(path) then + return false + end + fileInfo = getFileInfo(path) + + x, y = 1, 1 + scrollX, scrollY = 0, 0 + lastPos = { x = 1, y = 1 } + lastSave = nil + dirty = { y = 1, ey = h } + mark = { } + undo = { chain = { }, pointer = 0 } + complete = { } + + tLines = { } + if fs.exists(fileInfo.abspath) then + local file = io.open(fileInfo.abspath, "r") + local sLine = file:read() + while sLine do + table.insert(tLines, sLine) + sLine = file:read() + end + file:close() + end + + if #tLines == 0 then + table.insert(tLines, '') + end + + local name = fileInfo.path + if fileInfo.isNew then + if not fileInfo.dirExists then + setStatus('"%s" [New DIRECTORY]', name) + else + setStatus('"%s" [New File]', name) + end + elseif fileInfo.isReadOnly then + setStatus('"%s" [readonly] %dL, %dC', + name, #tLines, fs.getSize(fileInfo.abspath)) + else + setStatus('"%s" %dL, %dC', + name, #tLines, fs.getSize(fileInfo.abspath)) + end + + return true + end, + save = function(filename) filename = filename or fileInfo.abspath if fs.isReadOnly(filename) then @@ -767,9 +819,6 @@ actions = { if ok then lastSave = undo.chain[#undo.chain] fileInfo = getFileInfo(filename) - if multishell then - multishell.setTitle(multishell.getCurrent(), fileInfo.path) - end setStatus('"%s" %dL, %dC written', fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) return true @@ -783,9 +832,9 @@ actions = { page.save_as:show() end, - exit = function() - if undo.chain[#undo.chain] ~= lastSave then - page.quit:show() + exit = function(force) + if not force and undo.chain[#undo.chain] ~= lastSave then + page.unsaved:show('exit') else UI:quit() end @@ -810,12 +859,9 @@ actions = { end, status = function() - local modified = '' - if undo.chain[1] then - modified = '[Modified] ' - end + local modified = undo.chain[#undo.chain] == lastSave and '' or '[Modified] ' setStatus('"%s" %s%d lines --%d%%--', - fileInfo.path, modified, #tLines, + fileInfo.abspath, modified, #tLines, math.floor((y - 1) / (#tLines - 1) * 100)) end, @@ -1299,23 +1345,10 @@ actions = { end, } -local tArgs = { ... } -if #tArgs == 0 then - error( "Usage: edit " ) -end - --- Error checking -local sPath = shell.resolve(tArgs[1]) -if fs.exists(sPath) and fs.isDir(sPath) then - error( "Cannot edit a directory." ) -end - -load(tArgs[1]) - -if multishell then - multishell.setTitle(multishell.getCurrent(), fs.getName(sPath)) +local args = { ... } +if not actions.load(args[1] and args[1] or 'untitled.txt') then + error('Error opening file') end UI:setPage(page) UI:start() - diff --git a/common/etc/apps.db b/common/etc/apps.db index f434ef9..da88fad 100644 --- a/common/etc/apps.db +++ b/common/etc/apps.db @@ -65,4 +65,12 @@ run = "SoundPlayer", iconExt = "\030 \031 \128\0307\159\129\030 \0317\149\0310\144\0300\031 \155\030 \0310\137\144\010\0307\0317\128\128\128\030 \149\0300\031 \149\030 \128\0310\149\0300\031 \149\010\030 \031 \128\0317\130\0307\031 \144\030 \0317\149\0310\129\134\152\129", }, + [ "464c4ffd019e1e9691dcf0537c797353ef2b1c1d4833d3d463e5b74ae4547344" ] = { + title = "Editor", + category = "Apps", + run = "edit", + iconExt = "7\ +¨¨¨¨f€0¨\ +¨¨f€0¨¨f€", + } } -- 2.49.1 From 1cbe87033df0b0ed3aebb8a35a098be7a2474ea2 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Mon, 6 Apr 2020 00:10:22 -0600 Subject: [PATCH 05/12] completions + refactor --- common/edit.lua | 236 +++++++++++++++++++----------------------------- 1 file changed, 92 insertions(+), 144 deletions(-) diff --git a/common/edit.lua b/common/edit.lua index e413221..e689700 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -15,14 +15,12 @@ local scrollY = 0 local lastPos = { x = 1, y = 1 } local tLines = { } local fileInfo -local lastAction local actions local lastSave local dirty = { y = 1, ey = h } local mark = { } local searchPattern local undo = { chain = { }, pointer = 0 } -local complete = { } h = h - 1 @@ -132,8 +130,8 @@ local page = UI.Page { { text = 'Quit ^q', event = 'menu_action', action = 'exit' }, } }, { text = 'Edit', dropdown = { - { text = 'Cut ^x', event = 'menu_action', action = 'cut' }, - { text = 'Copy ^c', event = 'menu_action', action = 'copy' }, + { text = 'Cut ^x', event = 'menu_action', action = 'cut' }, + { text = 'Copy ^c', event = 'menu_action', action = 'copy' }, { text = 'Paste ^V', event = 'menu_action', action = 'paste_internal' }, { spacer = true }, { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt' }, @@ -142,28 +140,19 @@ local page = UI.Page { { text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line' }, { text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' }, } }, + { text = 'Code', dropdown = { + { text = 'Complete ^space', event = 'menu_action', action = 'autocomplete' }, + } }, }, status = UI.Text { textColor = color.statusColor, - x = -11, width = 10, + x = -9, width = 9, align = 'right', }, }, - gotoLine = UI.SlideOut { - x = -15, height = 1, y = -2, - noFill = true, - close = UI.Button { - x = -1, - backgroundColor = color.panelColor, - backgroundFocusColor = color.panelColor, - text = 'x', - event = 'slide_hide', - noPadding = true, - }, - label = UI.Text { - x = 2, - value = 'Line', - }, + gotoLine = UI.MiniSlideOut { + x = -15, y = -2, + label = 'Line', lineNo = UI.TextEntry { x = 7, width = 7, limit = 5, @@ -176,8 +165,7 @@ local page = UI.Page { }, show = function(self) self.lineNo:reset() - UI.SlideOut.show(self) - self:addTransition('slideLeft', { easing = 'outBounce' }) + UI.MiniSlideOut.show(self) end, eventHandler = function(self, event) if event.type == 'accept' then @@ -187,24 +175,12 @@ local page = UI.Page { self:hide() return true end - return UI.SlideOut.eventHandler(self, event) + return UI.MiniSlideOut.eventHandler(self, event) end, }, - search = UI.SlideOut { - x = -20, height = 1, y = -2, - noFill = true, - close = UI.Button { - x = -1, - backgroundColor = color.panelColor, - backgroundFocusColor = color.panelColor, - text = 'x', - event = 'slide_hide', - noPadding = true, - }, - label = UI.Text { - x = 2, - value = 'Find', - }, + search = UI.MiniSlideOut { + x = -20, y = -2, + label = 'Find', search = UI.TextEntry { x = 7, width = 12, limit = 512, @@ -217,8 +193,7 @@ local page = UI.Page { }, show = function(self) self.search:markAll() - UI.SlideOut.show(self) - self:addTransition('slideLeft', { easing = 'outBounce' }) + UI.MiniSlideOut.show(self) end, eventHandler = function(self, event) if event.type == 'accept' then @@ -233,24 +208,12 @@ local page = UI.Page { self:hide() return true end - return UI.SlideOut.eventHandler(self, event) + return UI.MiniSlideOut.eventHandler(self, event) end, }, - save_as = UI.SlideOut { - x = -24, height = 1, y = -2, - noFill = true, - close = UI.Button { - x = -1, - backgroundColor = color.panelColor, - backgroundFocusColor = color.panelColor, - text = 'x', - event = 'slide_hide', - noPadding = true, - }, - label = UI.Text { - x = 2, - value = 'Save', - }, + save_as = UI.MiniSlideOut { + x = -24, y = -2, + label = 'Save', filename = UI.TextEntry { x = 7, width = 16, limit = 512, @@ -263,11 +226,8 @@ local page = UI.Page { }, show = function(self) self.filename.value = fileInfo.abspath - if self.filename.value then - self.filename:setPosition(#self.filename.value) - end - UI.SlideOut.show(self) - self:addTransition('slideLeft', { easing = 'outBounce' }) + self.filename:setPosition(#self.filename.value) + UI.MiniSlideOut.show(self) end, eventHandler = function(self, event) if event.type == 'accept' then @@ -278,70 +238,45 @@ local page = UI.Page { self:hide() return true end - return UI.SlideOut.eventHandler(self, event) + return UI.MiniSlideOut.eventHandler(self, event) end, }, - unsaved = UI.SlideOut { - x = -26, height = 1, y = -2, - noFill = true, - close = UI.Button { - x = -1, - backgroundColor = color.panelColor, - backgroundFocusColor = color.panelColor, - text = 'x', - event = 'slide_hide', - noPadding = true, - }, - label = UI.Text { - x = 2, - value = 'Save', - }, - yes = UI.Button { - x = 7, - text = 'Yes', - backgroundColor = color.panelColor, - event = 'save_yes', - }, - no = UI.Button { - x = 13, - text = 'No', - backgroundColor = color.panelColor, - event = 'save_no', - }, + unsaved = UI.Question { + x = -25, y = -2, + label = 'Save', cancel = UI.Button { - x = 18, + x = 16, text = 'Cancel', backgroundColor = color.panelColor, - event = 'save_cancel', + event = 'question_cancel', }, show = function(self, action) self.action = action - UI.SlideOut.show(self) - self:addTransition('slideLeft', { easing = 'outBounce' }) + UI.MiniSlideOut.show(self) end, eventHandler = function(self, event) - if event.type == 'save_yes' then + if event.type == 'question_yes' then if actions.save() then self:hide() actions.process(self.action) end - elseif event.type == 'save_no' then + elseif event.type == 'question_no' then actions.process(self.action, true) self:hide() - elseif event.type == 'save_cancel' then + elseif event.type == 'question_cancel' then self:hide() end - return UI.SlideOut.eventHandler(self, event) + return UI.MiniSlideOut.eventHandler(self, event) end, }, file_open = UI.FileSelect { modal = true, enable = function() end, - transitionHint = 'expandUp', show = function(self) UI.FileSelect.enable(self, fs.getDir(fileInfo.abspath)) self:focusFirst() self:draw() + self:addTransition('expandUp', { easing = 'outBounce', ticks = 12 }) end, eventHandler = function(self, event) if event.type == 'select_cancel' then @@ -353,6 +288,49 @@ local page = UI.Page { return UI.FileSelect.eventHandler(self, event) end, }, + completions = UI.SlideOut { + x = -12, y = 2, + transitionHint = 'slideLeft', + grid = UI.Grid { + x = 2, y = 2, ey = -2, + columns = { + { key = 'text', heading = 'Completion' }, + }, + accelerators = { + [ ' ' ] = 'down', + backspace = 'slide_hide', + } + }, + show = function(self, values) + local m = 12 + for _, v in pairs(values) do + m = #v.text > m and #v.text or m + end + m = m + 3 + m = m > self.parent.width and self.parent.width or m + self.ox = -m + self:resize() + self.grid:setValues(values) + self.grid:setIndex(1) + UI.SlideOut.show(self) + end, + cancel = UI.Button { + y = -1, x = -9, + text = 'Cancel', + backgroundColor = colors.black, + backgroundFocusColor = colors.black, + textColor = colors.lightGray, + event = 'slide_hide', + }, + eventHandler = function(self, event) + if event.type == 'grid_select' then + actions.process('insertText', x, y, event.selected.complete) + self:hide() + return true + end + return UI.SlideOut.eventHandler(self, event) + end, + }, editor = UI.Window { y = 2, backgroundColor = colors.black, @@ -590,7 +568,7 @@ local function redraw() end end - local modifiedIndicator = undo.chain[#undo.chain] == lastSave and '' or '*' + local modifiedIndicator = undo.chain[#undo.chain] == lastSave and ' ' or '*' page.menuBar.status.value = string.format(' %d:%d%s', y, x, modifiedIndicator) page.menuBar.status:draw() @@ -648,52 +626,24 @@ actions = { end, autocomplete = function() - if lastAction ~= 'autocomplete' or not complete.results then - local sLine = tLines[y]:sub(1, x - 1) - local nStartPos = sLine:find("[a-zA-Z0-9_%.]+$") - if nStartPos then - sLine = sLine:sub(nStartPos) - end - if #sLine > 0 then - complete.results = textutils.complete(sLine) - else - complete.results = { } - end - complete.index = 0 - complete.x = x - end + local sLine = tLines[y]:sub(1, x - 1):match("[a-zA-Z0-9_%.]+$") + local results = sLine and textutils.complete(sLine, _ENV) or { } - if #complete.results == 0 then + if #results == 0 then setError('No completions available') - elseif #complete.results == 1 then - actions.insertText(x, y, complete.results[1]) - complete.results = nil + elseif #results == 1 then + actions.insertText(x, y, results[1]) - elseif #complete.results > 1 then - local prefix = complete.results[1] - for n = 1, #complete.results do - local result = complete.results[n] - while #prefix > 0 do - if result:find(prefix, 1, true) == 1 then - break - end - prefix = prefix:sub(1, #prefix - 1) - end - end - if #prefix > 0 then - actions.insertText(x, y, prefix) - complete.results = nil - else - if complete.index > 0 then - actions.deleteText(complete.x, y, complete.x + #complete.results[complete.index], y) - end - complete.index = complete.index + 1 - if complete.index > #complete.results then - complete.index = 1 - end - actions.insertText(complete.x, y, complete.results[complete.index]) + elseif #results > 1 then + local prefix = sLine:match('^.+%.(.*)$') or sLine + for i = 1, #results do + results[i] = { + text = prefix .. results[i], + complete = results[i], + } end + page.completions:show(results) end end, @@ -775,7 +725,6 @@ actions = { dirty = { y = 1, ey = h } mark = { } undo = { chain = { }, pointer = 0 } - complete = { } tLines = { } if fs.exists(fileInfo.abspath) then @@ -1323,7 +1272,7 @@ actions = { redraw() end, - process = function(action, param, param2) + process = function(action, ...) if not actions[action] then error('Invaid action: ' .. action) end @@ -1331,8 +1280,7 @@ actions = { local wasMarking = mark.continue mark.continue = false - actions[action](param, param2) - lastAction = action + actions[action](...) if x ~= lastPos.x or y ~= lastPos.y then actions.setCursor() -- 2.49.1 From 3321866ba371aa594c3c5ec4c64d73aa2292b65c Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 9 Apr 2020 16:08:04 -0600 Subject: [PATCH 06/12] cleanup + editor additions --- ccemux/etc/apps.db | 4 +- common/edit.lua | 137 +++++++++++++++++++++++++++++++++++---- common/etc/apps.db | 7 +- examples/.package | 6 -- examples/grid.lua | 44 ------------- milo/MiloRemote.lua | 2 +- milo/apis/fuzzyMatch.lua | 19 ------ milo/core/listing.lua | 2 +- 8 files changed, 133 insertions(+), 88 deletions(-) delete mode 100644 examples/.package delete mode 100644 examples/grid.lua delete mode 100644 milo/apis/fuzzyMatch.lua diff --git a/ccemux/etc/apps.db b/ccemux/etc/apps.db index 081f9f7..d94fb3d 100644 --- a/ccemux/etc/apps.db +++ b/ccemux/etc/apps.db @@ -1,10 +1,10 @@ { - [ "emu_config" ] = { + [ "87e89abb4c1c551fe08d355d097f18b8de78edca5f556997085681662fce8eed" ] = { title = "Config", category = "CCEmuX", run = "emu config", }, - [ "emu_data" ] = { + [ "cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b3cdf79496dc442d52b8dd528" ] = { title = "Data", category = "CCEmuX", run = "emu data", diff --git a/common/edit.lua b/common/edit.lua index e689700..3c6f667 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -1,4 +1,5 @@ -local UI = require('opus.ui') +local fuzzy = require('opus.fuzzy') +local UI = require('opus.ui') local colors = _G.colors local fs = _G.fs @@ -29,8 +30,6 @@ local color = { keywordColor = '4', commentColor = 'd', stringColor = 'e', - statusColor = colors.gray, - panelColor = colors.cyan, } if not term.isColor() then @@ -39,8 +38,6 @@ if not term.isColor() then keywordColor = '8', commentColor = '8', stringColor = '8', - statusColor = colors.white, - panelColor = colors.white, } end @@ -53,7 +50,6 @@ local keyMapping = { pageUp = 'pageUp', [ 'control-b' ] = 'pageUp', pageDown = 'pageDown', --- [ 'control-f' ] = 'pageDown', home = 'home', [ 'end' ] = 'toend', [ 'control-home' ] = 'top', @@ -95,13 +91,13 @@ local keyMapping = { -- copy/paste [ 'control-x' ] = 'cut', [ 'control-c' ] = 'copy', --- [ 'control-shift-paste' ] = 'paste_internal', -- file [ 'control-s' ] = 'save', [ 'control-S' ] = 'save_as', [ 'control-q' ] = 'exit', [ 'control-enter' ] = 'run', + [ 'control-p' ] = 'quick_open', -- search [ 'control-f' ] = 'find_prompt', @@ -114,19 +110,17 @@ local keyMapping = { } local page = UI.Page { - backgroundColor = color.panelColor, menuBar = UI.MenuBar { transitionHint = 'slideLeft', buttons = { { text = 'File', dropdown = { { text = 'New ', event = 'menu_action', action = 'file_new' }, { text = 'Open ', event = 'menu_action', action = 'file_open' }, + { text = 'Quick Open... ^p', event = 'menu_action', action = 'quick_open' }, { spacer = true }, { text = 'Save ^s', event = 'menu_action', action = 'save' }, { text = 'Save As... ^S', event = 'menu_action', action = 'save_as' }, { spacer = true }, - { text = 'Run', event = 'menu_action', action = 'run' }, - { spacer = true }, { text = 'Quit ^q', event = 'menu_action', action = 'exit' }, } }, { text = 'Edit', dropdown = { @@ -142,10 +136,11 @@ local page = UI.Page { } }, { text = 'Code', dropdown = { { text = 'Complete ^space', event = 'menu_action', action = 'autocomplete' }, + { text = 'Run ^enter', event = 'menu_action', action = 'run' }, } }, }, status = UI.Text { - textColor = color.statusColor, + textColor = colors.gray, x = -9, width = 9, align = 'right', }, @@ -247,7 +242,7 @@ local page = UI.Page { cancel = UI.Button { x = 16, text = 'Cancel', - backgroundColor = color.panelColor, + backgroundColor = UI.colors.primary, event = 'question_cancel', }, show = function(self, action) @@ -288,6 +283,107 @@ local page = UI.Page { return UI.FileSelect.eventHandler(self, event) end, }, + quick_open = UI.SlideOut { + filter_entry = UI.TextEntry { + x = 2, y = 2, ex = -2, + limit = 256, + shadowText = 'File name', + accelerators = { + [ 'enter' ] = 'accept', + [ 'up' ] = 'grid_up', + [ 'down' ] = 'grid_down', + }, + }, + grid = UI.ScrollingGrid { + x = 2, y = 4, ex = -2, ey = -4, + sortColumn = 'name', + columns = { + { heading = 'Name', key = 'name' }, + { heading = 'Dir', key = 'dir' }, + }, + accelerators = { + grid_select = 'accept', + }, + }, + cancel = UI.Button { + x = -9, y = -2, + text = 'Cancel', + event = 'quick_cancel', + }, + apply_filter = function(self, filter) + local t = { } + if filter then + filter = filter:lower() + self.grid.sortColumn = 'score' + self.grid.inverseSort = true + + for _,v in pairs(self.listing) do + v.score = fuzzy(v.lname, filter) + if v.score then + table.insert(t, v) + end + end + else + self.grid.sortColumn = 'name' + self.grid.inverseSort = false + t = self.listing + end + + self.grid:setValues(t) + self.grid:update() + self.grid:setIndex(1) + end, + show = function(self) + local listing = { } + local function recurse(dir) + local files = fs.native.list(dir) + for _,f in ipairs(files) do + local fullName = fs.combine(dir, f) + if fs.native.isDir(fullName) then + recurse(fullName) + else + table.insert(listing, { + name = f, + dir = dir, + lname = f:lower(), + fullName = '/' .. fullName, + }) + end + end + end + recurse('') + self.listing = listing + self:apply_filter() + self.filter_entry:reset() + UI.SlideOut.show(self) + end, + eventHandler = function(self, event) + if event.type == 'grid_up' then + self.grid:emit({ type = 'scroll_up' }) + + elseif event.type == 'grid_down' then + self.grid:emit({ type = 'scroll_down' }) + + elseif event.type == 'accept' then + local sel = self.grid:getSelected() + if sel then + actions.process('open', sel.fullName) + self:hide() + end + + elseif event.type == 'quick_cancel' then + self:hide() + + elseif event.type == 'text_change' then + self:apply_filter(event.text) + self.grid:draw() + + else + return UI.SlideOut.eventHandler(self, event) + end + return true + end, + }, completions = UI.SlideOut { x = -12, y = 2, transitionHint = 'slideLeft', @@ -690,11 +786,19 @@ actions = { page.search:show() end, + quick_open = function(force) + if not force and undo.chain[#undo.chain] ~= lastSave then + page.unsaved:show('quick_open') + else + page.quick_open:show() + end + end, + file_open = function(force) if not force and undo.chain[#undo.chain] ~= lastSave then page.unsaved:show('file_open') else - page.file_open:show('file_open') + page.file_open:show() end end, @@ -1299,4 +1403,9 @@ if not actions.load(args[1] and args[1] or 'untitled.txt') then end UI:setPage(page) -UI:start() +local s, m = pcall(function() UI:start() end) +if not s then + actions.save('/crash.txt') + print('Editor has crashed. File saved as /crash.txt') + error(m) +end diff --git a/common/etc/apps.db b/common/etc/apps.db index da88fad..d8608bb 100644 --- a/common/etc/apps.db +++ b/common/etc/apps.db @@ -72,5 +72,10 @@ iconExt = "7\ ¨¨¨¨f€0¨\ ¨¨f€0¨¨f€", - } + }, + [ "3f00927a719345edd4a8316599d3b328857987547f8884306861161ffa09647e" ] = { + title = "Write", + category = "Apps", + run = "write", + }, } diff --git a/examples/.package b/examples/.package deleted file mode 100644 index da8c112..0000000 --- a/examples/.package +++ /dev/null @@ -1,6 +0,0 @@ -{ - title = 'Example programs for coding in Opus', - repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/examples', - description = [[Starter/example programs for creating Opus programs.]], - license = 'MIT', -} diff --git a/examples/grid.lua b/examples/grid.lua deleted file mode 100644 index b979a87..0000000 --- a/examples/grid.lua +++ /dev/null @@ -1,44 +0,0 @@ -local UI = require('opus.ui') - -local page = UI.Page { - menuBar = UI.MenuBar { - buttons = { - { text = 'Shuffle', event = 'shuffle' }, - { text = 'Clear', event = 'clear', }, - } - }, - grid = UI.ScrollingGrid { - y = 2, ey = -2, - values = { - { col = 'column1', value = 'value1' }, - { col = 'column2', value = 'value2' }, - { col = 'column3', value = 'value3' }, - }, - columns = { - { heading = 'HDR1', key = 'col' }, - { heading = 'HDR2', key = 'value' }, - } - }, - statusBar = UI.StatusBar { }, -} - -function page:eventHandler(event) - if event.type == 'grid_select' then - self.statusBar:setStatus('Selected: ' .. event.selected.value) - - elseif event.type == 'shuffle' then - for _,v in pairs(self.grid.values) do - v.col = 'column' .. math.random(1,3) - end - self.grid:update() - self.grid:draw() - - elseif event.type == 'clear' then - self.grid:setValues({ }) - self.grid:draw() - end - return UI.Page.eventHandler(self, event) -end - -UI:setPage(page) -UI:pullEvents() diff --git a/milo/MiloRemote.lua b/milo/MiloRemote.lua index 6644a5b..c2dc4f1 100644 --- a/milo/MiloRemote.lua +++ b/milo/MiloRemote.lua @@ -1,6 +1,6 @@ local Config = require('opus.config') local Event = require('opus.event') -local fuzzy = require('milo.fuzzyMatch') +local fuzzy = require('opus.fuzzy') local Sound = require('opus.sound') local Socket = require('opus.socket') local sync = require('opus.sync').sync diff --git a/milo/apis/fuzzyMatch.lua b/milo/apis/fuzzyMatch.lua deleted file mode 100644 index 7a6082d..0000000 --- a/milo/apis/fuzzyMatch.lua +++ /dev/null @@ -1,19 +0,0 @@ --- Based on Squid's fuzzy search --- https://github.com/SquidDev-CC/artist/blob/vnext/artist/lib/match.lua --- --- not very fuzzy anymore - -local SCORE_WEIGHT = 1000 -local LEADING_LETTER_PENALTY = -3 -local LEADING_LETTER_PENALTY_MAX = -9 - -local _find = string.find -local _max = math.max - -return function(str, pattern) - local start = _find(str, pattern, 1, true) - if start then - -- All letters before the current one are considered leading, so add them to our penalty - return SCORE_WEIGHT + _max(LEADING_LETTER_PENALTY * (start - 1), LEADING_LETTER_PENALTY_MAX) - end -end diff --git a/milo/core/listing.lua b/milo/core/listing.lua index b19b4d2..994ceba 100644 --- a/milo/core/listing.lua +++ b/milo/core/listing.lua @@ -1,6 +1,6 @@ local Craft = require('milo.craft2') local Event = require('opus.event') -local fuzzy = require('milo.fuzzyMatch') +local fuzzy = require('opus.fuzzy') local Milo = require('milo') local Sound = require('opus.sound') local UI = require('opus.ui') -- 2.49.1 From 569dd5572d0018c056dd1399083f1d6273e695bc Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 10 Apr 2020 22:51:56 -0600 Subject: [PATCH 07/12] cleanup + undo overhaul --- common/edit.lua | 343 ++++++++++++++++++++++-------------------------- 1 file changed, 157 insertions(+), 186 deletions(-) diff --git a/common/edit.lua b/common/edit.lua index 3c6f667..416d3da 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -1,5 +1,6 @@ local fuzzy = require('opus.fuzzy') local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors local fs = _G.fs @@ -9,6 +10,14 @@ local shell = _ENV.shell local term = _G.term local textutils = _G.textutils +local _format = string.format +local _rep = string.rep +local _sub = string.sub +local _concat = table.concat +local _insert = table.insert +local _remove = table.remove +local _unpack = table.unpack + local x, y = 1, 1 local w, h = term.getSize() local scrollX = 0 @@ -21,7 +30,7 @@ local lastSave local dirty = { y = 1, ey = h } local mark = { } local searchPattern -local undo = { chain = { }, pointer = 0 } +local undo = { chain = { } } h = h - 1 @@ -47,9 +56,9 @@ local keyMapping = { down = 'down', left = 'left', right = 'right', - pageUp = 'pageUp', - [ 'control-b' ] = 'pageUp', - pageDown = 'pageDown', + pageUp = 'page_up', + [ 'control-b' ] = 'page_up', + pageDown = 'page_down', home = 'home', [ 'end' ] = 'toend', [ 'control-home' ] = 'top', @@ -77,6 +86,7 @@ local keyMapping = { [ 'shift-home' ] = 'mark_home', [ 'mouse_down' ] = 'mark_anchor', [ 'mouse_doubleclick' ] = 'mark_current_word', + [ 'mouse_tripleclick' ] = 'mark_line', -- editing delete = 'delete', @@ -91,6 +101,7 @@ local keyMapping = { -- copy/paste [ 'control-x' ] = 'cut', [ 'control-c' ] = 'copy', + [ 'control-y' ] = 'paste_internal', -- file [ 'control-s' ] = 'save', @@ -126,7 +137,7 @@ local page = UI.Page { { text = 'Edit', dropdown = { { text = 'Cut ^x', event = 'menu_action', action = 'cut' }, { text = 'Copy ^c', event = 'menu_action', action = 'copy' }, - { text = 'Paste ^V', event = 'menu_action', action = 'paste_internal' }, + { text = 'Paste ^y,^V', event = 'menu_action', action = 'paste_internal' }, { spacer = true }, { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt' }, { text = 'Find Next ^n', event = 'menu_action', action = 'find_next' }, @@ -220,7 +231,7 @@ local page = UI.Page { }, }, show = function(self) - self.filename.value = fileInfo.abspath + self.filename:setValue(fileInfo.abspath) self.filename:setPosition(#self.filename.value) UI.MiniSlideOut.show(self) end, @@ -295,11 +306,11 @@ local page = UI.Page { }, }, grid = UI.ScrollingGrid { - x = 2, y = 4, ex = -2, ey = -4, - sortColumn = 'name', + x = 2, y = 3, ex = -2, ey = -4, + disableHeader = true, columns = { - { heading = 'Name', key = 'name' }, - { heading = 'Dir', key = 'dir' }, + { key = 'name' }, + { key = 'dir', textColor = colors.lightGray }, }, accelerators = { grid_select = 'accept', @@ -308,7 +319,7 @@ local page = UI.Page { cancel = UI.Button { x = -9, y = -2, text = 'Cancel', - event = 'quick_cancel', + event = 'slide_hide', }, apply_filter = function(self, filter) local t = { } @@ -320,17 +331,16 @@ local page = UI.Page { for _,v in pairs(self.listing) do v.score = fuzzy(v.lname, filter) if v.score then - table.insert(t, v) + _insert(t, v) end end else - self.grid.sortColumn = 'name' + self.grid.sortColumn = 'lname' self.grid.inverseSort = false t = self.listing end self.grid:setValues(t) - self.grid:update() self.grid:setIndex(1) end, show = function(self) @@ -340,9 +350,9 @@ local page = UI.Page { for _,f in ipairs(files) do local fullName = fs.combine(dir, f) if fs.native.isDir(fullName) then - recurse(fullName) + if f ~= '.git' then recurse(fullName) end else - table.insert(listing, { + _insert(listing, { name = f, dir = dir, lname = f:lower(), @@ -371,9 +381,6 @@ local page = UI.Page { self:hide() end - elseif event.type == 'quick_cancel' then - self:hide() - elseif event.type == 'text_change' then self:apply_filter(event.text) self.grid:draw() @@ -395,7 +402,7 @@ local page = UI.Page { accelerators = { [ ' ' ] = 'down', backspace = 'slide_hide', - } + }, }, show = function(self, values) local m = 12 @@ -443,7 +450,7 @@ local page = UI.Page { UI.Window.resize(self) w, h = self.width, self.height - actions.setCursor(x, y) + actions.set_cursor(x, y) actions.dirty_all() actions.redraw() end, @@ -461,7 +468,6 @@ local page = UI.Page { elseif ie.code == "mouse_click" or ie.code == 'mouse_drag' or - --ie.code == 'mouse_up' or ie.code == 'shift-mouse_click' or ie.code == 'mouse_down' or ie.code == 'mouse_doubleclick' then @@ -528,121 +534,50 @@ local function getFileInfo(path) return fi end -local function setStatus(pattern, ...) - page.notification:info(string.format(pattern, ...)) -end - -local function setError(pattern, ...) - page.notification:error(string.format(pattern, ...)) -end - -local function save( _sPath ) - -- Create intervening folder - local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() ) - if not fs.exists( sDir ) then - fs.makeDir( sDir ) - end - - -- Save - local file = nil - local function innerSave() - file = fs.open( _sPath, "w" ) - if file then - for _,sLine in ipairs( tLines ) do - file.write(sLine .. "\n") - end - else - error( "Failed to open ".._sPath ) - end - end - - local ok, err = pcall( innerSave ) - if file then - file.close() - end - return ok, err -end - -local function split(str, pattern) - pattern = pattern or "(.-)\n" - local t = {} - local function helper(line) table.insert(t, line) return "" end - helper((str:gsub(pattern, helper))) - return t -end - -local tKeywords = { - ["and"] = true, - ["break"] = true, - ["do"] = true, - ["else"] = true, - ["elseif"] = true, - ["end"] = true, - ["false"] = true, - ["for"] = true, - ["function"] = true, - ["if"] = true, - ["in"] = true, - ["local"] = true, - ["nil"] = true, - ["not"] = true, - ["or"] = true, - ["repeat"] = true, - ["return"] = true, - ["then"] = true, - ["true"] = true, - ["until"]= true, - ["while"] = true, +local keywords = Util.transpose { + 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', + 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while' } local function writeHighlighted(sLine, ny, dy) - local buffer = { - fg = '', - text = '', - } + local buffer = { fg = { }, text = { } } local function tryWrite(line, regex, fgcolor) local match = line:match(regex) if match then local fg = type(fgcolor) == "string" and fgcolor or fgcolor(match) - buffer.text = buffer.text .. match - buffer.fg = buffer.fg .. string.rep(fg, #match) - return line:sub(#match + 1) + _insert(buffer.text, match) + _insert(buffer.fg, _rep(fg, #match)) + return _sub(line, #match + 1) end return nil end while #sLine > 0 do sLine = + -- tryWrite(sLine, "^[%\26]", '7' ) or tryWrite(sLine, "^%-%-%[%[.-%]%]", color.commentColor ) or tryWrite(sLine, "^%-%-.*", color.commentColor ) or tryWrite(sLine, "^\".-[^\\]\"", color.stringColor ) or tryWrite(sLine, "^\'.-[^\\]\'", color.stringColor ) or tryWrite(sLine, "^%[%[.-%]%]", color.stringColor ) or tryWrite(sLine, "^[%w_]+", function(match) - if tKeywords[match] then - return color.keywordColor - end - return color.textColor + return keywords[match] and color.keywordColor or color.textColor end) or tryWrite(sLine, "^[^%w_]", color.textColor) end - buffer.fg = buffer.fg .. '7' - buffer.text = buffer.text .. '\183' + buffer.fg = _concat(buffer.fg) .. '7' + buffer.text = _concat(buffer.text) .. '\183' if mark.active and ny >= mark.y and ny <= mark.ey then local sx = ny == mark.y and mark.x or 1 - local ex = #buffer.text - if ny == mark.ey then - ex = mark.ex - end - buffer.bg = string.rep('f', sx - 1) .. - string.rep('7', ex - sx) .. - string.rep('f', #buffer.text - ex + 1) - + local ex = ny == mark.ey and mark.ex or #buffer.text + buffer.bg = _rep('f', sx - 1) .. + _rep('7', ex - sx) .. + _rep('f', #buffer.text - ex + 1) else - buffer.bg = string.rep('f', #buffer.text) + buffer.bg = _rep('f', #buffer.text) end page.editor:blit(1 - scrollX, dy, buffer.text, buffer.bg, buffer.fg) @@ -651,7 +586,6 @@ end local function redraw() if dirty.y > 0 then for dy = 1, h do - local sLine = tLines[dy + scrollY] if sLine ~= nil then if dy + scrollY >= dirty.y and dy + scrollY <= dirty.ey then @@ -665,7 +599,7 @@ local function redraw() end local modifiedIndicator = undo.chain[#undo.chain] == lastSave and ' ' or '*' - page.menuBar.status.value = string.format(' %d:%d%s', y, x, modifiedIndicator) + page.menuBar.status.value = _format('%d:%d%s', y, x, modifiedIndicator) page.menuBar.status:draw() if page.editor.focused then @@ -688,36 +622,34 @@ local function nextWord(line, cx) end actions = { + info = function(pattern, ...) + page.notification:info(_format(pattern, ...)) + end, + + error = function(pattern, ...) + page.notification:error(_format(pattern, ...)) + end, + undo = function() - local last = table.remove(undo.chain) + local last = _remove(undo.chain) if last then undo.active = true - actions[last.action](table.unpack(last.args)) + for i = #last, 1, -1 do + local u = last[i] + actions[u.action](_unpack(u.args)) + end undo.active = false else - setStatus('Already at oldest change') + actions.info('already at oldest change') end end, - addUndo = function(entry) + undo_add = function(entry) local last = undo.chain[#undo.chain] - if last and last.action == entry.action then - if last.action == 'deleteText' then - if last.args[3] == entry.args[1] and - last.args[4] == entry.args[2] then - last.args = { - last.args[1], last.args[2], entry.args[3], entry.args[4], - last.args[5] .. entry.args[5] - } - else - table.insert(undo.chain, entry) - end - else - -- insertText (need to finish) - table.insert(undo.chain, entry) - end + if last and undo.continue then + table.insert(last, entry) else - table.insert(undo.chain, entry) + _insert(undo.chain, { entry }) end end, @@ -726,7 +658,7 @@ actions = { local results = sLine and textutils.complete(sLine, _ENV) or { } if #results == 0 then - setError('No completions available') + actions.error('no completions available') elseif #results == 1 then actions.insertText(x, y, results[1]) @@ -746,7 +678,7 @@ actions = { refresh = function() actions.dirty_all() mark.continue = mark.active - setStatus('refreshed') + actions.info('refreshed') end, goto_line = function() @@ -763,7 +695,7 @@ actions = { local nx = tLines[ny]:lower():find(pattern, sx, true) if nx then if ny < y or ny == y and nx <= x then - setStatus('search hit BOTTOM, continuing at TOP') + actions.info('search hit BOTTOM, continuing at TOP') end actions.go_to(nx, ny) actions.mark_to(nx + #pattern, ny) @@ -772,7 +704,7 @@ actions = { end sx = 1 end - setError('Pattern not found') + actions.error('pattern not found') end, find_next = function() @@ -812,7 +744,7 @@ actions = { open = function(filename) if not actions.load(filename) then - setError('Unable to load file') + actions.error('unable to load file') end end, @@ -825,39 +757,51 @@ actions = { x, y = 1, 1 scrollX, scrollY = 0, 0 lastPos = { x = 1, y = 1 } - lastSave = nil + lastSave = nil dirty = { y = 1, ey = h } mark = { } - undo = { chain = { }, pointer = 0 } + undo = { chain = { } } - tLines = { } - if fs.exists(fileInfo.abspath) then - local file = io.open(fileInfo.abspath, "r") - local sLine = file:read() - while sLine do - table.insert(tLines, sLine) - sLine = file:read() - end - file:close() + tLines = Util.readLines(fileInfo.abspath) or { } + if #tLines == 0 then + _insert(tLines, '') end - if #tLines == 0 then - table.insert(tLines, '') + --[[ + local function detabify(l) + return l:gsub('\26\26', '\9'):gsub('\26', '\9') + end ]] + + -- since we can't handle tabs, convert them to spaces :( + local t1, t2 = ' ', ' ' + local function tabify(l) + repeat + local i = l:find('\9') + if i then + local tabs = (i - 1) % 2 == 0 and t2 or t1 + l = l:sub(1, i - 1) .. tabs .. l:sub(i + 1) + end + until not i + return l + end + + for k, v in pairs(tLines) do + tLines[k] = tabify(v) end local name = fileInfo.path if fileInfo.isNew then if not fileInfo.dirExists then - setStatus('"%s" [New DIRECTORY]', name) + actions.info('"%s" [New DIRECTORY]', name) else - setStatus('"%s" [New File]', name) + actions.info('"%s" [New File]', name) end elseif fileInfo.isReadOnly then - setStatus('"%s" [readonly] %dL, %dC', - name, #tLines, fs.getSize(fileInfo.abspath)) + actions.info('"%s" [readonly] %dL, %dC', + name, #tLines, fs.getSize(fileInfo.abspath)) else - setStatus('"%s" %dL, %dC', - name, #tLines, fs.getSize(fileInfo.abspath)) + actions.info('"%s" %dL, %dC', + name, #tLines, fs.getSize(fileInfo.abspath)) end return true @@ -866,17 +810,22 @@ actions = { save = function(filename) filename = filename or fileInfo.abspath if fs.isReadOnly(filename) then - setError("Access denied") + actions.error("access denied") else - local ok = save(filename) - if ok then + local s, m = pcall(function() + if not Util.writeLines(filename, tLines) then + error("Failed to open " .. filename) + end + end) + + if s then lastSave = undo.chain[#undo.chain] fileInfo = getFileInfo(filename) - setStatus('"%s" %dL, %dC written', + actions.info('"%s" %dL, %dC written', fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) - return true + return true else - setError("Error saving to %s", filename) + actions.error(m) end end end, @@ -894,26 +843,34 @@ actions = { end, run = function() - --input:reset() - local sTempPath = "/.temp" - local ok = save(sTempPath) - if ok then - local nTask = shell.openTab(sTempPath) + if undo.chain[#undo.chain] == lastSave then + local nTask = shell.openTab(fileInfo.abspath) if nTask then shell.switchTab(nTask) else - setError("Error starting Task") + actions.error("error starting Task") end - os.sleep(0) - fs.delete(sTempPath) else - setError("Error saving to %s", sTempPath) + local fn, msg = load(_concat(tLines, '\n'), fileInfo.abspath) + if fn then + multishell.openTab({ + fn = fn, + focused = true, + title = fs.getName(fileInfo.abspath), + }) + else + local ln = msg:match(':(%d+):') + if ln and tonumber(ln) then + actions.go_to(1, tonumber(ln)) + end + actions.error(msg) + end end end, status = function() local modified = undo.chain[#undo.chain] == lastSave and '' or '[Modified] ' - setStatus('"%s" %s%d lines --%d%%--', + actions.info('"%s" %s%d lines --%d%%--', fileInfo.abspath, modified, #tLines, math.floor((y - 1) / (#tLines - 1) * 100)) end, @@ -1019,6 +976,14 @@ actions = { actions.mark_finish() end, + mark_line = function() + actions.home() + actions.mark_begin() + actions.toend() + actions.right() + actions.mark_finish() + end, + mark_word = function() actions.mark_begin() actions.word() @@ -1074,7 +1039,7 @@ actions = { actions.dirty_all() end, - setCursor = function() + set_cursor = function() lastPos.x = x lastPos.y = y @@ -1128,11 +1093,11 @@ actions = { actions.insertText(x, y, ' ') end, - pageUp = function() + page_up = function() actions.go_to(x, y - h) end, - pageDown = function() + page_down = function() actions.go_to(x, y + h) end, @@ -1208,21 +1173,21 @@ actions = { actions.dirty_line(y) x = x + #text else - local lines = split(text) + local lines = Util.split(text) local remainder = sLine:sub(x) tLines[y] = sLine:sub(1, x - 1) .. lines[1] actions.dirty_range(y, #tLines + #lines) x = x + #lines[1] for k = 2, #lines do y = y + 1 - table.insert(tLines, y, lines[k]) + _insert(tLines, y, lines[k]) x = #lines[k] + 1 end tLines[y] = tLines[y]:sub(1, x) .. remainder end if not undo.active then - actions.addUndo( + actions.undo_add( { action = 'deleteText', args = { sx, sy, x, y, text } }) end end, @@ -1233,14 +1198,14 @@ actions = { if not undo.active then local text = actions.copyText(sx, sy, ex, ey) - actions.addUndo( + actions.undo_add( { action = 'insertText', args = { sx, sy, text } }) end local front = tLines[sy]:sub(1, sx - 1) local back = tLines[ey]:sub(ex, #tLines[ey]) for _ = 2, ey - sy + 1 do - table.remove(tLines, y + 1) + _remove(tLines, y + 1) end tLines[y] = front .. back if sy ~= ey then @@ -1267,10 +1232,10 @@ actions = { end local str = line:sub(cx, ex) count = count + #str - table.insert(lines, str) + _insert(lines, str) end end - return table.concat(lines, '\n'), count + return _concat(lines, '\n'), count end, delete = function() @@ -1304,7 +1269,7 @@ actions = { if mark.active then actions.delete() end - actions.insertText(x, y, '\n' .. string.rep(' ', spaces)) + actions.insertText(x, y, '\n' .. _rep(' ', spaces)) end, char = function(ch) @@ -1317,7 +1282,7 @@ actions = { copy_marked = function() local text = actions.copyText(mark.x, mark.y, mark.ex, mark.ey) os.queueEvent('clipboard_copy', text) - setStatus('shift-^v to paste') + actions.info('shift-^v to paste') end, cut = function() @@ -1340,9 +1305,9 @@ actions = { end if text then actions.insertText(x, y, text) - setStatus('%d chars added', #text) + actions.info('%d chars added', #text) else - setStatus('Clipboard empty') + actions.info('clipboard empty') end end, @@ -1384,10 +1349,16 @@ actions = { local wasMarking = mark.continue mark.continue = false + -- for undo purposes, treat tab and enter as char actions + local a = (action == 'tab' or action == 'enter') and 'char' or action + undo.continue = a == undo.lastAction + actions[action](...) + undo.lastAction = a + if x ~= lastPos.x or y ~= lastPos.y then - actions.setCursor() + actions.set_cursor() end if not mark.continue and wasMarking then actions.unmark() -- 2.49.1 From ef6cde3013f47109ebf3a1758f47f00eb32777a9 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Sun, 12 Apr 2020 18:46:04 -0600 Subject: [PATCH 08/12] editor recent/peripherals/redo + cleanup --- common/Events.lua | 127 +++++++++--------- common/edit.lua | 240 ++++++++++++++++++++++++++++++----- screenSaver/system/saver.lua | 35 +++-- 3 files changed, 281 insertions(+), 121 deletions(-) diff --git a/common/Events.lua b/common/Events.lua index 6a0dd2c..83f3fdd 100644 --- a/common/Events.lua +++ b/common/Events.lua @@ -27,6 +27,26 @@ local page = UI.Page { }, autospace = true, disableHeader = true, + getDisplayValues = function(_, row) + row = Util.shallowCopy(row) + + local function tovalue(s) + if type(s) == 'table' then + return 'table' + end + return s + end + + for k,v in pairs(row) do + row[k] = tovalue(v) + end + + return row + end, + draw = function(self) + self:adjustWidth() + UI.Grid.draw(self) + end, }, accelerators = { f = 'filter', @@ -36,81 +56,48 @@ local page = UI.Page { [ 'control-q' ] = 'quit', }, filtered = { }, -} + eventHandler = function(self, event) + if event.type == 'filter' then + local entry = self.grid:getSelected() + self.filtered[entry.event] = true -function page:eventHandler(event) + elseif event.type == 'toggle' then + self.paused = not self.paused + if self.paused then + self.menuBar.pauseButton.text = 'Resume' + else + self.menuBar.pauseButton.text = 'Pause ' + end + self.menuBar:draw() - if event.type == 'filter' then - local entry = self.grid:getSelected() - self.filtered[entry.event] = true + elseif event.type == 'grid_select' then + multishell.openTab({ + path = 'sys/apps/Lua.lua', + args = { event.selected }, + focused = true, + }) - elseif event.type == 'toggle' then - self.paused = not self.paused - if self.paused then - self.menuBar.pauseButton.text = 'Resume' - else - self.menuBar.pauseButton.text = 'Pause ' - end - self.menuBar:draw() - - elseif event.type == 'grid_select' then - multishell.openTab({ - path = 'sys/apps/Lua.lua', - args = { event.selected }, - focused = true, - }) - - elseif event.type == 'reset' then - self.filtered = { } - self.grid:setValues({ }) - self.grid:draw() - if self.paused then - self:emit({ type = 'toggle' }) - end - - elseif event.type == 'clear' then - self.grid:setValues({ }) - self.grid:draw() - - elseif event.type == 'quit' then - UI:exitPullEvents() - - --[[ - elseif event.type == 'focus_change' then - if event.focused == self.grid then - if not self.paused then + elseif event.type == 'reset' then + self.filtered = { } + self.grid:setValues({ }) + self.grid:draw() + if self.paused then self:emit({ type = 'toggle' }) end + + elseif event.type == 'clear' then + self.grid:setValues({ }) + self.grid:draw() + + elseif event.type == 'quit' then + UI:exitPullEvents() + + else + return UI.Page.eventHandler(self, event) end - --]] - - else - return UI.Page.eventHandler(self, event) - end - return true -end - -function page.grid:getDisplayValues(row) - row = Util.shallowCopy(row) - - local function tovalue(s) - if type(s) == 'table' then - return 'table' - end - return s - end - - for k,v in pairs(row) do - row[k] = tovalue(v) - end - - return row -end - -function page.grid:draw() - self:adjustWidth() - UI.Grid.draw(self) -end + return true + end, +} local updated = false local timerId = os.startTimer(1) @@ -150,6 +137,6 @@ end kernel.hook('*', hookFunction) UI:setPage(page) -UI:pullEvents() +UI:start() kernel.unhook('*', hookFunction) diff --git a/common/edit.lua b/common/edit.lua index 416d3da..7baef06 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -1,8 +1,11 @@ -local fuzzy = require('opus.fuzzy') -local UI = require('opus.ui') -local Util = require('opus.util') +local Array = require('opus.array') +local Config = require('opus.config') +local fuzzy = require('opus.fuzzy') +local UI = require('opus.ui') +local Util = require('opus.util') local colors = _G.colors +local device = _G.device local fs = _G.fs local multishell = _ENV.multishell local os = _G.os @@ -18,6 +21,8 @@ local _insert = table.insert local _remove = table.remove local _unpack = table.unpack +local config = Config.load('edit') + local x, y = 1, 1 local w, h = term.getSize() local scrollX = 0 @@ -30,7 +35,7 @@ local lastSave local dirty = { y = 1, ey = h } local mark = { } local searchPattern -local undo = { chain = { } } +local undo = { chain = { }, redo = { } } h = h - 1 @@ -96,7 +101,9 @@ local keyMapping = { paste = 'paste', tab = 'tab', [ 'control-z' ] = 'undo', + [ 'control-Z' ] = 'redo', [ 'control-space' ] = 'autocomplete', + [ 'control-shift-space' ] = 'peripheral', -- copy/paste [ 'control-x' ] = 'cut', @@ -126,8 +133,9 @@ local page = UI.Page { buttons = { { text = 'File', dropdown = { { text = 'New ', event = 'menu_action', action = 'file_new' }, - { text = 'Open ', event = 'menu_action', action = 'file_open' }, + { text = 'Open... ', event = 'menu_action', action = 'file_open' }, { text = 'Quick Open... ^p', event = 'menu_action', action = 'quick_open' }, + { text = 'Recent... ', event = 'menu_action', action = 'recent' }, { spacer = true }, { text = 'Save ^s', event = 'menu_action', action = 'save' }, { text = 'Save As... ^S', event = 'menu_action', action = 'save_as' }, @@ -146,8 +154,10 @@ local page = UI.Page { { text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' }, } }, { text = 'Code', dropdown = { - { text = 'Complete ^space', event = 'menu_action', action = 'autocomplete' }, - { text = 'Run ^enter', event = 'menu_action', action = 'run' }, + { text = 'Complete ^space', event = 'menu_action', action = 'autocomplete' }, + { text = 'Run ^enter', event = 'menu_action', action = 'run' }, + { spacer = true }, + { text = 'Peripheral ^SPACE', event = 'menu_action', action = 'peripheral' }, } }, }, status = UI.Text { @@ -185,10 +195,10 @@ local page = UI.Page { end, }, search = UI.MiniSlideOut { - x = -20, y = -2, + x = '50%', y = -2, label = 'Find', search = UI.TextEntry { - x = 7, width = 12, + x = 7, ex = -3, limit = 512, markBackgroundColor = colors.lightGray, backgroundFocusColor = colors.gray, @@ -218,10 +228,10 @@ local page = UI.Page { end, }, save_as = UI.MiniSlideOut { - x = -24, y = -2, + x = '30%', y = -2, label = 'Save', filename = UI.TextEntry { - x = 7, width = 16, + x = 7, ex = -3, limit = 512, markBackgroundColor = colors.lightGray, backgroundFocusColor = colors.gray, @@ -294,6 +304,42 @@ local page = UI.Page { return UI.FileSelect.eventHandler(self, event) end, }, + recent = UI.SlideOut { + transitionHint = 'expandUp', + grid = UI.Grid { + x = 2, y = 2, ey = -4, ex = -2, + columns = { + { key = 'name', heading = 'Name' }, + { key = 'dir', heading = 'Directory' }, + }, + accelerators = { + backspace = 'slide_hide', + }, + }, + cancel = UI.Button { + x = -9, y = -2, + text = 'Cancel', + event = 'slide_hide', + }, + show = function(self) + local t = { } + for _,v in pairs(config.recent or { }) do + table.insert(t, { name = fs.getName(v), dir = fs.getDir(v), path = v }) + end + self.grid:setValues(t) + self.grid:setIndex(1) + UI.SlideOut.show(self) + self:addTransition('expandUp', { easing = 'outBounce', ticks = 12 }) + end, + eventHandler = function(self, event) + if event.type == 'grid_select' then + actions.process('open', event.selected.path) + self:hide() + return true + end + return UI.SlideOut.eventHandler(self, event) + end, + }, quick_open = UI.SlideOut { filter_entry = UI.TextEntry { x = 2, y = 2, ex = -2, @@ -346,10 +392,10 @@ local page = UI.Page { show = function(self) local listing = { } local function recurse(dir) - local files = fs.native.list(dir) + local files = fs.list(dir) for _,f in ipairs(files) do local fullName = fs.combine(dir, f) - if fs.native.isDir(fullName) then + if fs.native.isDir(fullName) then -- skip virtual dirs if f ~= '.git' then recurse(fullName) end else _insert(listing, { @@ -366,6 +412,7 @@ local page = UI.Page { self:apply_filter() self.filter_entry:reset() UI.SlideOut.show(self) + self:addTransition('expandUp', { easing = 'outBounce', ticks = 12 }) end, eventHandler = function(self, event) if event.type == 'grid_up' then @@ -404,6 +451,14 @@ local page = UI.Page { backspace = 'slide_hide', }, }, + cancel = UI.Button { + y = -1, x = -9, + text = 'Cancel', + backgroundColor = colors.black, + backgroundFocusColor = colors.black, + textColor = colors.lightGray, + event = 'slide_hide', + }, show = function(self, values) local m = 12 for _, v in pairs(values) do @@ -417,6 +472,72 @@ local page = UI.Page { self.grid:setIndex(1) UI.SlideOut.show(self) end, + eventHandler = function(self, event) + if event.type == 'grid_select' then + actions.process('insertText', x, y, event.selected.complete) + self:hide() + return true + end + return UI.SlideOut.eventHandler(self, event) + end, + }, + peripheral = UI.SlideOut { + x = '20%', y = 2, + transitionHint = 'slideLeft', + grid1 = UI.Grid { + x = 2, y = 2, ey = 5, + sortColumn = 'name', + columns = { + { key = 'name', heading = 'Peripheral' }, + }, + accelerators = { + [ ' ' ] = 'down', + backspace = 'slide_hide', + grid_focus_row = 'select_peripheral', + grid_select = 'complete', + }, + scan = function(self) + self.values = { } + for k, v in pairs(device) do + table.insert(self.values, { name = k, complete = 'peripheral.wrap("' .. v.side .. '")' }) + end + end, + postInit = function(self) + self:scan() + end, + }, + grid2 = UI.Grid { + x = 2, y = 6, ey = -2, + sortColumn = 'method', + columns = { + { key = 'method', heading = 'Method' }, + }, + accelerators = { + [ ' ' ] = 'down', + backspace = 'slide_hide', + grid_select = 'complete', + }, + showMethods = function(self) + local dev = device[self.parent.grid1:getSelected().name] + local t = { } + if dev then + pcall(function() + local docs = dev.getDocs and dev.getDocs() + for k, v in pairs(dev) do + if type(v) == 'function' then + local m = docs and docs[k] and docs[k]:match('^function%((.+)%).+') + table.insert(t, { method = k, complete = k .. '(' .. (m or '') .. ')' }) + end + end + end) + end + self:setValues(t) + end, + enable = function(self) + self:showMethods() + UI.Grid.enable(self) + end, + }, cancel = UI.Button { y = -1, x = -9, text = 'Cancel', @@ -426,10 +547,16 @@ local page = UI.Page { event = 'slide_hide', }, eventHandler = function(self, event) - if event.type == 'grid_select' then + if event.type == 'complete' then actions.process('insertText', x, y, event.selected.complete) + actions.process('left') self:hide() return true + elseif event.type == 'select_peripheral' then + self.grid2:showMethods() + self.grid2:setIndex(1) + self.grid2:update() + self.grid2:draw() end return UI.SlideOut.eventHandler(self, event) end, @@ -527,6 +654,19 @@ local function getFileInfo(path) fi.isReadOnly = fs.isReadOnly(fi.abspath) end + if abspath ~= config.filename then + config.filename = abspath + config.recent = config.recent or { } + + Array.removeByValue(config.recent, '/' .. abspath) + table.insert(config.recent, 1, '/' .. abspath) + while #config.recent > 10 do + table.remove(config.recent) + end + + Config.update('edit', config) + end + if multishell then multishell.setTitle(multishell.getCurrent(), fs.getName(fi.path)) end @@ -634,6 +774,7 @@ actions = { local last = _remove(undo.chain) if last then undo.active = true + table.insert(undo.redo, { }) for i = #last, 1, -1 do local u = last[i] actions[u.action](_unpack(u.args)) @@ -645,11 +786,36 @@ actions = { end, undo_add = function(entry) - local last = undo.chain[#undo.chain] - if last and undo.continue then + if undo.active then + local last = undo.redo[#undo.redo] table.insert(last, entry) else - _insert(undo.chain, { entry }) + if not undo.redo_active then + undo.redo = { } + end + local last = undo.chain[#undo.chain] + if last and undo.continue then + table.insert(last, entry) + else + _insert(undo.chain, { entry }) + end + end + end, + + redo = function() + local last = _remove(undo.redo) + if last then + -- too many flags ! + undo.redo_active = true + undo.continue = false + for i = #last, 1, -1 do + local u = last[i] + actions[u.action](_unpack(u.args)) + undo.continue = true + end + undo.redo_active = false + else + actions.info('already at newest change') end end, @@ -675,6 +841,10 @@ actions = { end end, + peripheral = function() + page.peripheral:show() + end, + refresh = function() actions.dirty_all() mark.continue = mark.active @@ -734,6 +904,14 @@ actions = { end end, + recent = function(force) + if not force and undo.chain[#undo.chain] ~= lastSave then + page.unsaved:show('recent') + else + page.recent:show() + end + end, + file_new = function(force) if not force and undo.chain[#undo.chain] ~= lastSave then page.unsaved:show('file_new') @@ -749,7 +927,7 @@ actions = { end, load = function(path) - if fs.exists(path) and fs.isDir(path) then + if not path or (fs.exists(path) and fs.isDir(path)) then return false end fileInfo = getFileInfo(path) @@ -760,7 +938,7 @@ actions = { lastSave = nil dirty = { y = 1, ey = h } mark = { } - undo = { chain = { } } + undo = { chain = { }, redo = { } } tLines = Util.readLines(fileInfo.abspath) or { } if #tLines == 0 then @@ -843,6 +1021,10 @@ actions = { end, run = function() + if not multishell then + actions.error('open available with multishell') + return + end if undo.chain[#undo.chain] == lastSave then local nTask = shell.openTab(fileInfo.abspath) if nTask then @@ -1186,21 +1368,17 @@ actions = { tLines[y] = tLines[y]:sub(1, x) .. remainder end - if not undo.active then - actions.undo_add( - { action = 'deleteText', args = { sx, sy, x, y, text } }) - end + actions.undo_add( + { action = 'deleteText', args = { sx, sy, x, y } }) end, deleteText = function(sx, sy, ex, ey) x = sx y = sy - if not undo.active then - local text = actions.copyText(sx, sy, ex, ey) - actions.undo_add( - { action = 'insertText', args = { sx, sy, text } }) - end + local text = actions.copyText(sx, sy, ex, ey) + actions.undo_add( + { action = 'insertText', args = { sx, sy, text } }) local front = tLines[sy]:sub(1, sx - 1) local back = tLines[ey]:sub(ex, #tLines[ey]) @@ -1252,9 +1430,7 @@ actions = { end, backspace = function() - if mark.active then - actions.delete() - elseif actions.left() then + if mark.active or actions.left() then actions.delete() end end, @@ -1369,7 +1545,7 @@ actions = { } local args = { ... } -if not actions.load(args[1] and args[1] or 'untitled.txt') then +if not (actions.load(args[1]) or actions.load(config.filename) or actions.load('untitled.txt')) then error('Error opening file') end diff --git a/screenSaver/system/saver.lua b/screenSaver/system/saver.lua index 2813173..7391f2d 100644 --- a/screenSaver/system/saver.lua +++ b/screenSaver/system/saver.lua @@ -6,7 +6,7 @@ local config = Config.load('saver', { timeout = 60, }) -local tab = UI.Tab { +return UI.Tab { tabTitle = 'Screen Saver', description = 'Screen saver', [1] = UI.Window { @@ -38,24 +38,21 @@ local tab = UI.Tab { text = 'Apply', event = 'update', }, -} + eventHandler = function(self, event) + if event.type =='checkbox_change' then + config.enabled = not not event.checked -function tab:eventHandler(event) - if event.type =='checkbox_change' then - config.enabled = not not event.checked + elseif event.type == 'update' then + if self.timeout.value then + config.timeout = self.timeout.value + Config.update('saver', config) - elseif event.type == 'update' then - if self.timeout.value then - config.timeout = self.timeout.value - Config.update('saver', config) - - self:emit({ type = 'success_message', message = 'Settings updated' }) - os.queueEvent('config_update', 'saver', config) - else - self:emit({ type = 'error_message', message = 'Invalid timeout' }) + self:emit({ type = 'success_message', message = 'Settings updated' }) + os.queueEvent('config_update', 'saver', config) + else + self:emit({ type = 'error_message', message = 'Invalid timeout' }) + end end - end - return UI.Tab.eventHandler(self, event) -end - -return tab + return UI.Tab.eventHandler(self, event) + end, +} -- 2.49.1 From 6b429a26e4c64bc8023c0a8f43887e431948d2c3 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 14 Apr 2020 14:12:44 -0600 Subject: [PATCH 09/12] editor path issues --- common/edit.lua | 62 ++++++++++++++++++++------------------------- common/recorder.lua | 16 +++++++----- 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/common/edit.lua b/common/edit.lua index 7baef06..7dcd028 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -21,7 +21,7 @@ local _insert = table.insert local _remove = table.remove local _unpack = table.unpack -local config = Config.load('edit') +local config = Config.load('editor') local x, y = 1, 1 local w, h = term.getSize() @@ -241,7 +241,7 @@ local page = UI.Page { }, }, show = function(self) - self.filename:setValue(fileInfo.abspath) + self.filename:setValue(fileInfo.path) self.filename:setPosition(#self.filename.value) UI.MiniSlideOut.show(self) end, @@ -289,7 +289,7 @@ local page = UI.Page { modal = true, enable = function() end, show = function(self) - UI.FileSelect.enable(self, fs.getDir(fileInfo.abspath)) + UI.FileSelect.enable(self, fs.getDir(fileInfo.path)) self:focusFirst() self:draw() self:addTransition('expandUp', { easing = 'outBounce', ticks = 12 }) @@ -305,7 +305,6 @@ local page = UI.Page { end, }, recent = UI.SlideOut { - transitionHint = 'expandUp', grid = UI.Grid { x = 2, y = 2, ey = -4, ex = -2, columns = { @@ -402,7 +401,7 @@ local page = UI.Page { name = f, dir = dir, lname = f:lower(), - fullName = '/' .. fullName, + fullName = fullName, }) end end @@ -565,12 +564,10 @@ local page = UI.Page { y = 2, backgroundColor = colors.black, transitionHint = 'slideRight', + cursorBlink = true, focus = function(self) if self.focused then self:setCursorPos(x - scrollX, y - scrollY) - self:setCursorBlink(true) - else - self:setCursorBlink(false) end end, resize = function(self) @@ -639,32 +636,26 @@ local page = UI.Page { } local function getFileInfo(path) - local abspath = shell.resolve(path) + path = fs.combine('/', path) local fi = { - abspath = abspath, path = path, - isNew = not fs.exists(abspath), - dirExists = fs.exists(fs.getDir(abspath)), - modified = false, + isNew = not fs.exists(path), + dirExists = fs.exists(fs.getDir(path)), + isReadOnly = fs.isReadOnly(path), } - if fi.isDir then - fi.isReadOnly = true - else - fi.isReadOnly = fs.isReadOnly(fi.abspath) - end - if abspath ~= config.filename then - config.filename = abspath + if path ~= config.filename then + config.filename = path config.recent = config.recent or { } - Array.removeByValue(config.recent, '/' .. abspath) - table.insert(config.recent, 1, '/' .. abspath) + Array.removeByValue(config.recent, path) + table.insert(config.recent, 1, path) while #config.recent > 10 do table.remove(config.recent) end - Config.update('edit', config) + Config.update('editor', config) end if multishell then @@ -940,7 +931,7 @@ actions = { mark = { } undo = { chain = { }, redo = { } } - tLines = Util.readLines(fileInfo.abspath) or { } + tLines = Util.readLines(fileInfo.path) or { } if #tLines == 0 then _insert(tLines, '') end @@ -976,17 +967,17 @@ actions = { end elseif fileInfo.isReadOnly then actions.info('"%s" [readonly] %dL, %dC', - name, #tLines, fs.getSize(fileInfo.abspath)) + name, #tLines, fs.getSize(fileInfo.path)) else actions.info('"%s" %dL, %dC', - name, #tLines, fs.getSize(fileInfo.abspath)) + name, #tLines, fs.getSize(fileInfo.path)) end return true end, save = function(filename) - filename = filename or fileInfo.abspath + filename = filename or fileInfo.path if fs.isReadOnly(filename) then actions.error("access denied") else @@ -1000,7 +991,7 @@ actions = { lastSave = undo.chain[#undo.chain] fileInfo = getFileInfo(filename) actions.info('"%s" %dL, %dC written', - fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) + fileInfo.path, #tLines, fs.getSize(fileInfo.path)) return true else actions.error(m) @@ -1026,19 +1017,19 @@ actions = { return end if undo.chain[#undo.chain] == lastSave then - local nTask = shell.openTab(fileInfo.abspath) + local nTask = shell.openTab(fileInfo.path) if nTask then shell.switchTab(nTask) else actions.error("error starting Task") end else - local fn, msg = load(_concat(tLines, '\n'), fileInfo.abspath) + local fn, msg = load(_concat(tLines, '\n'), fileInfo.path) if fn then multishell.openTab({ fn = fn, focused = true, - title = fs.getName(fileInfo.abspath), + title = fs.getName(fileInfo.path), }) else local ln = msg:match(':(%d+):') @@ -1053,7 +1044,7 @@ actions = { status = function() local modified = undo.chain[#undo.chain] == lastSave and '' or '[Modified] ' actions.info('"%s" %s%d lines --%d%%--', - fileInfo.abspath, modified, #tLines, + fileInfo.path, modified, #tLines, math.floor((y - 1) / (#tLines - 1) * 100)) end, @@ -1229,10 +1220,10 @@ actions = { local screenY = y - scrollY if screenX < 1 then - scrollX = x - 1 + scrollX = math.max(0, x - 4) actions.dirty_all() elseif screenX > w then - scrollX = x - w + scrollX = x - w + 3 actions.dirty_all() end @@ -1545,7 +1536,8 @@ actions = { } local args = { ... } -if not (actions.load(args[1]) or actions.load(config.filename) or actions.load('untitled.txt')) then +local filename = args[1] and shell.resolve(args[1]) +if not (actions.load(filename) or actions.load(config.filename) or actions.load('untitled.txt')) then error('Error opening file') end diff --git a/common/recorder.lua b/common/recorder.lua index e6c7a94..908e58f 100644 --- a/common/recorder.lua +++ b/common/recorder.lua @@ -134,15 +134,17 @@ end recTerm = multishell.term for key, func in pairs(oldTerm) do - recTerm[key] = function(...) - local result = { func(...) } + if type(func) == 'function' then + recTerm[key] = function(...) + local result = { func(...) } - if callCount == 0 then - os.queueEvent('capture_frame') + if callCount == 0 then + os.queueEvent('capture_frame') + end + callCount = callCount + 1 + curCalls[callCount] = { key, ... } + return unpack(result) end - callCount = callCount + 1 - curCalls[callCount] = { key, ... } - return unpack(result) end end -- 2.49.1 From 3246579ab178cb0a6ce998519dfdb57d62cb8c85 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Thu, 16 Apr 2020 23:11:59 -0600 Subject: [PATCH 10/12] cleanup --- builder/builder.lua | 9 +- common/Appstore.lua | 3 - common/Devices.lua | 2 +- common/DiskCopy.lua | 1 - common/Turtles.lua | 324 ++++++++++++++--------------- common/etc/scripts/goHome | 2 +- common/etc/scripts/moveTo | 4 +- common/etc/scripts/setHome | 2 +- common/etc/scripts/summon | 6 +- ignore/Music.lua | 2 - milo/plugins/item/resetTab.lua | 2 +- miners/scanningMiner.lua | 3 +- recipeBook/recipeBook.lua | 7 +- turtle/{autorun => init}/6.tl3.lua | 0 14 files changed, 177 insertions(+), 190 deletions(-) rename turtle/{autorun => init}/6.tl3.lua (100%) diff --git a/builder/builder.lua b/builder/builder.lua index 0c39cb8..7e7638f 100644 --- a/builder/builder.lua +++ b/builder/builder.lua @@ -236,10 +236,7 @@ function substitutionPage.info:draw() end self:clear() - self:setCursorPos(1, 1) - self:print(' Replace ' .. inName .. '\n') - --self:print(' ' .. sub.id .. ':' .. sub.dmg .. '\n', nil, colors.yellow) - self:print(' With ' .. outName) + self:print(' Replace ' .. inName .. '\n' .. ' With ' .. outName) end function substitutionPage:enable() @@ -536,7 +533,7 @@ local startPage = UI.Page { event = 'setStartLevel', cancelEvent = 'slide_hide', text = UI.Text { - x = 5, y = 1, width = 20, + x = 5, y = 1, width = 10, textColor = colors.gray, }, textEntry = UI.TextEntry { @@ -554,7 +551,7 @@ local startPage = UI.Page { event = 'setStartBlock', cancelEvent = 'slide_hide', text = UI.Text { - x = 2, y = 1, width = 20, + x = 2, y = 1, width = 13, textColor = colors.gray, }, textEntry = UI.TextEntry { diff --git a/common/Appstore.lua b/common/Appstore.lua index 7a5856f..2bbb521 100644 --- a/common/Appstore.lua +++ b/common/Appstore.lua @@ -211,9 +211,7 @@ function appPage.container.viewport:draw() Ansi.yellow .. app.description .. Ansi.reset) self:clear() - self:setCursorPos(1, 1) self:print(str) - self.ymax = self.cursorY if appPage.notification.enabled then appPage.notification:draw() @@ -369,4 +367,3 @@ categoryPage:setCategory(source.name, source.index) UI:setPage(categoryPage) UI:pullEvents() -UI.term:reset() diff --git a/common/Devices.lua b/common/Devices.lua index 6ad2f08..0415291 100644 --- a/common/Devices.lua +++ b/common/Devices.lua @@ -68,7 +68,7 @@ local methodsPage = UI.Page { grid = UI.ScrollingGrid { y = -6, ey = -2, columns = { - { heading = 'Name', key = 'name', width = UI.term.width } + { heading = 'Name', key = 'name' } }, sortColumn = 'name', }, diff --git a/common/DiskCopy.lua b/common/DiskCopy.lua index 849dbe3..a0d41ef 100644 --- a/common/DiskCopy.lua +++ b/common/DiskCopy.lua @@ -122,7 +122,6 @@ function page:drawInfo(drive, textArea) return isValid(drive) and fs.getFreeSpace(drive.getMountPath()) or 0 end - textArea:setCursorPos(1, 1) textArea:print(string.format('Drive: %s%s%s\nLabel: %s%s%s\nUsed: %s%s%s\nFree: %s%s%s', Ansi.yellow, drive.name, Ansi.reset, isValid(drive) and Ansi.yellow or Ansi.orange, getLabel():sub(1, 10), Ansi.reset, diff --git a/common/Turtles.lua b/common/Turtles.lua index f27a004..947ec62 100644 --- a/common/Turtles.lua +++ b/common/Turtles.lua @@ -2,7 +2,6 @@ local Config = require('opus.config') local Event = require('opus.event') local itemDB = require('core.itemDB') local Socket = require('opus.socket') -local Terminal = require('opus.terminal') local UI = require('opus.ui') local Util = require('opus.util') @@ -11,10 +10,7 @@ local fs = _G.fs local multishell = _ENV.multishell local network = _G.network local os = _G.os -local shell = _ENV.shell -local term = _G.term ---UI.Button.defaults.focusIndicator = ' ' UI:configure('Turtles', ...) local config = { } @@ -31,13 +27,26 @@ local options = { local SCRIPTS_PATH = 'packages/common/etc/scripts' -local nullTerm = Terminal.getNullTerm(term.current()) -local socket +local socket, turtle, page -local page = UI.Page { +page = UI.Page { coords = UI.Window { backgroundColor = colors.black, height = 3, + marginTop = 1, marginLeft = 1, + draw = function(self) + local t = turtle + self:clear() + if t then + self:setCursorPos(2, 2) + local ind = 'GPS' + if not t.point.gps then + ind = 'REL' + end + self:print(string.format('%s : %d,%d,%d', + ind, t.point.x, t.point.y, t.point.z)) + end + end, }, tabs = UI.Tabs { x = 1, y = 4, ey = -2, @@ -50,6 +59,23 @@ local page = UI.Page { disableHeader = true, sortColumn = 'label', autospace = true, + draw = function(self) + Util.clear(self.values) + local files = fs.list(SCRIPTS_PATH) + for _,path in pairs(files) do + table.insert(self.values, { label = path, path = fs.combine(SCRIPTS_PATH, path) }) + end + self:update() + UI.ScrollingGrid.draw(self) + end, + eventHandler = function(self, event) + if event.type == 'grid_select' then + page:runScript(event.selected.label) + else + return UI.ScrollingGrid.eventHandler(self, event) + end + return true + end, }, turtles = UI.ScrollingGrid { tabTitle = 'Select', @@ -63,6 +89,41 @@ local page = UI.Page { disableHeader = true, sortColumn = 'label', autospace = true, + getDisplayValues = function(_, row) + row = Util.shallowCopy(row) + if row.fuel then + row.fuel = Util.toBytes(row.fuel) + end + if row.distance then + row.distance = Util.round(row.distance, 1) + end + return row + end, + draw = function(self) + Util.clear(self.values) + for _,v in pairs(network) do + if v.fuel then + table.insert(self.values, v) + end + end + self:update() + UI.ScrollingGrid.draw(self) + end, + eventHandler = function(self, event) + if event.type == 'grid_select' then + turtle = event.selected + config.id = event.selected.id + Config.update('Turtles', config) + multishell.setTitle(multishell.getCurrent(), turtle.label) + if socket then + socket:close() + socket = nil + end + else + return UI.ScrollingGrid.eventHandler(self, event) + end + return true + end, }, inventory = UI.ScrollingGrid { backgroundColor = colors.cyan, @@ -74,6 +135,54 @@ local page = UI.Page { }, disableHeader = true, sortColumn = 'index', + getRowTextColor = function(self, row, selected) + if turtle and row.selected then + return colors.yellow + end + return UI.ScrollingGrid.getRowTextColor(self, row, selected) + end, + draw = function(self) + local t = turtle + Util.clear(self.values) + if t then + for k,v in pairs(t.inv or { }) do -- new method (less data) + local index, count = k:match('(%d+),(%d+)') + v = { + index = tonumber(index), + key = v, + count = tonumber(count), + } + table.insert(self.values, v) + end + + for _,v in pairs(t.inventory or { }) do + if v.count > 0 then + table.insert(self.values, v) + end + end + + for _,v in pairs(self.values) do + if v.index == t.slotIndex then + v.selected = true + end + if v.key then + v.key = itemDB:getName(v.key) + end + end + end + self:adjustWidth() + self:update() + UI.ScrollingGrid.draw(self) + end, + eventHandler = function(self, event) + if event.type == 'grid_select' then + local fn = string.format('turtle.select(%d)', event.selected.index) + page:runFunction(fn) + else + return UI.ScrollingGrid.eventHandler(self, event) + end + return true + end, }, --[[ policy = UI.ScrollingGrid { @@ -134,6 +243,15 @@ local page = UI.Page { { key = 'distance', width = 6 }, { key = 'fuel', width = 6 }, }, + draw = function(self) + local t = turtle + if t then + self.values.status = t.status + self.values.distance = t.distance and Util.round(t.distance, 2) + self.values.fuel = Util.toBytes(t.fuel) + end + UI.StatusBar.draw(self) + end, }, notification = UI.Notification(), accelerators = { @@ -141,15 +259,10 @@ local page = UI.Page { }, } -function page:enable(turtle) - self.turtle = turtle - UI.Page.enable(self) -end - function page:runFunction(script, nowrap) for _ = 1, 2 do if not socket then - socket = Socket.connect(self.turtle.id, 161) + socket = Socket.connect(turtle.id, 161) end if socket then @@ -170,151 +283,42 @@ function page:runFunction(script, nowrap) end function page:runScript(scriptName) - if self.turtle then + if turtle then self.notification:info('Connecting') self:sync() - local cmd = string.format('Script %d %s', self.turtle.id, scriptName) - local ot = term.redirect(nullTerm) - pcall(function() shell.run(cmd) end) - term.redirect(ot) + local script = Util.readFile(fs.combine(SCRIPTS_PATH, scriptName)) + if not script then + print('Unable to read script file') + end + + local socket = Socket.connect(turtle.id, 161) + if not socket then + print('Unable to connect to ' .. turtle.id) + return + end + + local function processVariables(script) + local variables = { + COMPUTER_ID = os.getComputerID(), + } + for k,v in pairs(variables) do + local token = string.format('{%s}', k) + script = script:gsub(token, v) + end + + return script + end + + script = processVariables(script) + + socket:write({ type = 'script', args = script }) + socket:close() + self.notification:success('Sent') end end -function page.coords:draw() - local t = self.parent.turtle - self:clear() - if t then - self:setCursorPos(2, 2) - local ind = 'GPS' - if not t.point.gps then - ind = 'REL' - end - self:print(string.format('%s : %d,%d,%d', - ind, t.point.x, t.point.y, t.point.z)) - end -end - ---[[ Inventory Tab ]]-- -function page.tabs.inventory:getRowTextColor(row, selected) - if page.turtle and row.selected then - return colors.yellow - end - return UI.ScrollingGrid.getRowTextColor(self, row, selected) -end - -function page.tabs.inventory:draw() - local t = page.turtle - Util.clear(self.values) - if t then - for k,v in pairs(t.inv or { }) do -- new method (less data) - local index, count = k:match('(%d+),(%d+)') - v = { - index = tonumber(index), - key = v, - count = tonumber(count), - } - table.insert(self.values, v) - end - - for _,v in pairs(t.inventory or { }) do - if v.count > 0 then - table.insert(self.values, v) - end - end - - for _,v in pairs(self.values) do - if v.index == t.slotIndex then - v.selected = true - end - if v.key then - v.key = itemDB:getName(v.key) - end - end - end - self:adjustWidth() - self:update() - UI.ScrollingGrid.draw(self) -end - -function page.tabs.inventory:eventHandler(event) - if event.type == 'grid_select' then - local fn = string.format('turtle.select(%d)', event.selected.index) - page:runFunction(fn) - else - return UI.ScrollingGrid.eventHandler(self, event) - end - return true -end - -function page.tabs.scripts:draw() - Util.clear(self.values) - local files = fs.list(SCRIPTS_PATH) - for _,path in pairs(files) do - table.insert(self.values, { label = path, path = fs.combine(SCRIPTS_PATH, path) }) - end - self:update() - UI.ScrollingGrid.draw(self) -end - -function page.tabs.scripts:eventHandler(event) - if event.type == 'grid_select' then - page:runScript(event.selected.label) - else - return UI.ScrollingGrid.eventHandler(self, event) - end - return true -end - -function page.tabs.turtles:getDisplayValues(row) - row = Util.shallowCopy(row) - if row.fuel then - row.fuel = Util.toBytes(row.fuel) - end - if row.distance then - row.distance = Util.round(row.distance, 1) - end - return row -end - -function page.tabs.turtles:draw() - Util.clear(self.values) - for _,v in pairs(network) do - if v.fuel then - table.insert(self.values, v) - end - end - self:update() - UI.ScrollingGrid.draw(self) -end - -function page.tabs.turtles:eventHandler(event) - if event.type == 'grid_select' then - page.turtle = event.selected - config.id = event.selected.id - Config.update('Turtles', config) - multishell.setTitle(multishell.getCurrent(), page.turtle.label) - if socket then - socket:close() - socket = nil - end - else - return UI.ScrollingGrid.eventHandler(self, event) - end - return true -end - -function page.statusBar:draw() - local t = self.parent.turtle - if t then - self.values.status = t.status - self.values.distance = t.distance and Util.round(t.distance, 2) - self.values.fuel = Util.toBytes(t.fuel) - end - UI.StatusBar.draw(self) -end - function page:showBlocks() local script = [[ local function inspect(direction) @@ -354,19 +358,14 @@ function page:eventHandler(event) return true end -function page:enable() - UI.Page.enable(self) --- self.tabs:activateTab(page.tabs.turtles) -end - if not Util.getOptions(options, { ... }, true) then return end if options.turtle.value >= 0 then for _ = 1, 10 do - page.turtle = _G.network[options.turtle.value] - if page.turtle then + turtle = _G.network[options.turtle.value] + if turtle then break end os.sleep(1) @@ -374,9 +373,9 @@ if options.turtle.value >= 0 then end Event.onInterval(1, function() - if page.turtle then - local t = _G.network[page.turtle.id] - page.turtle = t + if turtle then + --local t = _G.network[turtle.id] + --turtle = t page:draw() page:sync() end @@ -387,5 +386,4 @@ if config.tab then end UI:setPage(page) - -UI:pullEvents() +UI:start() diff --git a/common/etc/scripts/goHome b/common/etc/scripts/goHome index 2749820..94fd138 100644 --- a/common/etc/scripts/goHome +++ b/common/etc/scripts/goHome @@ -1,5 +1,5 @@ _G.requireInjector(_ENV) -local config = require('config').load('gps') +local config = require('opus.config').load('gps') if config.home then if turtle.enableGPS() then return turtle.pathfind(config.home) diff --git a/common/etc/scripts/moveTo b/common/etc/scripts/moveTo index c68e1db..11be075 100644 --- a/common/etc/scripts/moveTo +++ b/common/etc/scripts/moveTo @@ -2,8 +2,8 @@ turtle.run(function() _G.requireInjector(_ENV) - local GPS = require('gps') - local Socket = require('socket') + local GPS = require('opus.gps') + local Socket = require('opus.socket') local id = {COMPUTER_ID} diff --git a/common/etc/scripts/setHome b/common/etc/scripts/setHome index 9f88beb..be69170 100644 --- a/common/etc/scripts/setHome +++ b/common/etc/scripts/setHome @@ -1,5 +1,5 @@ _G.requireInjector(_ENV) -local Config = require('config') +local Config = require('opus.config') local pt = turtle.enableGPS() if pt then local config = Config.load('gps', { }) diff --git a/common/etc/scripts/summon b/common/etc/scripts/summon index 45e0c9e..66dcded 100644 --- a/common/etc/scripts/summon +++ b/common/etc/scripts/summon @@ -2,9 +2,9 @@ local function summon(id) _G.requireInjector(_ENV) - local GPS = require('gps') - local Point = require('point') - local Socket = require('socket') + local GPS = require('opus.gps') + local Point = require('opus.point') + local Socket = require('opus.socket') turtle.setStatus('GPSing') turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 }) diff --git a/ignore/Music.lua b/ignore/Music.lua index 2af2b86..7ff44c2 100644 --- a/ignore/Music.lua +++ b/ignore/Music.lua @@ -250,5 +250,3 @@ turtle.setStatus('Jamming') UI:pullEvents() turtle.setStatus('idle') page:play(false) - -UI.term:reset() diff --git a/milo/plugins/item/resetTab.lua b/milo/plugins/item/resetTab.lua index a0a12ae..0d9d34d 100644 --- a/milo/plugins/item/resetTab.lua +++ b/milo/plugins/item/resetTab.lua @@ -9,7 +9,7 @@ local context = Milo:getContext() local resetTab = UI.Tab { tabTitle = 'Reset', index = 5, - backgroundColor = colors.cyan, + noFill = true, textArea = UI.TextArea { y = 2, ey = 6, textColor = colors.yellow, diff --git a/miners/scanningMiner.lua b/miners/scanningMiner.lua index 1d5e361..588259b 100644 --- a/miners/scanningMiner.lua +++ b/miners/scanningMiner.lua @@ -637,8 +637,7 @@ Event.addRoutine(function() end) UI:setPage(page) -UI:pullEvents() -UI.term:reset() +UI:start() turtle.reset() diff --git a/recipeBook/recipeBook.lua b/recipeBook/recipeBook.lua index 4922929..4df6acb 100644 --- a/recipeBook/recipeBook.lua +++ b/recipeBook/recipeBook.lua @@ -100,11 +100,10 @@ function page.info:draw() self:clear() if book then - self:setCursorPos(1, 1) self:print( - string.format('Name: %s%s%s\n', Ansi.yellow, book.name, Ansi.reset)) - self:print( - string.format('Version: %s%s%s\n', Ansi.yellow, book.version, Ansi.reset)) + string.format('Name: %s%s%s\nVersion: %s%s%s\n', + Ansi.yellow, book.name, Ansi.reset, + Ansi.yellow, book.version, Ansi.reset)) self.button.text = book.enabled and 'Disable' or 'Enable' self.button:draw() diff --git a/turtle/autorun/6.tl3.lua b/turtle/init/6.tl3.lua similarity index 100% rename from turtle/autorun/6.tl3.lua rename to turtle/init/6.tl3.lua -- 2.49.1 From 949c4855399cb035ca93157d296c351722c52315 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 17 Apr 2020 20:41:58 -0600 Subject: [PATCH 11/12] changes for deprecated ui methods - recolor milo - make turtle scripts run again - mob rancher improvements --- builder/builder.lua | 6 +- common/Appstore.lua | 4 +- common/Devices.lua | 4 +- common/DiskCopy.lua | 2 +- common/Events.lua | 2 +- common/Follow.lua | 2 +- common/SoundPlayer.lua | 2 +- common/Turtles.lua | 46 ++++++---- common/etc/scripts/moveTo | 29 ------ common/etc/scripts/moveTo.lua | 17 ++++ gps/gpsServer.lua | 2 +- milo/MiloLocal.lua | 2 +- milo/MiloRemote.lua | 8 +- milo/core/listing.lua | 8 +- milo/core/machines.lua | 11 +-- milo/plugins/activityView.lua | 1 - milo/plugins/backupView.lua | 2 - milo/plugins/brewingStandView.lua | 1 - milo/plugins/emitterView.lua | 2 - milo/plugins/inputChestView.lua | 2 - milo/plugins/item/infoTab.lua | 3 - milo/plugins/item/machinesTab.lua | 1 - milo/plugins/item/recipeTab.lua | 3 - milo/plugins/jobMonitor.lua | 1 - milo/plugins/remote/setup.lua | 3 +- milo/plugins/speakerView.lua | 1 - milo/plugins/statsView.lua | 6 +- milo/plugins/storageView.lua | 2 - milo/plugins/transferView.lua | 1 - milo/plugins/trashcanView.lua | 1 - neural/Equipment.lua | 142 ++++++++++++++++++++++++++++++ neural/Scanner.lua | 4 +- neural/Sensor.lua | 4 +- neural/etc/apps.db | 6 ++ neural/mobRancher.lua | 35 +++++--- recipeBook/recipeBook.lua | 4 +- secure/autorun/lock.lua | 4 +- swshop/Shoplogs.lua | 2 +- swshop/shopConfig.lua | 4 +- 39 files changed, 258 insertions(+), 122 deletions(-) delete mode 100644 common/etc/scripts/moveTo create mode 100644 common/etc/scripts/moveTo.lua create mode 100644 neural/Equipment.lua diff --git a/builder/builder.lua b/builder/builder.lua index 7e7638f..c021169 100644 --- a/builder/builder.lua +++ b/builder/builder.lua @@ -724,8 +724,7 @@ function startPage:eventHandler(event) Builder:begin() elseif event.type == 'quit' then - UI.term:reset() - Event.exitPullEvents() + UI:quit() end return UI.Page.eventHandler(self, event) @@ -769,5 +768,4 @@ UI:setPages({ }) UI:setPage('start') - -UI:pullEvents() +UI:start() diff --git a/common/Appstore.lua b/common/Appstore.lua index 2bbb521..7576f5f 100644 --- a/common/Appstore.lua +++ b/common/Appstore.lua @@ -354,7 +354,7 @@ function categoryPage:eventHandler(event) self:draw() elseif event.type == 'quit' then - UI:exitPullEvents() + UI:quit() else return UI.Page.eventHandler(self, event) @@ -366,4 +366,4 @@ print("Retrieving catalog list") categoryPage:setCategory(source.name, source.index) UI:setPage(categoryPage) -UI:pullEvents() +UI:start() diff --git a/common/Devices.lua b/common/Devices.lua index 0415291..22177b9 100644 --- a/common/Devices.lua +++ b/common/Devices.lua @@ -49,7 +49,7 @@ end function peripheralsPage:eventHandler(event) if event.type == 'quit' then - Event.exitPullEvents() + UI:quit() elseif event.type == 'grid_select' then UI:setPage('methods', event.selected) @@ -198,4 +198,4 @@ UI:setPages({ methods = methodsPage, }) -UI:pullEvents() +UI:start() diff --git a/common/DiskCopy.lua b/common/DiskCopy.lua index a0d41ef..ef1f4a6 100644 --- a/common/DiskCopy.lua +++ b/common/DiskCopy.lua @@ -269,4 +269,4 @@ Event.onTimeout(.2, function() end) UI:setPage(page) -UI:pullEvents() +UI:start() diff --git a/common/Events.lua b/common/Events.lua index 83f3fdd..783e38c 100644 --- a/common/Events.lua +++ b/common/Events.lua @@ -90,7 +90,7 @@ local page = UI.Page { self.grid:draw() elseif event.type == 'quit' then - UI:exitPullEvents() + UI:quit() else return UI.Page.eventHandler(self, event) diff --git a/common/Follow.lua b/common/Follow.lua index cd9afb2..6c2e84d 100644 --- a/common/Follow.lua +++ b/common/Follow.lua @@ -238,6 +238,6 @@ Event.addRoutine(function() end) UI:setPage(page) -UI:pullEvents() +UI:start() swarm:stop() diff --git a/common/SoundPlayer.lua b/common/SoundPlayer.lua index bcce449..bb36029 100644 --- a/common/SoundPlayer.lua +++ b/common/SoundPlayer.lua @@ -60,4 +60,4 @@ function page:eventHandler(event) end UI:setPage(page) -UI:pullEvents() +UI:start() diff --git a/common/Turtles.lua b/common/Turtles.lua index 947ec62..38bf888 100644 --- a/common/Turtles.lua +++ b/common/Turtles.lua @@ -292,30 +292,42 @@ function page:runScript(scriptName) print('Unable to read script file') end - local socket = Socket.connect(turtle.id, 161) - if not socket then - print('Unable to connect to ' .. turtle.id) - return - end - - local function processVariables(script) + local function processVariables() local variables = { - COMPUTER_ID = os.getComputerID(), + COMPUTER_ID = os.getComputerID, + GPS = function() + local pt = require('opus.gps').getPoint() + if not pt then + error('Unable to determine location') + end + return _G.textutils.serialize(pt) + end, } for k,v in pairs(variables) do local token = string.format('{%s}', k) - script = script:gsub(token, v) + if script:find(token, 1, true) then + local s, m = pcall(v) + if not s then + self.notification:error(m) + return + end + script = script:gsub(token, m) + end end - - return script + return true end - script = processVariables(script) + if processVariables(script) then + local socket = Socket.connect(turtle.id, 161) + if not socket then + self.notification:error('Unable to connect') + return + end + socket:write({ type = 'script', args = script }) + socket:close() - socket:write({ type = 'script', args = script }) - socket:close() - - self.notification:success('Sent') + self.notification:success('Sent') + end end end @@ -339,7 +351,7 @@ end function page:eventHandler(event) if event.type == 'quit' then - UI:exitPullEvents() + UI:quit() elseif event.type == 'tab_select' then config.tab = event.button.text diff --git a/common/etc/scripts/moveTo b/common/etc/scripts/moveTo deleted file mode 100644 index 11be075..0000000 --- a/common/etc/scripts/moveTo +++ /dev/null @@ -1,29 +0,0 @@ -turtle.run(function() - - _G.requireInjector(_ENV) - - local GPS = require('opus.gps') - local Socket = require('opus.socket') - - local id = {COMPUTER_ID} - - if not turtle.enableGPS() then - error('turtle: No GPS found') - end - - local socket = Socket.connect(id, 161) - if not socket then - error('turtle: Unable to connect to ' .. id) - end - - socket:write({ type = 'gps' }) - - local pt = socket:read(3) - if not pt then - error('turtle: No GPS response') - end - - if not turtle.pathfind(pt) then - error('Unable to go to location') - end -end) diff --git a/common/etc/scripts/moveTo.lua b/common/etc/scripts/moveTo.lua new file mode 100644 index 0000000..72d597a --- /dev/null +++ b/common/etc/scripts/moveTo.lua @@ -0,0 +1,17 @@ +local turtle = _G.turtle + +turtle.run(function() + _G.requireInjector(_ENV) + + local GPS = require('opus.gps') + + if not turtle.enableGPS() then + error('turtle: No GPS found') + end + + local pt = {GPS} + + if not turtle.pathfind(pt) then + error('Unable to go to location') + end +end) diff --git a/gps/gpsServer.lua b/gps/gpsServer.lua index 5c60926..7f6aaed 100644 --- a/gps/gpsServer.lua +++ b/gps/gpsServer.lua @@ -313,4 +313,4 @@ else end UI:setPage(page) -UI:pullEvents() +UI:start() diff --git a/milo/MiloLocal.lua b/milo/MiloLocal.lua index 68b409f..7ba699b 100644 --- a/milo/MiloLocal.lua +++ b/milo/MiloLocal.lua @@ -216,7 +216,7 @@ _G._syslog = function(...) end local s, m = pcall(function() - UI:pullEvents() + UI:start() end) turtle.setStatus('idle') diff --git a/milo/MiloRemote.lua b/milo/MiloRemote.lua index c2dc4f1..f9c6e8c 100644 --- a/milo/MiloRemote.lua +++ b/milo/MiloRemote.lua @@ -63,8 +63,8 @@ local page = UI.Page { x = 1, ex = -13, limit = 50, shadowText = 'filter', - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = UI.colors.primary, + backgroundFocusColor = UI.colors.primary, accelerators = { [ 'enter' ] = 'eject', [ 'up' ] = 'grid_up', @@ -169,7 +169,7 @@ end function page:eventHandler(event) if event.type == 'quit' then - UI:exitPullEvents() + UI:quit() elseif event.type == 'setup' then self.setup.form:setValues(context.state) @@ -524,7 +524,7 @@ local programDir = fs.getDir(shell.getRunningProgram()) loadDirectory(fs.combine(programDir, 'plugins/remote')) UI:setPage(page) -UI:pullEvents() +UI:start() if context.socket then context.socket:close() diff --git a/milo/core/listing.lua b/milo/core/listing.lua index 994ceba..aa23978 100644 --- a/milo/core/listing.lua +++ b/milo/core/listing.lua @@ -54,8 +54,8 @@ local page = UI.Page { limit = 50, shadowText = 'filter', shadowTextColor = colors.gray, - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = UI.colors.primary, + backgroundFocusColor = UI.colors.primary, accelerators = { [ 'enter' ] = 'eject', [ 'up' ] = 'grid_up', @@ -66,7 +66,7 @@ local page = UI.Page { storageStatus = UI.Text { x = -17, ex = -10, textColor = colors.lime, - backgroundColor = colors.cyan, + backgroundColor = UI.colors.primary, value = '', }, amount = UI.TextEntry { @@ -208,7 +208,7 @@ end function page:eventHandler(event) if event.type == 'quit' then - UI:exitPullEvents() + UI:quit() elseif event.type == 'eject' or event.type == 'grid_select' then self:eject(1) diff --git a/milo/core/machines.lua b/milo/core/machines.lua index 99c61b5..23cb9f1 100644 --- a/milo/core/machines.lua +++ b/milo/core/machines.lua @@ -7,7 +7,6 @@ local Util = require('opus.util') local colors = _G.colors local device = _G.device -local turtle = _G.turtle local context = Milo:getContext() @@ -22,8 +21,8 @@ local networkPage = UI.Page { y = -2, x = 1, ex = -9, limit = 50, shadowText = 'filter', - backgroundColor = colors.cyan, - backgroundFocusColor = colors.cyan, + backgroundColor = UI.colors.primary, + backgroundFocusColor = UI.colors.primary, }, grid = UI.ScrollingGrid { y = 2, ey = -3, @@ -195,7 +194,6 @@ nodeWizard = UI.Page { pages = { general = UI.WizardPage { index = 1, - backgroundColor = colors.cyan, form = UI.Form { x = 2, ex = -2, y = 1, ey = 3, manualControls = true, @@ -236,11 +234,10 @@ The settings will take effect immediately!]], }, }, statusBar = UI.StatusBar { - backgroundColor = colors.cyan, + backgroundColor = UI.colors.primary, }, notification = UI.Notification { }, filter = UI.SlideOut { - backgroundColor = colors.cyan, noFill = true, menuBar = UI.MenuBar { buttons = { @@ -292,7 +289,7 @@ The settings will take effect immediately!]], }, }, statusBar = UI.StatusBar { - backgroundColor = colors.cyan, + backgroundColor = UI.colors.primary, }, }, } diff --git a/milo/plugins/activityView.lua b/milo/plugins/activityView.lua index 723d313..1d8cffd 100644 --- a/milo/plugins/activityView.lua +++ b/milo/plugins/activityView.lua @@ -17,7 +17,6 @@ Right-clicking on the activity monitor will reset the totals.]] local wizardPage = UI.WizardPage { title = 'Activity Monitor', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, ex = -2, y = 2, ey = 6, marginRight = 0, diff --git a/milo/plugins/backupView.lua b/milo/plugins/backupView.lua index f52a00e..f53516a 100644 --- a/milo/plugins/backupView.lua +++ b/milo/plugins/backupView.lua @@ -3,7 +3,6 @@ local Event = require('opus.event') local Milo = require('milo') local UI = require('opus.ui') -local colors = _G.colors local device = _G.device local fs = _G.fs local os = _G.os @@ -23,7 +22,6 @@ Backup configuration files each minecraft day. local wizardPage = UI.WizardPage { title = 'Backup Drive', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, ex = -2, y = 2, ey = -2, value = string.format(template, Ansi.yellow, Ansi.reset), diff --git a/milo/plugins/brewingStandView.lua b/milo/plugins/brewingStandView.lua index 88b550a..c97004e 100644 --- a/milo/plugins/brewingStandView.lua +++ b/milo/plugins/brewingStandView.lua @@ -18,7 +18,6 @@ Note that you do not need to import items from the brewing stand or export blaze local wizardPage = UI.WizardPage { title = 'Brewing Stand', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, ex = -2, y = 2, ey = -2, value = string.format(template, Ansi.yellow, Ansi.reset), diff --git a/milo/plugins/emitterView.lua b/milo/plugins/emitterView.lua index f3c51d3..6198a6a 100644 --- a/milo/plugins/emitterView.lua +++ b/milo/plugins/emitterView.lua @@ -4,12 +4,10 @@ local itemDB = require('core.itemDB') local colors = _G.colors local device = _G.device -local context = Milo:getContext() local wizardPage = UI.WizardPage { title = 'Level Emitter', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, y = 1, height = 2, diff --git a/milo/plugins/inputChestView.lua b/milo/plugins/inputChestView.lua index fe0fd9a..5709f3b 100644 --- a/milo/plugins/inputChestView.lua +++ b/milo/plugins/inputChestView.lua @@ -1,7 +1,6 @@ local Ansi = require('opus.ansi') local UI = require('opus.ui') -local colors = _G.colors local device = _G.device --[[ Configuration Screen ]] @@ -14,7 +13,6 @@ Any items placed in this chest will be imported into storage. local inputChestWizardPage = UI.WizardPage { title = 'Input Chest', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, ex = -2, y = 2, ey = -2, value = string.format(template, Ansi.yellow, Ansi.reset), diff --git a/milo/plugins/item/infoTab.lua b/milo/plugins/item/infoTab.lua index 5bf7cc9..fb96fc1 100644 --- a/milo/plugins/item/infoTab.lua +++ b/milo/plugins/item/infoTab.lua @@ -1,12 +1,9 @@ local Ansi = require('opus.ansi') local UI = require('opus.ui') -local colors = _G.colors - local infoTab = UI.Tab { tabTitle = 'Info', index = 4, - backgroundColor = colors.cyan, textArea = UI.TextArea { x = 2, ex = -2, y = 2, ey = -2, }, diff --git a/milo/plugins/item/machinesTab.lua b/milo/plugins/item/machinesTab.lua index 4ff7e04..8f52595 100644 --- a/milo/plugins/item/machinesTab.lua +++ b/milo/plugins/item/machinesTab.lua @@ -9,7 +9,6 @@ local context = Milo:getContext() local machinesTab = UI.Tab { tabTitle = 'Machine', index = 3, - backgroundColor = colors.cyan, grid = UI.ScrollingGrid { x = 2, ex = -2, y = 2, ey = -2, disableHeader = true, diff --git a/milo/plugins/item/recipeTab.lua b/milo/plugins/item/recipeTab.lua index 0a08fca..93e321f 100644 --- a/milo/plugins/item/recipeTab.lua +++ b/milo/plugins/item/recipeTab.lua @@ -3,12 +3,9 @@ local itemDB = require('core.itemDB') local Milo = require('milo') local UI = require('opus.ui') -local colors = _G.colors - local recipeTab = UI.Tab { tabTitle = 'Recipe', index = 2, - backgroundColor = colors.cyan, grid = UI.ScrollingGrid { x = 2, ex = -2, y = 2, ey = -4, disableHeader = true, diff --git a/milo/plugins/jobMonitor.lua b/milo/plugins/jobMonitor.lua index 846e279..a548fcf 100644 --- a/milo/plugins/jobMonitor.lua +++ b/milo/plugins/jobMonitor.lua @@ -15,7 +15,6 @@ local os = _G.os local wizardPage = UI.WizardPage { title = 'Crafting Monitor', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, ex = -2, y = 2, ey = 3, marginRight = 0, diff --git a/milo/plugins/remote/setup.lua b/milo/plugins/remote/setup.lua index 1ea8de3..4688300 100644 --- a/milo/plugins/remote/setup.lua +++ b/milo/plugins/remote/setup.lua @@ -10,7 +10,6 @@ local STARTUP_FILE = 'usr/autorun/miloRemote.lua' local context = ({ ... })[1] local setup = UI.SlideOut { - backgroundColor = colors.cyan, titleBar = UI.TitleBar { title = 'Remote Setup', }, @@ -51,7 +50,7 @@ local setup = UI.SlideOut { [[also have an introspection module.]], }, statusBar = UI.StatusBar { - backgroundColor = colors.cyan, + backgroundColor = UI.colors.primary, }, } diff --git a/milo/plugins/speakerView.lua b/milo/plugins/speakerView.lua index c5668dc..1b5cd3c 100644 --- a/milo/plugins/speakerView.lua +++ b/milo/plugins/speakerView.lua @@ -14,7 +14,6 @@ end local wizardPage = UI.WizardPage { title = 'Speaker', index = 2, - backgroundColor = colors.cyan, [1] = UI.Text { x = 2, y = 2, textColor = colors.yellow, diff --git a/milo/plugins/statsView.lua b/milo/plugins/statsView.lua index 4f70601..b6ab90c 100644 --- a/milo/plugins/statsView.lua +++ b/milo/plugins/statsView.lua @@ -18,7 +18,6 @@ Right-clicking on the activity monitor will reset the totals.]] local wizardPage = UI.WizardPage { title = 'Status Monitor', index = 2, - backgroundColor = colors.cyan, [1] = UI.TextArea { x = 2, ex = -2, y = 2, ey = 6, marginRight = 0, @@ -137,12 +136,14 @@ local function createPage(node) }, [2] = UI.Tab { tabTitle = 'Stats', + noFill = true, textArea = UI.TextArea { y = 3, }, }, [3] = UI.Tab { tabTitle = 'Storage', + noFill = true, grid = UI.ScrollingGrid { y = 2, columns = { @@ -157,6 +158,7 @@ local function createPage(node) }, [4] = UI.Tab { tabTitle = 'Offline', + noFill = true, grid = UI.ScrollingGrid { y = 2, columns = { @@ -167,12 +169,14 @@ local function createPage(node) }, [5] = UI.Tab { tabTitle = 'Activity', + noFill = true, term = UI.Embedded { --visible = true, }, }, [6] = UI.Tab { tabTitle = 'Tasks', + noFill = true, grid = UI.ScrollingGrid { y = 2, values = context.tasks, diff --git a/milo/plugins/storageView.lua b/milo/plugins/storageView.lua index b1d51c2..18e2c0e 100644 --- a/milo/plugins/storageView.lua +++ b/milo/plugins/storageView.lua @@ -7,7 +7,6 @@ local device = _G.device local storageView = UI.WizardPage { title = 'Storage Options - General', index = 2, - backgroundColor = colors.cyan, form = UI.Form { x = 2, ex = -2, y = 1, ey = -2, manualControls = true, @@ -62,7 +61,6 @@ UI:getPage('nodeWizard').wizard:add({ storageGeneral = storageView }) local lockView = UI.WizardPage { title = 'Storage Options - Locking', index = 3, - backgroundColor = colors.cyan, form = UI.Form { x = 2, ex = -2, y = 1, ey = 3, manualControls = true, diff --git a/milo/plugins/transferView.lua b/milo/plugins/transferView.lua index 3fa70ff..df6079e 100644 --- a/milo/plugins/transferView.lua +++ b/milo/plugins/transferView.lua @@ -12,7 +12,6 @@ local context = Milo:getContext() local wizardPage = UI.WizardPage { title = 'Transfer Inventory', index = 2, - backgroundColor = colors.cyan, grid = UI.ScrollingGrid { y = 2, ey = -2, values = context.storage.nodes, diff --git a/milo/plugins/trashcanView.lua b/milo/plugins/trashcanView.lua index 2de4a4e..fc1e70f 100644 --- a/milo/plugins/trashcanView.lua +++ b/milo/plugins/trashcanView.lua @@ -9,7 +9,6 @@ local device = _G.device local wizardPage = UI.WizardPage { title = 'Trashcan', index = 2, - backgroundColor = colors.cyan, info = UI.TextArea { x = 1, ex = -1, y = 2, ey = 4, textColor = colors.yellow, diff --git a/neural/Equipment.lua b/neural/Equipment.lua new file mode 100644 index 0000000..32b849e --- /dev/null +++ b/neural/Equipment.lua @@ -0,0 +1,142 @@ +local Event = require('opus.event') +local itemDB = require('core.itemDB') +local neural = require('neural.interface') +local UI = require('opus.ui') +local Util = require('opus.util') + +local device = _G.device + +neural.assertModules({ + 'plethora:sensor', + 'plethora:kinetic', + 'plethora:introspection', +}) +UI:configure('Equipment', ...) + +local equipment = device.neuralInterface.getEquipment() + +local slots = { + 'primary', + 'offhand', + 'boots', + 'leggings', + 'chest', + 'helmet', +} + +local page = UI.Page { + menuBar = UI.MenuBar { + buttons = { + { text = 'Drop', event = 'drop' }, + { text = 'Suck', event = 'suck' }, + }, + }, + grid = UI.Grid { + y = 2, + columns = { + { heading = 'Slot', key = 'index', width = 7 }, + { heading = 'Name', key = 'displayName' }, + { heading = 'Count', key = 'count', width = 5, align = 'right' }, + }, + sortColumn = 'index', + accelerators = { + grid_select = 'show_detail', + }, + getDisplayValues = function(_, row) + row = Util.shallowCopy(row) + if row.name then + local item = itemDB:get( + table.concat({ row.name, row.damage, row.nbtHash }, ':'), + function() + return equipment.getItemMeta(row.index) + end) + row.displayName = item.displayName + else + row.displayName = 'empty' + end + row.index = slots[row.index] + return row + end, + }, + accelerators = { + [ 'control-q' ] = 'quit', + }, + detail = UI.SlideOut { + menuBar = UI.MenuBar { + buttons = { + { text = 'Back', event = 'slide_hide' }, + }, + }, + grid = UI.ScrollingGrid { + y = 2, + columns = { + { heading = 'Name', key = 'name' }, + { heading = 'Value', key = 'value' }, + }, + sortColumn = 'name', + accelerators = { + grid_select = 'inspect', + }, + }, + show = function(self, slot) + local detail = equipment.getItemMeta(slot.index) + local t = { } + for k,v in pairs(detail) do + table.insert(t, { + name = k, + value = v, + }) + end + self.grid:setValues(t) + self.grid:setIndex(1) + UI.SlideOut.show(self) + end, + }, + enable = function(self) + self:refresh() + UI.Page.enable(self) + end, + refresh = function(self) + local t = { } + local list = equipment.list() + for i = 1, equipment.size() do + local v = list[i] or { } + v.index = i + table.insert(t, v) + end + self.grid:setValues(t) + self.grid:draw() + end, + eventHandler = function(self, event) + if event.type == 'quit' then + UI:quit() + + elseif event.type == 'show_detail' then + if event.selected.name then + self.detail:show(event.selected) + end + + elseif event.type == 'drop' then + local selected = self.grid:getSelected() + equipment.drop(selected.index) + self:refresh() + + elseif event.type == 'suck' then + local selected = self.grid:getSelected() + equipment.suck(selected.index) + self:refresh() + end + + UI.Page.eventHandler(self, event) + end, +} + +Event.onInterval(1, function() + page:refresh() + page:sync() +end) + +UI:setPage(page) +UI:start() + +itemDB:flush() diff --git a/neural/Scanner.lua b/neural/Scanner.lua index 11edab2..4dd6be5 100644 --- a/neural/Scanner.lua +++ b/neural/Scanner.lua @@ -182,7 +182,7 @@ end function page:eventHandler(event) if event.type == 'quit' then - Event.exitPullEvents() + UI:quit() elseif event.type == 'scan' then self:scan() @@ -211,7 +211,7 @@ Event.onTimeout(0, function() page:sync() end) -UI:pullEvents() +UI:start() if canvas then canvas:clear() diff --git a/neural/Sensor.lua b/neural/Sensor.lua index d926c05..42d0b9a 100644 --- a/neural/Sensor.lua +++ b/neural/Sensor.lua @@ -253,7 +253,7 @@ end function page:eventHandler(event) if event.type == 'quit' then - Event.exitPullEvents() + UI:quit() elseif event.type == 'tab_activate' then config.activeTab = event.activated.tabTitle @@ -268,7 +268,7 @@ if config.activeTab then end UI:setPage(page) -UI:pullEvents() +UI:start() if canvas then canvas:clear() diff --git a/neural/etc/apps.db b/neural/etc/apps.db index 61040b2..31c01d7 100644 --- a/neural/etc/apps.db +++ b/neural/etc/apps.db @@ -29,4 +29,10 @@ run = "ores.lua", requires = "neuralInterface", }, + [ "7f2465ac7cefab2766e6ee0714647089df9364b0ff09858c84b21b8a436a845d" ] = { + title = "Equipment", + category = "Neural", + run = "Equipment", + requires = "neuralInterface", + } } diff --git a/neural/mobRancher.lua b/neural/mobRancher.lua index c09d7d3..51ce614 100644 --- a/neural/mobRancher.lua +++ b/neural/mobRancher.lua @@ -1,6 +1,15 @@ --[[ - Breed either cows or sheep. - Must be run on a mob with the same height. + Changed to use a 2-high mob (smaller mobs may work ?) + Updated due to entity.look working correctly now. + + The mob looks head-on to the lever. Make sure the + lever is accessible by the mob. + + Laser is now optional - if no laser, the mobs will be + punched (or provide a stick). Best mob may be a + skeleton (unlimited ammo). + + Feeding hand has been changed to off-hand. ]] local Array = require('opus.array') @@ -21,7 +30,7 @@ local WALK_SPEED = 1.5 neural.assertModules({ 'plethora:sensor', 'plethora:scanner', - 'plethora:laser', + --'plethora:laser', 'plethora:kinetic', 'plethora:introspection', }) @@ -29,27 +38,27 @@ neural.assertModules({ local fed = { } local function resupply() - local slot = neural.getEquipment().list()[1] + local slot = neural.getEquipment().list()[2] if slot and slot.count > 32 then return end print('resupplying') for _ = 1, 2 do - local dispenser = Map.find(neural.scan(), 'name', 'minecraft:dispenser') + local dispenser = Map.find(neural.scan(), 'name', 'minecraft:lever') if not dispenser then print('dispenser not found') break end if math.abs(dispenser.x) <= 1 and math.abs(dispenser.z) <= 1 then - neural.lookAt(dispenser) + neural.lookAt({ x = dispenser.x, y = dispenser.y, z = dispenser.z }) for _ = 1, 8 do neural.use(0, 'off') os.sleep(.2) - neural.getEquipment().suck(1, 64) + neural.getEquipment().suck(2, 64) end break else - neural.walkTo({ x = dispenser.x, y = 0, z = dispenser.z }, WALK_SPEED) + neural.walkTo({ x = dispenser.x, y = 0, z = dispenser.z }, WALK_SPEED, .5) end end end @@ -63,18 +72,22 @@ local function breed(entity) entity = neural.getMetaByID(entity.id) if entity then neural.lookAt(entity) - neural.use(1) + neural.use(1, 'off') os.sleep(.1) end end local function kill(entity) print('killing') - neural.walkTo(entity, WALK_SPEED, 2.5) + neural.walkTo(entity, WALK_SPEED, (neural.fire or neural.shoot) and 2.5 or .5) entity = neural.getMetaByID(entity.id) if entity then neural.lookAt(entity) - neural.fireAt({ x = entity.x, y = 0, z = entity.z }) + if neural.fire or neural.shoot then + neural.shootAt(entity) + else + neural.swing() + end Sound.play('entity.firework.launch') os.sleep(.2) end diff --git a/recipeBook/recipeBook.lua b/recipeBook/recipeBook.lua index 4df6acb..65d4fc7 100644 --- a/recipeBook/recipeBook.lua +++ b/recipeBook/recipeBook.lua @@ -172,11 +172,11 @@ function page:eventHandler(event) self.info:draw() elseif event.type == 'quit' then - UI:exitPullEvents() + UI:quit() end UI.Page.eventHandler(self, event) end UI:setPage(page) -UI:pullEvents() +UI:start() diff --git a/secure/autorun/lock.lua b/secure/autorun/lock.lua index f951dfc..a8965d7 100644 --- a/secure/autorun/lock.lua +++ b/secure/autorun/lock.lua @@ -49,7 +49,7 @@ local function buildLockScreen() #self.pass.value > 0 and Security.verifyPassword(SHA.compute(self.pass.value)) then - UI:exitPullEvents() -- valid + UI:quit() -- valid else self.notification:error('Invalid password', math.max(counter, 2)) self:sync() @@ -66,7 +66,7 @@ local function buildLockScreen() Event.onTerminate(function() return false end) UI:setPage(page) - UI:pullEvents() + UI:start() -- restart lock timer timer = os.startTimer(config.timeout) diff --git a/swshop/Shoplogs.lua b/swshop/Shoplogs.lua index 5766b08..5a478e3 100644 --- a/swshop/Shoplogs.lua +++ b/swshop/Shoplogs.lua @@ -189,4 +189,4 @@ end) page.grid:loadTransactions() UI:setPage(page) -UI:pullEvents() +UI:start() diff --git a/swshop/shopConfig.lua b/swshop/shopConfig.lua index 026ad16..761b587 100644 --- a/swshop/shopConfig.lua +++ b/swshop/shopConfig.lua @@ -9,7 +9,6 @@ local os = _G.os local wizardPage = UI.WizardPage { title = 'Store Front', index = 2, - backgroundColor = colors.cyan, form = UI.Form { x = 2, ex = -2, y = 1, ey = -2, manualControls = true, @@ -90,7 +89,6 @@ end local passwordPage = UI.WizardPage { title = 'Krist Settings', index = 3, - backgroundColor = colors.cyan, form = UI.Form { x = 2, ex = -2, y = 1, ey = -2, manualControls = true, @@ -112,7 +110,7 @@ local passwordPage = UI.WizardPage { preview = UI.TextEntry { formIndex = 4, formLabel = 'Using address', formKey = 'address', - backgroundColor = colors.cyan, + backgroundColor = UI.colors.primary, textColor = colors.yellow, inactive = true, }, -- 2.49.1 From d17162b49da4db9039f303f6dfc59e3ded6cfd53 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 21 Apr 2020 22:32:53 -0600 Subject: [PATCH 12/12] can now use named colors --- common/Devices.lua | 70 ++++++++++++------------ common/DiskCopy.lua | 4 ++ common/Turtles.lua | 2 +- common/edit.lua | 74 ++++++++++++-------------- common/recorder.lua | 91 ++++++++++++++++++-------------- milo/MiloRemote.lua | 4 +- milo/apis/massAdapter.lua | 53 ------------------- milo/core/listing.lua | 6 +-- milo/core/machines.lua | 8 +-- milo/plugins/item.lua | 1 - milo/plugins/massStorageView.lua | 43 --------------- milo/plugins/remote/setup.lua | 2 +- neural/mobRancher.lua | 83 +++++++++++++++++++---------- swshop/shopConfig.lua | 2 +- 14 files changed, 190 insertions(+), 253 deletions(-) delete mode 100644 milo/apis/massAdapter.lua delete mode 100644 milo/plugins/massStorageView.lua diff --git a/common/Devices.lua b/common/Devices.lua index 22177b9..fc2cecd 100644 --- a/common/Devices.lua +++ b/common/Devices.lua @@ -3,7 +3,6 @@ local Event = require('opus.event') local UI = require('opus.ui') local Util = require('opus.util') -local colors = _G.colors local peripheral = _G.peripheral --[[ -- PeripheralsPage -- ]] -- @@ -16,6 +15,20 @@ local peripheralsPage = UI.Page { }, sortColumn = 'type', autospace = true, + enable = function(self) + local sides = peripheral.getNames() + + Util.clear(self.values) + for _,side in pairs(sides) do + table.insert(self.values, { + type = peripheral.getType(side), + side = side + }) + end + self:update() + self:adjustWidth() + UI.Grid.enable(self) + end, }, statusBar = UI.StatusBar { values = 'Select peripheral', @@ -23,47 +36,30 @@ local peripheralsPage = UI.Page { accelerators = { [ 'control-q' ] = 'quit', }, + updatePeripherals = function(self) + if UI:getCurrentPage() == self then + self.grid:draw() + self:sync() + end + end, + eventHandler = function(self, event) + if event.type == 'quit' then + UI:quit() + + elseif event.type == 'grid_select' then + UI:setPage('methods', event.selected) + + end + return UI.Page.eventHandler(self, event) + end, } -function peripheralsPage.grid:enable() - local sides = peripheral.getNames() - - Util.clear(self.values) - for _,side in pairs(sides) do - table.insert(self.values, { - type = peripheral.getType(side), - side = side - }) - end - self:update() - self:adjustWidth() - UI.Grid.enable(self) -end - -function peripheralsPage:updatePeripherals() - if UI:getCurrentPage() == self then - self.grid:draw() - self:sync() - end -end - -function peripheralsPage:eventHandler(event) - if event.type == 'quit' then - UI:quit() - - elseif event.type == 'grid_select' then - UI:setPage('methods', event.selected) - - end - return UI.Page.eventHandler(self, event) -end - --[[ -- MethodsPage -- ]] -- local methodsPage = UI.Page { - backgroundColor = colors.black, doc = UI.TextArea { - backgroundColor = colors.black, - x = 2, y = 2, ex = -1, ey = -7, + backgroundColor = 'black', + ey = -7, + marginLeft = 1, marginTop = 1, }, grid = UI.ScrollingGrid { y = -6, ey = -2, diff --git a/common/DiskCopy.lua b/common/DiskCopy.lua index ef1f4a6..b3efc4e 100644 --- a/common/DiskCopy.lua +++ b/common/DiskCopy.lua @@ -137,6 +137,7 @@ function page:scan() self.copyButton.inactive = not valid self:draw() + self.progress:clear() self.progress:centeredWrite(1, 'Analyzing Disks..') self.progress:sync() @@ -166,6 +167,7 @@ function page:copy() throttle() end + self.progress:clear() self.progress:centeredWrite(1, 'Computing..') self.progress:sync() @@ -210,6 +212,8 @@ function page:copy() self.progress:clear() rawCopy(sdrive.getMountPath(), tdrive.getMountPath()) cleanup() + + self.progress:clear() self.progress:centeredWrite(1, 'Copy Complete', colors.lime, colors.black) self.progress:sync() diff --git a/common/Turtles.lua b/common/Turtles.lua index 38bf888..cc48825 100644 --- a/common/Turtles.lua +++ b/common/Turtles.lua @@ -131,7 +131,7 @@ page = UI.Page { columns = { { heading = '', key = 'index', width = 2 }, { heading = '', key = 'count', width = 2 }, - { heading = 'Inventory', key = 'key', width = UI.term.width - 7 }, + { heading = 'Inventory', key = 'key' }, }, disableHeader = true, sortColumn = 'index', diff --git a/common/edit.lua b/common/edit.lua index 7dcd028..804d40c 100644 --- a/common/edit.lua +++ b/common/edit.lua @@ -4,7 +4,6 @@ local fuzzy = require('opus.fuzzy') local UI = require('opus.ui') local Util = require('opus.util') -local colors = _G.colors local device = _G.device local fs = _G.fs local multishell = _ENV.multishell @@ -39,19 +38,25 @@ local undo = { chain = { }, redo = { } } h = h - 1 +local bgColor = 'gray' local color = { - textColor = '0', - keywordColor = '4', - commentColor = 'd', - stringColor = 'e', + text = '0', + keyword = '2', + comment = 'd', + string = '1', + mark = '8', + bg = '7', } if not term.isColor() then + bgColor = 'black' color = { - textColor = '0', - keywordColor = '8', - commentColor = '8', - stringColor = '8', + text = '0', + keyword = '8', + comment = '8', + string = '8', + mark = '7', + bg = 'f', } end @@ -161,7 +166,7 @@ local page = UI.Page { } }, }, status = UI.Text { - textColor = colors.gray, + textColor = 'gray', x = -9, width = 9, align = 'right', }, @@ -172,8 +177,6 @@ local page = UI.Page { lineNo = UI.TextEntry { x = 7, width = 7, limit = 5, - backgroundFocusColor = colors.gray, - backgroundColor = colors.gray, transform = 'number', accelerators = { [ 'enter' ] = 'accept', @@ -200,9 +203,6 @@ local page = UI.Page { search = UI.TextEntry { x = 7, ex = -3, limit = 512, - markBackgroundColor = colors.lightGray, - backgroundFocusColor = colors.gray, - backgroundColor = colors.gray, accelerators = { [ 'enter' ] = 'accept', }, @@ -233,9 +233,6 @@ local page = UI.Page { filename = UI.TextEntry { x = 7, ex = -3, limit = 512, - markBackgroundColor = colors.lightGray, - backgroundFocusColor = colors.gray, - backgroundColor = colors.gray, accelerators = { [ 'enter' ] = 'accept', }, @@ -263,7 +260,7 @@ local page = UI.Page { cancel = UI.Button { x = 16, text = 'Cancel', - backgroundColor = UI.colors.primary, + backgroundColor = 'primary', event = 'question_cancel', }, show = function(self, action) @@ -355,7 +352,7 @@ local page = UI.Page { disableHeader = true, columns = { { key = 'name' }, - { key = 'dir', textColor = colors.lightGray }, + { key = 'dir', textColor = 'lightGray' }, }, accelerators = { grid_select = 'accept', @@ -453,9 +450,9 @@ local page = UI.Page { cancel = UI.Button { y = -1, x = -9, text = 'Cancel', - backgroundColor = colors.black, - backgroundFocusColor = colors.black, - textColor = colors.lightGray, + backgroundColor = 'black', + backgroundFocusColor = 'black', + textColor = 'lightGray', event = 'slide_hide', }, show = function(self, values) @@ -540,9 +537,9 @@ local page = UI.Page { cancel = UI.Button { y = -1, x = -9, text = 'Cancel', - backgroundColor = colors.black, - backgroundFocusColor = colors.black, - textColor = colors.lightGray, + backgroundColor = 'black', + backgroundFocusColor = 'black', + textColor = 'lightGray', event = 'slide_hide', }, eventHandler = function(self, event) @@ -562,7 +559,7 @@ local page = UI.Page { }, editor = UI.Window { y = 2, - backgroundColor = colors.black, + backgroundColor = bgColor, transitionHint = 'slideRight', cursorBlink = true, focus = function(self) @@ -687,15 +684,15 @@ local function writeHighlighted(sLine, ny, dy) while #sLine > 0 do sLine = -- tryWrite(sLine, "^[%\26]", '7' ) or - tryWrite(sLine, "^%-%-%[%[.-%]%]", color.commentColor ) or - tryWrite(sLine, "^%-%-.*", color.commentColor ) or - tryWrite(sLine, "^\".-[^\\]\"", color.stringColor ) or - tryWrite(sLine, "^\'.-[^\\]\'", color.stringColor ) or - tryWrite(sLine, "^%[%[.-%]%]", color.stringColor ) or + tryWrite(sLine, "^%-%-%[%[.-%]%]", color.comment ) or + tryWrite(sLine, "^%-%-.*", color.comment ) or + tryWrite(sLine, "^\".-[^\\]\"", color.string ) or + tryWrite(sLine, "^\'.-[^\\]\'", color.string ) or + tryWrite(sLine, "^%[%[.-%]%]", color.string ) or tryWrite(sLine, "^[%w_]+", function(match) - return keywords[match] and color.keywordColor or color.textColor + return keywords[match] and color.keyword or color.text end) or - tryWrite(sLine, "^[^%w_]", color.textColor) + tryWrite(sLine, "^[^%w_]", color.text) end buffer.fg = _concat(buffer.fg) .. '7' @@ -704,11 +701,11 @@ local function writeHighlighted(sLine, ny, dy) if mark.active and ny >= mark.y and ny <= mark.ey then local sx = ny == mark.y and mark.x or 1 local ex = ny == mark.ey and mark.ex or #buffer.text - buffer.bg = _rep('f', sx - 1) .. - _rep('7', ex - sx) .. - _rep('f', #buffer.text - ex + 1) + buffer.bg = _rep(color.bg, sx - 1) .. + _rep(color.mark, ex - sx) .. + _rep(color.bg, #buffer.text - ex + 1) else - buffer.bg = _rep('f', #buffer.text) + buffer.bg = _rep(color.bg, #buffer.text) end page.editor:blit(1 - scrollX, dy, buffer.text, buffer.bg, buffer.fg) @@ -860,7 +857,6 @@ actions = { end actions.go_to(nx, ny) actions.mark_to(nx + #pattern, ny) - actions.go_to(nx, ny) return end sx = 1 diff --git a/common/recorder.lua b/common/recorder.lua index 908e58f..4ea8824 100644 --- a/common/recorder.lua +++ b/common/recorder.lua @@ -19,10 +19,14 @@ local Util = require('opus.util') local multishell = _ENV.multishell local os = _G.os -local recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput = {}, Util.shallowCopy(multishell.term), {...}, false, false, 2, "" +local colours = _G.colors + +local args, options = Util.parse(...) + +local oldTerm, showInput, skipLast, lastDelay, curInput = Util.shallowCopy(multishell.term), false, false, 2, "" local curBlink, oldBlink, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, oldTerm.getSize() local greys, buttons = {["0"] = true, ["7"] = true, ["8"] = true, ["f"] = true}, {"l", "r", "m"} -local charW, charH, chars, resp +local charW, charH, chars local calls = { } local curCalls = { delay = 0 } @@ -32,38 +36,44 @@ local callCount = 0 local function showSyntax() print('Gif Recorder by Bomb Bloke\n') print('Syntax: recGif [-i] [-s] [-ld:] filename') - print(' -i : show input') - print(' -s : skip last') - print(' -ld : last delay') + print(' --showInput : show input') + print(' --skipLast : skip last') + print(' --lastDelay : last delay') + print(' --noResize : dont resize') end -for i = #arg, 1, -1 do - local curArg = arg[i]:lower() - - if curArg == "-i" then - showInput, ySize = true, ySize + 1 - table.remove(arg, i) - elseif curArg == "-s" then - skipLast = true - table.remove(arg, i) - elseif curArg:sub(1, 4) == "-ld:" then - curArg = tonumber(curArg:sub(5)) - if curArg then lastDelay = curArg end - table.remove(arg, i) - elseif curArg == '-?' then - showSyntax() - return - elseif i ~= #arg then - showSyntax() - printError('\nInvalid argument') - return - end +if options.showInput then + showInput, ySize = true, ySize + 1 end -print('Gif Recorder by Bomb Bloke\n') -print('Press control-p to stop recording') +if options.skipLast then + skipLast = true +end -local filename = arg[#arg] +if options.lastDelay then + lastDelay = options.lastDelay +end + +if options.help then + showSyntax() + return +end + +if options.daemon then + device.keyboard.addHotkey('control-P', function() + multishell.openTab({ + path = 'sys/apps/shell.lua', + args = { arg[0], '--noResize', '--rawOutput', 'recorder.gif' }, + }) + end) + return +end + +print('Gif Recorder by Bomb Bloke') +print(version) +print('\nPress control-p to stop recording') + +local filename = args[1] if not filename then print('Enter file name:') filename = read() @@ -131,7 +141,7 @@ end -- Build a terminal that records stuff: -recTerm = multishell.term +local recTerm = multishell.term for key, func in pairs(oldTerm) do if type(func) == 'function' then @@ -149,21 +159,16 @@ for key, func in pairs(oldTerm) do end local tabId = multishell.getCurrent() +multishell.hideTab(tabId) + +if not options.noResize then + os.queueEvent('term_resize') +end _G.device.keyboard.addHotkey('control-p', function() os.queueEvent('recorder_stop') end) -local tabs = multishell.getTabs() -for _,tab in pairs(tabs) do - if tab.isOverview then - multishell.hideTab(tabId) - multishell.setFocus(tab.tabId) - os.queueEvent('term_resize') - break - end -end - local curTime = os.clock() - 1 while true do @@ -202,8 +207,12 @@ if skipLast and #calls > 1 then calls[#calls] = nil end calls[#calls].delay = lastDelay +if options.rawOutput then + Util.writeTable('tmp/raw.txt', calls) + return +end + print(string.format("Encoding %d frames...", #calls)) ---Util.writeTable('tmp/raw.txt', calls) -- Perform a quick re-parse of the recorded data (adding frames for when the cursor blinks): diff --git a/milo/MiloRemote.lua b/milo/MiloRemote.lua index f9c6e8c..1f2caa8 100644 --- a/milo/MiloRemote.lua +++ b/milo/MiloRemote.lua @@ -63,8 +63,8 @@ local page = UI.Page { x = 1, ex = -13, limit = 50, shadowText = 'filter', - backgroundColor = UI.colors.primary, - backgroundFocusColor = UI.colors.primary, + backgroundColor = 'primary', + backgroundFocusColor = 'primary', accelerators = { [ 'enter' ] = 'eject', [ 'up' ] = 'grid_up', diff --git a/milo/apis/massAdapter.lua b/milo/apis/massAdapter.lua deleted file mode 100644 index f272e4b..0000000 --- a/milo/apis/massAdapter.lua +++ /dev/null @@ -1,53 +0,0 @@ -local class = require('opus.class') -local itemDB = require('core.itemDB') -local Mini = require('milo.miniAdapter') - -local os = _G.os - -local Adapter = class(Mini) - -function Adapter:init(args) - Mini.init(self, args) - - self._rawList = self.list - - function self.list() - -- wait for up to 1 sec until any items that have been inserted - -- into interface are added to the system - for _ = 0, 20 do - if #self._rawList() == 0 then - break - end - os.sleep(0) - end - - local list = { } - for _, v in pairs(self.listAvailableItems()) do - list[itemDB:makeKey(v)] = v - end - return list - end - - function self.getItemMeta(key) - local item = self.findItem(itemDB:splitKey(key)) - if item and item.getMetadata then - return item.getMetadata() - end - end - - function self.pushItems(target, key, amount, slot) - local item = self.findItem(itemDB:splitKey(key)) - if item and item.export then - return item.export(target, amount, slot) - end - return 0 - end - - function self.pullItems(target, key, amount, slot) - _G._syslog({target, key, amount, slot }) - return 0 - end - -end - -return Adapter diff --git a/milo/core/listing.lua b/milo/core/listing.lua index aa23978..34f1b6c 100644 --- a/milo/core/listing.lua +++ b/milo/core/listing.lua @@ -54,8 +54,8 @@ local page = UI.Page { limit = 50, shadowText = 'filter', shadowTextColor = colors.gray, - backgroundColor = UI.colors.primary, - backgroundFocusColor = UI.colors.primary, + backgroundColor = 'primary', + backgroundFocusColor = 'primary', accelerators = { [ 'enter' ] = 'eject', [ 'up' ] = 'grid_up', @@ -66,7 +66,7 @@ local page = UI.Page { storageStatus = UI.Text { x = -17, ex = -10, textColor = colors.lime, - backgroundColor = UI.colors.primary, + backgroundColor = 'primary', value = '', }, amount = UI.TextEntry { diff --git a/milo/core/machines.lua b/milo/core/machines.lua index 23cb9f1..b3779db 100644 --- a/milo/core/machines.lua +++ b/milo/core/machines.lua @@ -21,8 +21,8 @@ local networkPage = UI.Page { y = -2, x = 1, ex = -9, limit = 50, shadowText = 'filter', - backgroundColor = UI.colors.primary, - backgroundFocusColor = UI.colors.primary, + backgroundColor = 'primary', + backgroundFocusColor = 'primary', }, grid = UI.ScrollingGrid { y = 2, ey = -3, @@ -234,7 +234,7 @@ The settings will take effect immediately!]], }, }, statusBar = UI.StatusBar { - backgroundColor = UI.colors.primary, + backgroundColor = 'primary', }, notification = UI.Notification { }, filter = UI.SlideOut { @@ -289,7 +289,7 @@ The settings will take effect immediately!]], }, }, statusBar = UI.StatusBar { - backgroundColor = UI.colors.primary, + backgroundColor = 'primary', }, }, } diff --git a/milo/plugins/item.lua b/milo/plugins/item.lua index c6dcd85..75c2fc4 100644 --- a/milo/plugins/item.lua +++ b/milo/plugins/item.lua @@ -41,7 +41,6 @@ function page:eventHandler(event) elseif event.type == 'focus_change' then self.statusBar:setStatus(event.focused.help) - self.statusBar:draw() elseif event.type == 'success_message' then self.notification:success(event.message) diff --git a/milo/plugins/massStorageView.lua b/milo/plugins/massStorageView.lua deleted file mode 100644 index e198b3e..0000000 --- a/milo/plugins/massStorageView.lua +++ /dev/null @@ -1,43 +0,0 @@ -local Ansi = require('opus.ansi') -local UI = require('opus.ui') - -local colors = _G.colors -local device = _G.device - ---[[ Configuration Screen ]] -local template = -[[%sWarning%s - -Must an interface for Refined Storage / Applied Energistics. - -Add all speed upgrades possible. -]] - -local wizardPage = UI.WizardPage { - title = 'Mass Storage', - index = 2, - backgroundColor = colors.cyan, - [1] = UI.TextArea { - x = 2, ex = -2, y = 2, ey = -2, - value = string.format(template, Ansi.red, Ansi.reset), - }, -} - -function wizardPage:isValidFor(node) - if node.mtype == 'storage' then - local m = device[node.name] - return m and m.listAvailableItems - end -end - -function wizardPage:setNode(node) - self.node = node -end - -function wizardPage:validate() - self.node.adapterType = 'massAdapter' - return true -end - --- disable until a way is found to transfer between 2 non-transferrable nodes --- UI:getPage('nodeWizard').wizard:add({ inputChest = wizardPage }) diff --git a/milo/plugins/remote/setup.lua b/milo/plugins/remote/setup.lua index 4688300..856278d 100644 --- a/milo/plugins/remote/setup.lua +++ b/milo/plugins/remote/setup.lua @@ -50,7 +50,7 @@ local setup = UI.SlideOut { [[also have an introspection module.]], }, statusBar = UI.StatusBar { - backgroundColor = UI.colors.primary, + backgroundColor = 'primary', }, } diff --git a/neural/mobRancher.lua b/neural/mobRancher.lua index 51ce614..cef0975 100644 --- a/neural/mobRancher.lua +++ b/neural/mobRancher.lua @@ -35,6 +35,12 @@ neural.assertModules({ 'plethora:introspection', }) +local caninimals = config.animals or { [ config.animal ] = true } +local animals = { } +for k in pairs(caninimals) do + animals[k] = { } +end + local fed = { } local function resupply() @@ -49,10 +55,12 @@ local function resupply() print('dispenser not found') break end - if math.abs(dispenser.x) <= 1 and math.abs(dispenser.z) <= 1 then + if math.abs(dispenser.x) <= 1.2 and math.abs(dispenser.z) <= 1.2 then neural.lookAt({ x = dispenser.x, y = dispenser.y, z = dispenser.z }) for _ = 1, 8 do - neural.use(0, 'off') + if not neural.use(0, 'off') then + break + end os.sleep(.2) neural.getEquipment().suck(2, 64) end @@ -64,21 +72,22 @@ local function resupply() end local function breed(entity) - print('breeding') - entity.lastFed = os.clock() - fed[entity.id] = entity + print('breeding ' .. entity.name) neural.walkTo(entity, WALK_SPEED, 1) entity = neural.getMetaByID(entity.id) if entity then neural.lookAt(entity) - neural.use(1, 'off') + if neural.use(1, 'off') then + entity.lastFed = os.clock() + fed[entity.id] = entity + end os.sleep(.1) end end local function kill(entity) - print('killing') + print('killing ' .. entity.name) neural.walkTo(entity, WALK_SPEED, (neural.fire or neural.shoot) and 2.5 or .5) entity = neural.getMetaByID(entity.id) if entity then @@ -93,21 +102,28 @@ local function kill(entity) end end -local function getEntities() - local sheep = Array.filter(neural.sense(), function(entity) - if entity.name == 'Sheep' and entity.y > -.5 then - return true - end - end) - if #sheep > config.maxAdults then - return sheep +local function shuffle(tbl) + for i = #tbl, 2, -1 do + local j = math.random(i) + tbl[i], tbl[j] = tbl[j], tbl[i] end + return tbl +end - return Map.filter(neural.sense(), function(entity) - if entity.name == config.animal and entity.y > -.5 then - return true +local function getEntities() + return shuffle(Array.filter(neural.sense(), function(entity) + if animals[entity.name] then + if not animals[entity.name].height then + entity = neural.getMetaByID(entity.id) + if entity and not entity.isChild and entity.motionX == 0 and entity.motionZ == 0 then + animals[entity.name].height = entity.y + return true + end + elseif entity.y == animals[entity.name].height then + return true + end end - end) + end)) end local function getHungry(entities) @@ -118,13 +134,25 @@ local function getHungry(entities) end end -local function randomEntity(entities) - local r = math.random(1, Map.size(entities)) - local i = 1 +local function getCount(entities, name) + local c = 0 for _, v in pairs(entities) do - i = i + 1 - if i > r then - return v + if v.name == name then + c = c + 1 + end + end + print(name .. ' ' .. c) + return c +end + +local function getKillable(entities) + print('map: ' .. Map.size(fed)) + if Map.size(fed) > 1000 then + fed = { } + end + for name in pairs(animals) do + if getCount(entities, name) > config.maxAdults then + return Array.find(entities, 'name', name) end end end @@ -133,9 +161,10 @@ while true do resupply() local entities = getEntities() + local killable = getKillable(entities) - if Map.size(entities) > config.maxAdults then - kill(randomEntity(entities)) + if killable then + kill(killable) else local entity = getHungry(entities) if entity then diff --git a/swshop/shopConfig.lua b/swshop/shopConfig.lua index 761b587..857d0c1 100644 --- a/swshop/shopConfig.lua +++ b/swshop/shopConfig.lua @@ -110,7 +110,7 @@ local passwordPage = UI.WizardPage { preview = UI.TextEntry { formIndex = 4, formLabel = 'Using address', formKey = 'address', - backgroundColor = UI.colors.primary, + backgroundColor = 'primary', textColor = colors.yellow, inactive = true, }, -- 2.49.1