From fc127f8d3e822966002a974b81e105cae717c027 Mon Sep 17 00:00:00 2001 From: XeonSquared Date: Sun, 12 Apr 2020 01:59:56 +1000 Subject: [PATCH] moved the VT100 driver out of the kernel and into its own library --- lib/vtansi.lua | 197 ++++++++++++++++++++++++++++++++++++++++++++++ module/init.lua | 1 - service/getty.lua | 3 +- 3 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 lib/vtansi.lua diff --git a/lib/vtansi.lua b/lib/vtansi.lua new file mode 100644 index 0000000..d5a247f --- /dev/null +++ b/lib/vtansi.lua @@ -0,0 +1,197 @@ +local vtansi = {} +function vtansi.vtemu(gpu) -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal + local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF} + local mx, my = gpu.maxResolution() + local cx, cy = 1, 1 + local pc = " " + local lc = "" + local mode = 0 -- 0 normal, 1 escape, 2 command + local lw = true + local sx, sy = 1,1 + local cs = "" + local bg, fg = 0, 0xFFFFFF + + -- setup + gpu.setResolution(mx,my) + gpu.fill(1,1,mx,my," ") + local function checkCursor() + if cx > mx and lw then + cx, cy = 1, cy+1 + end + if cy > my then + gpu.copy(1,2,mx,my-1,0,-1) + gpu.fill(1,my,mx,1," ") + cy=my + end + if cy < 1 then cy = 1 end + if cx < 1 then cx = 1 end + end + + local function termwrite(s) + local wb = "" + local lb, ec = nil, nil + local function flushwb() + while wb:len() > 0 do + checkCursor() + local wl = wb:sub(1,mx-cx+1) + wb = wb:sub(wl:len()+1) + gpu.set(cx, cy, wl) + cx = cx + wl:len() + end + end + local rs = "" + s=s:gsub("\8","\27[D") + pc = gpu.get(cx,cy) + gpu.setForeground(fg) + gpu.setBackground(bg) + gpu.set(cx,cy,pc) + for cc in s:gmatch(".") do + if mode == 0 then + if cc == "\n" then + flushwb() + cx,cy = 1, cy+1 + elseif cc == "\t" then + wb=wb..(" "):rep(8*((cx+9)//8)) + elseif cc == "\27" then + flushwb() + mode = 1 + else + wb = wb .. cc + end + elseif mode == 1 then + if cc == "[" then + mode = 2 + else + mode = 0 + end + elseif mode == 2 then + if cc:match("[%d;]") then + cs = cs .. cc + else + mode = 0 + local tA = {} + for s in cs:gmatch("%d+") do + tA[#tA+1] = tonumber(s) + end + if cc == "H" then + cx, cy = tA[1] or 1, tA[2] or 1 + elseif cc == "A" then + cy = cy - (tA[1] or 1) + elseif cc == "B" then + cy = cy + (tA[1] or 1) + elseif cc == "C" then + cx = cx + (tA[1] or 1) + elseif cc == "D" then + cx = cx - (tA[1] or 1) + elseif cc == "s" then + sx, sy = cx, cy + elseif cc == "u" then + cx, cy = sx, sy + elseif cc == "n" and tA[1] == 6 then + rs = string.format("%s\27[%d;%dR",rs,cx,cy) + elseif cc == "K" and tA[1] == 1 then + gpu.fill(1,cy,cx,1," ") + elseif cc == "K" and tA[1] == 2 then + gpu.fill(cx,cy,mx,1," ") + elseif cc == "K" then + gpu.fill(1,cy,mx,1," ") + elseif cc == "J" and tA[1] == 1 then + gpu.fill(1,1,mx,cy," ") + elseif cc == "J" and tA[1] == 2 then + gpu.fill(1,1,mx,my," ") + cx, cy = 1, 1 + elseif cc == "J" then + gpu.fill(1,cy,mx,my," ") + elseif cc == "m" then + for _,num in ipairs(tA) do + if num == 0 then + fg,bg,ec,lb = 0xFFFFFF,0,true,true + elseif num == 7 then + local nfg,nbg = bg, fg + fg, bg = nfg, nbg + elseif num > 29 and num < 38 then + fg = colours[num-29] + elseif num > 39 and num < 48 then + bg = colours[num-39] + elseif num == 100 then -- disable local echo + ec = false + elseif num == 101 then -- disable line mode + lb = false + end + end + gpu.setForeground(fg) + gpu.setBackground(bg) + end + cs = "" + checkCursor() + end + end + end + flushwb() + checkCursor() + pc = gpu.get(cx,cy) + gpu.setForeground(bg) + gpu.setBackground(fg) + gpu.set(cx,cy,pc) + gpu.setForeground(fg) + gpu.setBackground(bg) + return rs, lb, ec + end + + return termwrite +end + +function vtansi.vtsession(gpua,scra) -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions. + local gpu = component.proxy(gpua) + gpu.bind(scra) + local write = vtansi.vtemu(gpu) + local kba = {} + for k,v in ipairs(component.invoke(scra,"getKeyboards")) do + kba[v]=true + end + local buf, lbuf, echo = "", true, true + os.spawn(function() dprint(pcall(function() + while true do + local ty,ka,ch = coroutine.yield() + if ty == "key_down" and kba[ka] then + if ch == 13 then ch = 10 end + if ch == 8 and lbuf then + if buf:len() > 0 then + if echo then write("\8 \8") end + buf = buf:sub(1,-2) + end + elseif ch > 0 then + if echo then write(string.char(ch)) end + buf=buf..string.char(ch) + end + end + end + end)) end,string.format("ttyd[%s:%s]",gpua:sub(1,8),scra:sub(1,8))) + local function bread(n) + local r + if lbuf then + while not buf:find("\n") do + coroutine.yield() + end + local n = buf:find("\n") + r, buf = buf:sub(1,n), buf:sub(n+1) + else + r = buf + buf = "" + coroutine.yield() + end + return r + end + local function bwrite(d) + local ba, lb, ec = write(d) + buf = buf .. ba + if lb ~= nil then + lbuf = lb + end + if ec ~= nil then + echo = ec + end + end + return bread, bwrite, function() io.write("\27[2J\27[H") end +end +return vtansi diff --git a/module/init.lua b/module/init.lua index aa9cc11..08b4fe8 100644 --- a/module/init.lua +++ b/module/init.lua @@ -7,7 +7,6 @@ --#include "module/devfs.lua" --#include "module/devfs/syslog.lua" --#include "module/loadfile.lua" ---#include "module/vt-task.lua" os.spawn(function() os.setenv("PWD","/boot") diff --git a/service/getty.lua b/service/getty.lua index 0c5797c..6c71b6c 100644 --- a/service/getty.lua +++ b/service/getty.lua @@ -1,6 +1,7 @@ local gpus,screens,ttyn,pids = {}, {}, 0, {} local basepid = nil local shell = require "shell" +local vtansi = require "vtansi" local function scan() local w,di = pcall(computer.getDeviceInfo) if w then @@ -44,7 +45,7 @@ local function allocate() dprint(k) local sA = nextScreen(v[2]) if v[1] == false and sA then - local r,w = vtemu(k,sA) + local r,w = vtansi.vtsession(k,sA) devfs.register("tty"..tostring(ttyn), function() return r,w,function() end end) gpus[k][1] = true screens[sA][1] = true