From c9157a1b7c5474f8e115257ae0b9fc56ae3a2669 Mon Sep 17 00:00:00 2001 From: 20kdc Date: Thu, 2 Apr 2020 14:33:14 +0100 Subject: [PATCH] More terminal improvements. Yes. Again. --- claw/repo-claw.lua | 2 +- code/apps/app-luashell.lua | 8 +- code/apps/svc-t.lua | 49 ++++++-- laboratory/ocemu.cfg.default | 4 +- repository/apps/app-kmt.lua | 213 +++++++++++------------------------ 5 files changed, 112 insertions(+), 164 deletions(-) diff --git a/claw/repo-claw.lua b/claw/repo-claw.lua index c78cda9..4823944 100644 --- a/claw/repo-claw.lua +++ b/claw/repo-claw.lua @@ -93,7 +93,7 @@ return { }, ["app-kmt"] = { desc = "Line-terminal for MUDs & such", - v = 1, + v = 2, deps = { "neo", "zzz-license-pd" diff --git a/code/apps/app-luashell.lua b/code/apps/app-luashell.lua index 371656e..9ac6572 100644 --- a/code/apps/app-luashell.lua +++ b/code/apps/app-luashell.lua @@ -10,11 +10,11 @@ local termClose if not ok then termId = nil - neo.executeAsync("svc-t", function (res) + assert(neo.executeAsync("svc-t", function (res) termId = res.access termClose = res.close neo.scheduleTimer(0) - end, "luashell") + end, "luashell")) while not termId do coroutine.yield() end @@ -32,7 +32,7 @@ event.listen("k.procdie", function (_, _, pid) end end) -TERM.write(([[ +TERM.write([[ KittenOS NEO Shell Usage Notes Prefixing = is an alias for 'return '. @@ -46,7 +46,7 @@ os.exit(): quit the shell =listCmdApps(): -t- (terminal) apps event: useful for setting up listeners without breaking shell functionality -]]):gsub("[\r]*\n", "\r\n")) +]]) function listCmdApps() local apps = {} diff --git a/code/apps/svc-t.lua b/code/apps/svc-t.lua index de1c300..f7bb34a 100644 --- a/code/apps/svc-t.lua +++ b/code/apps/svc-t.lua @@ -30,7 +30,9 @@ local console = {} -- This must not go below 3. local conW = 40 local conCX, conCY = 1, 1 -local conCV = false +-- Performance +local consoleShown = {} +local conCYShown for i = 1, 14 do console[i] = (" "):rep(conW) end @@ -70,6 +72,9 @@ local window = neo.requireAccess("x.neo.pub.window", "window")(conW, #console + local function setSize(w, h) conW = w + for i = 1, #console do + consoleShown[i] = nil + end while #console < h do table.insert(console, "") end @@ -101,7 +106,7 @@ end local function draw(i) if console[i] then window.span(1, i, console[i], 0, 0xFFFFFF) - if i == conCY and conCV then + if i == conCY and not leText then window.span(conCX, i, unicode.sub(console[i], conCX, conCX), 0xFFFFFF, 0) end elseif leText then @@ -109,7 +114,13 @@ local function draw(i) end end local function drawDisplay() - for i = 1, #console do draw(i) end + for i = 1, #console do + if consoleShown[i] ~= console[i] or i == conCY or i == conCYShown then + draw(i) + consoleShown[i] = console[i] + end + end + conCYShown = conCY end -- Terminal Visual -- @@ -147,6 +158,8 @@ local function writeData(data) end if char == "\r" then conCX = 1 + elseif char == "\x00" then + -- caused by TELNET \r rules elseif char == "\n" then conCX = 1 writeFF() @@ -171,6 +184,7 @@ local function writeData(data) end local function writeANSI(s) + --neo.emergency("svc-t.ansi: " .. s) -- This supports just about enough to get by. if s == "c" then for i = 1, #console do @@ -186,13 +200,18 @@ local function writeANSI(s) if cmd == "H" or cmd == "f" then local p = s:find(";") if not p then - conCX, conCY = 1, 1 + conCY = np + conCX = 1 else conCY = tonumber(s:sub(2, p - 1)) or 1 conCX = tonumber(s:sub(p + 1, -2)) or 1 end elseif cmd == "K" then console[conCY] = unicode.sub(console[conCY], 1, conCX - 1) .. (" "):rep(1 + conW - conCX) + elseif cmd == "J" then + for i = 1, #console do + console[i] = (" "):rep(conW) + end elseif cmd == "A" then conCY = conCY - np elseif cmd == "B" then @@ -372,10 +391,24 @@ local function key(a, c) -- Line Editing not active. -- For now support a bare minimum. for _, v in pairs(sendSigs) do - if control then - if a == 99 then - v("telnet", "\xFF\xF4") - end + if a == "\x03" then + v("telnet", "\xFF\xF4") + elseif c == 199 then + v("data", "\x1b[H") + elseif c == 201 then + v("data", "\x1b[5~") + elseif c == 207 then + v("data", "\x1b[F") + elseif c == 209 then + v("data", "\x1b[6~") + elseif c == 203 then + v("data", "\x1b[D") + elseif c == 205 then + v("data", "\x1b[C") + elseif c == 200 then + v("data", "\x1b[A") + elseif c == 208 then + v("data", "\x1b[B") elseif a == "\r" then v("data", "\r\n") elseif a then diff --git a/laboratory/ocemu.cfg.default b/laboratory/ocemu.cfg.default index b0c9c2b..994f9c7 100644 --- a/laboratory/ocemu.cfg.default +++ b/laboratory/ocemu.cfg.default @@ -3,8 +3,8 @@ ocemu { components { {"gpu", "c1-gpu-tier3", 0, 160, 50, 3}, {"gpu", "c1-gpu-tier1", 0, 50, 16, 1}, --- {"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3}, - {"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1}, + {"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3}, +-- {"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1}, {"modem", "c1-modem", 1, false}, {"eeprom", "c1-eeprom", 9, "lua/bios.lua"}, {"filesystem", "c1-tmpfs", -1, "tmpfs", "tmpfs", false, 5}, diff --git a/repository/apps/app-kmt.lua b/repository/apps/app-kmt.lua index b36f378..c4208d6 100644 --- a/repository/apps/app-kmt.lua +++ b/repository/apps/app-kmt.lua @@ -1,181 +1,96 @@ -- This is released into the public domain. -- No warranty is provided, implied or otherwise. --- app-kmt.lua : LC emergency plan +-- app-kmt.lua : just a utility now -- Authors: 20kdc -local lcOverride = false -local l15 = "20kdc.duckdns.org:8888" - --- unicode.safeTextFormat'd lines -local console = { - "┎┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┒", - "┋ ┃ ╱ ┃╲ ╱┃ ▀▀┃▀▀ ┋", - "┋ ┃╳ ┃ ╲ ╱ ┃ ┃ ┋", - "┋ ┃ ╲ ┃ ╲╱ ┃ ┃ ┋", - "┋ ┋", - "┋ KittenOS NEO MUD Terminal ┋", - "┖┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┚", - ":Type text, Enter key sends.", - ":'>' is 'from you', '<' 'to you'.", - ":':' is 'internal message'.", - ":Control-Arrows resizes window.", --- ":F5/F6 copies/pastes current line.", - ":", - ":", - ":Enter target server:port", - -- 14 -} ---++++++++++++++++++++++++++++++++++++++++ - --- sW must not go below 3. --- sH must not go below 2. -local sW, sH = 40, 15 local inet = neo.requireAccess("c.internet", "internet").list()() -local windows = neo.requireAccess("x.neo.pub.window", "windows") -local window = windows(sW, sH) -local tcp = nil -local dummyTcp = {read = function() return "" end, write = function() end, close = function() end} -local tcpBuf = "" +local _, _, termId = ... +local ok = pcall(function () + assert(string.sub(termId, 1, 12) == "x.neo.pub.t/") +end) -local function fmtLine(s) - s = unicode.safeTextFormat(s) - local l = unicode.len(s) - return unicode.sub(s .. (" "):rep(sW - l), -sW) -end +local termClose -local function line(i) - if i ~= sH then - assert(console[i], "console" .. i) - window.span(1, i, fmtLine(console[i]), 0xFFFFFF, 0) - else - window.span(1, i, fmtLine(l15), 0, 0xFFFFFF) +if not ok then + termId = nil + assert(neo.executeAsync("svc-t", function (res) + termId = res.access + termClose = res.close + neo.scheduleTimer(0) + end, "kmt")) + while true do + if coroutine.yield() == "k.timer" then break end end end +local term = neo.requireAccess(termId, "terminal") -local function incoming(s) - local function shift(f) - for i = 1, #console - 1 do - console[i] = console[i + 1] - end - console[#console] = f - end - -- Need to break this safely. - shift("") - for i = 1, unicode.len(s) do - local ch = unicode.sub(s, i, i) - if unicode.wlen(console[#console] .. ch) > sW then - shift(" ") - end - console[#console] = console[#console] .. ch - end - for i = 1, #console do - line(i) - end -end +term.write([[ +┎┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┒ +┋ ┃ ╱ ┃╲ ╱┃ ▀▀┃▀▀ ┋ +┋ ┃╳ ┃ ╲ ╱ ┃ ┃ ┋ +┋ ┃ ╲ ┃ ╲╱ ┃ ┃ ┋ +┋ ┋ +┋ KittenOS NEO MUD Terminal ┋ +┖┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┚ +export TERM=ansi-generic <- IMPORTANT!!! +Enter target server:port... +]]) -local function submitLine() - incoming(">" .. l15) - if not tcp then - tcp = inet.connect(l15) - if not tcp then - incoming(":The connection could not be created.") - tcp = dummyTcp - else - if not tcp.finishConnect() then - incoming(":Warning: finishConnect = false") - end - neo.scheduleTimer(os.uptime() + 0.1) - end - else - -- PRJblackstar doesn't need \r but others might - tcp.write(l15 .. "\r\n") - end - l15 = "" - line(sH) -end +local targetBuffer = "" -if lcOverride then - submitLine() -end - -local function clipEnt(tx) - tx = tx:gsub("\r", "") - local ci = tx:find("\n") or (#tx + 1) - tx = tx:sub(1, ci - 1) - l15 = tx - line(sH) -end - -local control = false +neo.scheduleTimer(0) while true do local e = {coroutine.yield()} if e[1] == "k.timer" then - while true do + while tcp do local b, e = tcp.read(neo.readBufSize) if not b then if e then - incoming(":Warning: " .. e) + term.write("\nkmt: " .. tostring(e) .. "\n") tcp.close() - tcp = dummyTcp + tcp = nil end - break elseif b == "" then break else - tcpBuf = tcpBuf .. b:gsub("\r", "") - while true do - local nlp = tcpBuf:find("\n") - if nlp then - incoming("<" .. tcpBuf:sub(1, nlp - 1)) - tcpBuf = tcpBuf:sub(nlp + 1) - else - break - end - end + term.write(b) end end - neo.scheduleTimer(os.uptime() + 0.1) - elseif e[1] == "x.neo.pub.window" then - if e[3] == "close" then - if tcp then - tcp.close() - end - return - elseif e[3] == "clipboard" then - clipEnt(e[4]) - elseif e[3] == "key" then - if e[5] == 29 or e[5] == 157 then - control = e[6] - elseif e[6] then - if not control then - if e[4] == 8 or e[4] == 127 then - l15 = unicode.sub(l15, 1, -2) - elseif e[4] == 13 then - submitLine() - elseif e[4] >= 32 then - l15 = l15 .. unicode.char(e[4]) - end - line(sH) - elseif e[5] == 203 and sW > 8 then - sW = sW - 1 - window.setSize(sW, sH) - elseif e[5] == 200 and sH > 2 then - sH = sH - 1 - table.remove(console, 1) - window.setSize(sW, sH) - elseif e[5] == 205 then - sW = sW + 1 - window.setSize(sW, sH) - elseif e[5] == 208 then - sH = sH + 1 - table.insert(console, 1, "") - window.setSize(sW, sH) + neo.scheduleTimer(os.uptime() + 0.049) + elseif e[1] == "k.procdie" then + if e[3] == term.pid then + break + end + elseif e[1] == termId then + if targetBuffer and e[2] == "data" then + targetBuffer = targetBuffer .. e[3]:gsub("\r", "") + local p = targetBuffer:find("\n") + if p then + local ok, res, rer = pcall(inet.connect, targetBuffer:sub(1, p - 1)) + targetBuffer = targetBuffer:sub(p + 1):gsub("\n", "\r\n") + if not ok then + -- Likes to return this kind + term.write("kmt: " .. tostring(res) .. "\n") + elseif not res then + -- Could theoretically return this kind + term.write("kmt: " .. tostring(rer) .. "\n") + else + -- Hopefully this kind + term.write("kmt: Connecting...\n") + tcp = res + tcp.write(targetBuffer) + targetBuffer = nil end end - elseif e[3] == "line" then - line(e[4]) + elseif tcp and e[2] == "data" or e[2] == "telnet" then + tcp.write(e[3]) end end end + +if tcp then + tcp.close() +end +