diff --git a/sys/apis/terminal.lua b/sys/apis/terminal.lua index 2f6addd..9e5db8b 100644 --- a/sys/apis/terminal.lua +++ b/sys/apis/terminal.lua @@ -1,23 +1,21 @@ -local Util = require('util') - local colors = _G.colors local term = _G.term local _gsub = string.gsub local Terminal = { } -function Terminal.scrollable(win, size) +function Terminal.scrollable(win, parent) local w, h = win.getSize() + local _, ph = parent.getSize() local scrollPos = 0 local scp = win.setCursorPos win.setCursorPos = function(x, y) + _G._p = y + if y > scrollPos + ph then + win.scrollTo(y - ph) + end scp(x, y) - if y > scrollPos + h then - win.scrollTo(y - h) - elseif y < scrollPos then - win.scrollTo(y - 2) - end end win.scrollUp = function() @@ -29,75 +27,15 @@ function Terminal.scrollable(win, size) end win.scrollTo = function(p) - p = math.min(math.max(p, 0), size) + p = math.min(math.max(p, 0), h - ph) if p ~= scrollPos then scrollPos = p - win.reposition(1, -scrollPos + 1, w, h + size) + win.reposition(1, -scrollPos + 1, w, h) end end - - win.reposition(1, 1, w, h + size, true) end -function Terminal.scrollable2(ct, size) - - local w, h = ct.getSize() - local win = _G.window.create(ct, 1, 1, w, h + size, true) - local oldWin = Util.shallowCopy(win) - local scrollPos = 0 - - local function drawScrollbar(oldPos, newPos) - local x, y = oldWin.getCursorPos() - - local pos = math.floor(oldPos / size * (h - 1)) - oldWin.setCursorPos(w, oldPos + pos + 1) - oldWin.write(' ') - - pos = math.floor(newPos / size * (h - 1)) - oldWin.setCursorPos(w, newPos + pos + 1) - oldWin.write('#') - - oldWin.setCursorPos(x, y) - end - - win.setCursorPos = function(x, y) - oldWin.setCursorPos(x, y) - if y > scrollPos + h then - win.scrollTo(y - h) - elseif y < scrollPos then - win.scrollTo(y - 2) - end - end - - win.scrollUp = function() - win.scrollTo(scrollPos - 1) - end - - win.scrollDown = function() - win.scrollTo(scrollPos + 1) - end - - win.scrollTo = function(p) - p = math.min(math.max(p, 0), size) - if p ~= scrollPos then - drawScrollbar(scrollPos, p) - scrollPos = p ---local w, h = win.getSize() - win.reposition(1, -scrollPos + 1, w, h + size) - end - end - - win.clear = function() - oldWin.clear() - scrollPos = 0 - end - - drawScrollbar(0, 0) - - return win -end function Terminal.toGrayscale(ct) - local scolors = { [ colors.white ] = colors.white, [ colors.orange ] = colors.lightGray, @@ -183,7 +121,7 @@ function Terminal.mirror(ct, dt) if dt[k] then dt[k](...) end - return unpack(ret) + return table.unpack(ret) end end end diff --git a/sys/apps/Tabs.lua b/sys/apps/Tabs.lua index 3740105..df857a5 100644 --- a/sys/apps/Tabs.lua +++ b/sys/apps/Tabs.lua @@ -25,7 +25,7 @@ local page = UI.Page { { heading = 'Time', key = 'timestamp' }, }, values = multishell.getTabs(), - sortColumn = 'title', + sortColumn = 'uid', autospace = true, }, accelerators = { diff --git a/sys/apps/multishell b/sys/apps/multishell index aba980b..04f2c33 100644 --- a/sys/apps/multishell +++ b/sys/apps/multishell @@ -14,7 +14,7 @@ local shell = _ENV.shell local term = _G.term local window = _G.window -local parentTerm = term.current() +local parentTerm = kernel.terminal.parent -- term.current() local w,h = parentTerm.getSize() local overviewId local tabsDirty = false @@ -128,6 +128,7 @@ function multishell.openTab(tab) end printError('Press enter to close') tab.isDead = true + tab.hidden = false while true do local e, code = os.pullEventRaw('key') if e == 'terminate' or e == 'key' and code == keys.enter then @@ -137,7 +138,7 @@ function multishell.openTab(tab) end end) - kernel.run(routine) + kernel.launch(routine) if tab.focused then multishell.setFocus(tab.uid) diff --git a/sys/apps/telnet.lua b/sys/apps/telnet.lua index 8a181b9..a1df07d 100644 --- a/sys/apps/telnet.lua +++ b/sys/apps/telnet.lua @@ -26,7 +26,6 @@ if options.title then multishell.setTitle(multishell.getCurrent(), options.title) end -print('connecting...') local socket, msg = Socket.connect(remoteId, 23) if not socket then @@ -44,6 +43,7 @@ socket:write({ height = h, isColor = ct.isColor(), program = args, + pos = { ct.getCursorPos() }, }) Event.addRoutine(function() @@ -58,8 +58,8 @@ Event.addRoutine(function() end end) -ct.clear() -ct.setCursorPos(1, 1) +--ct.clear() +--ct.setCursorPos(1, 1) local filter = Util.transpose { 'char', 'paste', 'key', 'key_up', 'terminate', @@ -77,10 +77,10 @@ while true do end if not socket.connected then - print() - print('Connection lost') - print('Press enter to exit') - pcall(read) +-- print() +-- print('Connection lost') +-- print('Press enter to exit') +-- pcall(read) break end end diff --git a/sys/boot/opus.boot b/sys/boot/opus.boot index 4191518..ef1c8eb 100644 --- a/sys/boot/opus.boot +++ b/sys/boot/opus.boot @@ -23,6 +23,7 @@ local terminal = term.current() local w, h = term.getSize() local kernelWindow = window.create(terminal, 1, 1, w, h, false) term.redirect(kernelWindow) +kernelWindow.parent = terminal local splashWindow local function showStatus(status, ...) @@ -152,11 +153,19 @@ local function createShellEnvironment(Util) sandboxEnv.LUA_PATH = config.lua_path end -local function loadExtensions(Util) +local function loadExtensions() local dir = 'sys/extensions' - for _,file in ipairs(fs.list(dir)) do + local files = fs.list(dir) + table.sort(files) + for _,file in ipairs(files) do showStatus('Loading ' .. file) - local s, m = Util.run(makeEnv(), 'sys/apps/shell', fs.combine(dir, file)) + local s, m = kernel.run({ + title = file:match('%d.(%S+).lua'), + hidden = true, + path = 'sys/apps/shell', + args = { fs.combine(dir, file) }, + terminal = kernelWindow, + }) if not s then error(m) end @@ -191,7 +200,7 @@ local s, m = pcall(function() showStatus('Reticulating splines') Util.run(makeEnv(), 'sys/kernel.lua') - loadExtensions(Util) + loadExtensions() showStatus('Mounting file systems') fs.loadTab('usr/etc/fstab') @@ -199,15 +208,15 @@ local s, m = pcall(function() splashWindow.setVisible(false) if args[1] then kernelWindow.setVisible(true) + kernelWindow.setVisible(false) end - --term.clear() - --term.redirect(terminal) - _G.kernel.run(_G.kernel.newRoutine({ + term.redirect(terminal) + + _G.kernel.run({ path = 'sys/apps/shell', args = args[1] and args or { 'sys/apps/multishell' }, - terminal = terminal, - })) + }) end) if not s then @@ -217,7 +226,7 @@ if not s then _G.printError(m .. '\n') else if _G.kernel.routines[1] then - _G.kernel.start(terminal, kernelWindow) + _G.kernel.start() end end diff --git a/sys/extensions/device.lua b/sys/extensions/1.device.lua similarity index 98% rename from sys/extensions/device.lua rename to sys/extensions/1.device.lua index 5c593ec..a5d5b73 100644 --- a/sys/extensions/device.lua +++ b/sys/extensions/1.device.lua @@ -4,7 +4,7 @@ local Peripheral = require('peripheral') _G.device = Peripheral.getList() -_G.device.terminal = _G.term.current() +_G.device.terminal = _G.kernel.terminal.parent _G.device.terminal.side = 'terminal' _G.device.terminal.type = 'terminal' _G.device.terminal.name = 'terminal' diff --git a/sys/extensions/vfs.lua b/sys/extensions/2.vfs.lua similarity index 100% rename from sys/extensions/vfs.lua rename to sys/extensions/2.vfs.lua diff --git a/sys/services/network.lua b/sys/extensions/3.netdaemon.lua similarity index 54% rename from sys/services/network.lua rename to sys/extensions/3.netdaemon.lua index 378e3f8..7e3ef77 100644 --- a/sys/services/network.lua +++ b/sys/extensions/3.netdaemon.lua @@ -3,45 +3,40 @@ _G.requireInjector() local Event = require('event') local Util = require('util') +_G.network = { } + local device = _G.device local fs = _G.fs -local multishell = _ENV.multishell local network = _G.network local os = _G.os local printError = _G.printError if not device.wireless_modem then - return -end - -if multishell and multishell.setTitle then - multishell.setTitle(multishell.getCurrent(), 'Net Daemon') + return end print('Net daemon started') for _,file in pairs(fs.list('sys/network')) do - local fn, msg = Util.run(_ENV, 'sys/network/' .. file) - if not fn then - printError(msg) - end + local fn, msg = Util.run(_ENV, 'sys/network/' .. file) + if not fn then + printError(msg) + end end Event.on('device_detach', function() - if not device.wireless_modem then - Event.exitPullEvents() - end + if not device.wireless_modem then + Event.exitPullEvents() + end end) Event.pullEvents() for _,c in pairs(network) do - c.active = false - os.queueEvent('network_detach', c) + c.active = false + os.queueEvent('network_detach', c) end os.queueEvent('network_down') Event.pullEvent('network_down') -Util.clear(_G.network) - -print('Net daemon stopped') +Util.clear(network) diff --git a/sys/extensions/3.network.lua b/sys/extensions/3.network.lua new file mode 100644 index 0000000..0f25ffc --- /dev/null +++ b/sys/extensions/3.network.lua @@ -0,0 +1,11 @@ +local kernel = _G.kernel + +kernel.hook('device_attach', function(_, eventData) + if eventData[1] == 'wireless_modem' then + kernel.run({ + title = 'Net daemon', + path = 'sys/extensions/netdaemon.lua', + hidden = true, + }) + end +end) diff --git a/sys/extensions/tl3.lua b/sys/extensions/6.tl3.lua similarity index 100% rename from sys/extensions/tl3.lua rename to sys/extensions/6.tl3.lua diff --git a/sys/extensions/network.lua b/sys/extensions/network.lua deleted file mode 100644 index 450be0b..0000000 --- a/sys/extensions/network.lua +++ /dev/null @@ -1,13 +0,0 @@ -local kernel = _G.kernel - -_G.network = { } - -kernel.hook('device_attach', function(_, eventData) - if eventData[1] == 'wireless_modem' then - local routine = kernel.newRoutine({ - path = 'sys/services/network.lua', - hidden = true - }) - kernel.run(routine) - end -end) diff --git a/sys/kernel.lua b/sys/kernel.lua index 2313f4b..ac9a8a0 100644 --- a/sys/kernel.lua +++ b/sys/kernel.lua @@ -12,6 +12,7 @@ _G.kernel = { hooks = { }, routines = { }, terminal = _G.term.current(), + window = _G.term.current(), } local kernel = _G.kernel @@ -25,7 +26,7 @@ local focusedRoutineEvents = Util.transpose { } _G.debug = function(pattern, ...) - local oldTerm = term.redirect(kernel.terminal) + local oldTerm = term.redirect(kernel.window) Util.print(pattern, ...) term.redirect(oldTerm) end @@ -65,7 +66,7 @@ function Routine:resume(event, ...) end if not self.filter or self.filter == event or event == "terminate" then - term.redirect(self.terminal) + local previousTerm = term.redirect(self.terminal) local previous = kernel.running kernel.running = self -- stupid shell set title @@ -73,6 +74,8 @@ function Routine:resume(event, ...) kernel.running = previous self.terminal = term.current() + term.redirect(previousTerm) + if ok then self.filter = result else @@ -103,16 +106,15 @@ function kernel.newRoutine(args) local routine = setmetatable(args, { __index = Routine }) routine.uid = kernel.UID + routine.timestamp = os.clock() + routine.env = args.env or Util.shallowCopy(sandboxEnv) + routine.terminal = args.terminal or kernel.terminal + routine.window = args.window or kernel.window return routine end -function kernel.run(routine) - routine.timestamp = os.clock() - routine.terminal = routine.terminal or kernel.terminal - routine.window = routine.window or kernel.window - routine.env = Util.shallowCopy(routine.env or sandboxEnv) - +function kernel.launch(routine) routine.co = routine.co or coroutine.create(function() local result, err @@ -131,11 +133,15 @@ function kernel.run(routine) table.insert(kernel.routines, routine) - local previousTerm = term.current() local s, m = routine:resume() - term.redirect(previousTerm) - return s, m + return not s and s or routine.uid, m +end + +function kernel.run(args) + local routine = kernel.newRoutine(args) + kernel.launch(routine) + return routine end function kernel.raise(uid) @@ -207,10 +213,7 @@ function kernel.event(event, eventData) end end -function kernel.start(terminal, kernelWindow) - kernel.window = kernelWindow - kernel.terminal = kernel.window - +function kernel.start() local s, m = pcall(function() repeat local eventData = { os.pullEventRaw() } @@ -221,9 +224,8 @@ function kernel.start(terminal, kernelWindow) kernel.window.setVisible(true) if not s then - term.redirect(kernel.window) print('\nCrash detected\n') _G.printError(m) end - term.redirect(terminal) + term.redirect(kernel.terminal) end diff --git a/sys/network/telnet.lua b/sys/network/telnet.lua index 93b3567..ce7e8ff 100644 --- a/sys/network/telnet.lua +++ b/sys/network/telnet.lua @@ -2,15 +2,11 @@ local Event = require('event') local Socket = require('socket') local Util = require('util') -local multishell = _ENV.multishell -local os = _G.os -local term = _G.term +local kernel = _G.kernel +local term = _G.term +local window = _G.window local function telnetHost(socket) - _G.requireInjector() - - local Event = require('event') - local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit', 'setTextColor', 'setTextColour', 'setBackgroundColor', 'setBackgroundColour', 'scroll', 'setCursorBlink', } @@ -21,11 +17,12 @@ local function telnetHost(socket) return end - socket.term = term.current() - local oldWindow = Util.shallowCopy(socket.term) + local win = window.create(_G.device.terminal, 1, 1, termInfo.width, termInfo.height, false) + win.setCursorPos(table.unpack(termInfo.pos)) for _,k in pairs(methods) do - socket.term[k] = function(...) + local fn = win[k] + win[k] = function(...) if not socket.queue then socket.queue = { } @@ -39,34 +36,36 @@ local function telnetHost(socket) f = k, args = { ... }, }) - oldWindow[k](...) + fn(...) end end - socket.term.getSize = function() - return termInfo.width, termInfo.height - end - - local shellThread = Event.addRoutine(function() - os.run(_ENV, 'sys/apps/shell', table.unpack(termInfo.program)) - Event.exitPullEvents() - end) + local shellThread = kernel.run({ + terminal = win, + window = win, + title = 'Telnet client', + hidden = true, + co = coroutine.create(function() + Util.run(_ENV, 'sys/apps/shell', table.unpack(termInfo.program)) + if socket.queue then + socket:write(socket.queue) + end + socket:close() + end) + }) Event.addRoutine(function() while true do local data = socket:read() if not data then - Event.exitPullEvents() + shellThread:resume('terminate') break end + local previousTerm = term.current() shellThread:resume(table.unpack(data)) + term.redirect(previousTerm) end end) - - Event.pullEvents() - - socket:close() - shellThread:terminate() end Event.addRoutine(function() @@ -76,11 +75,8 @@ Event.addRoutine(function() print('telnet: connection from ' .. socket.dhost) - multishell.openTab({ - fn = telnetHost, - args = { socket }, - title = 'Telnet Client', - hidden = true, - }) + Event.addRoutine(function() + telnetHost(socket) + end) end end) diff --git a/sys/network/vnc.lua b/sys/network/vnc.lua index c1dcb84..0724249 100644 --- a/sys/network/vnc.lua +++ b/sys/network/vnc.lua @@ -3,7 +3,7 @@ local Socket = require('socket') local Util = require('util') local os = _G.os -local terminal = _ENV.multishell.term +local terminal = _G.device.terminal local function vncHost(socket) local methods = { 'blit', 'clear', 'clearLine', 'setCursorPos', 'write', diff --git a/sys/services/log.lua b/sys/services/log.lua index f5f4181..399690d 100644 --- a/sys/services/log.lua +++ b/sys/services/log.lua @@ -11,22 +11,60 @@ local keyboard = _G.device.keyboard local multishell = _ENV.multishell local os = _G.os local term = _G.term +local window = _G.window if multishell and multishell.setTitle then multishell.setTitle(multishell.getCurrent(), 'System Log') end +-- jump through a lot of hoops to get around window api limitations +-- mainly failing to provide access to window buffer or knowledge of parent +-- need: window.getParent() +-- window.copy(target) + +local terminal = _G.kernel.terminal.parent +local w, h = kernel.window.getSize() +local win = window.create(kernel.window, 1, 1, w, h + 50, false) + +-- copy windows contents from parent window to child +local oblit, oscp = terminal.blit, terminal.setCursorPos +kernel.window.setVisible(false) +terminal.blit = function(...) + win.blit(...) +end +terminal.setCursorPos = function(...) + win.setCursorPos(...) +end +kernel.window.setVisible(true) + +-- position and resize window for multishell (but don't update screen) +terminal.blit = function() end +terminal.setCursorPos = function() end +kernel.window.reposition(1, 2, w, h - 1) + +-- restore original terminal +terminal.blit = oblit +terminal.setCursorPos = oscp + +-- add scrolling methods +Terminal.scrollable(win, kernel.window) + +-- update kernel with new window, set this tab with the new kernal window local routine = kernel.getCurrent() -local previousId - -kernel.window.reposition(1, 2) -Terminal.scrollable(kernel.window, 50) - -routine.terminal = kernel.window -routine.window = kernel.window - +for _,r in pairs(kernel.routines) do + if r.terminal == kernel.terminal then + r.terminal = win + r.window = win + end +end +kernel.terminal = win +kernel.window = win +routine.terminal = win +routine.window = win term.redirect(routine.window) +local previousId + kernel.hook('mouse_scroll', function(_, eventData) local dir, y = eventData[1], eventData[3]