@@ -1,141 +0,0 @@ | |||
function vt100emu(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 |
@@ -1,5 +0,0 @@ | |||
--#include "module/vt-task.lua" | |||
do | |||
local r,w = vtemu(component.list("gpu")(),component.list("screen")()) | |||
devfs.register("tty0", function() return r,w,function() end end) | |||
end |
@@ -1,58 +0,0 @@ | |||
do | |||
--#include "module/nvt100.lua" | |||
function vtemu(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 = vt100emu(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 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 | |||
dprint("local buffer mode: "..tostring(lb)) | |||
lbuf = lb | |||
end | |||
if ec ~= nil then | |||
dprint("echo mode: "..tostring(ec)) | |||
echo = ec | |||
end | |||
end | |||
return bread, bwrite, function() io.write("\27[2J\27[H") end | |||
end | |||
end |
@@ -1,148 +0,0 @@ | |||
function vt100emu(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 = "n" | |||
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 termwrite(s) | |||
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 i = 1, s:len() do | |||
local cc = s:sub(i,i) | |||
if mode == "n" then | |||
if cc == "\n" then -- line feed | |||
cx, cy = 1, cy+1 | |||
elseif cc == "\r" then -- cursor home | |||
cx = 1 | |||
elseif cc == "\27" then -- escape | |||
mode = "e" | |||
elseif cc == "\t" then | |||
cx = 8*((cx+9)//8) | |||
elseif string.byte(cc) > 31 and string.byte(cc) < 127 then -- printable, I guess | |||
gpu.set(cx, cy, cc) | |||
cx = cx + 1 | |||
end | |||
elseif mode == "e" then | |||
if cc == "[" then | |||
mode = "v" | |||
cs = "" | |||
elseif cc == "D" then -- scroll down | |||
gpu.copy(1,2,mx,my-1,0,-1) | |||
gpu.fill(1,my,mx,1," ") | |||
cy=cy+1 | |||
mode = "n" | |||
elseif cc == "M" then -- scroll up | |||
gpu.copy(1,1,mx,my-1,0,1) | |||
gpu.fill(1,1,mx,1," ") | |||
mode = "n" | |||
else | |||
mode = "n" | |||
end | |||
elseif mode == "v" then | |||
mode = "n" | |||
if cc == "s" then -- save cursor | |||
sx, sy = cx, cy | |||
elseif cc == "u" then -- restore cursor | |||
cx, cy = sx, sy | |||
elseif cc == "H" then -- cursor home or to | |||
local tx, ty = cs:match("(%d+);(%d+)") | |||
tx, ty = tx or "1", ty or "1" | |||
cx, cy = tonumber(tx), tonumber(ty) | |||
elseif cc == "A" then -- cursor up | |||
cy = cy - (tonumber(cs) or 1) | |||
elseif cc == "B" then -- cursor down | |||
cy = cy + (tonumber(cs) or 1) | |||
elseif cc == "C" then -- cursor right | |||
cx = cx + (tonumber(cs) or 1) | |||
elseif cc == "D" then -- cursor left | |||
cx = cx - (tonumber(cs) or 1) | |||
elseif cc == "h" and lc == "7" then -- enable line wrap | |||
lw = true | |||
elseif cc == "l" and lc == "7" then -- disable line wrap | |||
lw = false | |||
elseif cc == "c" then | |||
rs = string.format("%s\27[%d;%d0c",rs,mx,my) | |||
elseif cc == "n" and lc == "6" then | |||
rs = string.format("%s\27[%d;%dR",rs,cx,cy) | |||
elseif cc == "K" then | |||
if lc == "1" then | |||
gpu.fill(1,cy,cx,1," ") | |||
elseif lc == "2" then | |||
gpu.fill(cx,cy,mx,1," ") | |||
else | |||
gpu.fill(1,cy,mx,1," ") | |||
end | |||
elseif cc == "J" then | |||
if lc == "1" then | |||
gpu.fill(1,1,mx,cy," ") | |||
elseif lc == "2" then | |||
gpu.full(1,1,mx,my," ") | |||
cx,cy = 1, 1 | |||
else | |||
gpu.fill(1,cy,mx,my," ") | |||
end | |||
elseif cc == "m" then | |||
for num in cs:gmatch("%d+") do | |||
num=tonumber(num) | |||
if num == 0 then | |||
fg,bg = 0xFFFFFF,0 | |||
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] | |||
end | |||
end | |||
gpu.setForeground(fg) | |||
gpu.setBackground(bg) | |||
else | |||
cs = cs .. cc | |||
if cc:match("[%d;]") then | |||
mode = "v" | |||
end | |||
end | |||
end | |||
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 | |||
lc = cc | |||
end | |||
pc = gpu.get(cx,cy) | |||
gpu.setForeground(bg) | |||
gpu.setBackground(fg) | |||
gpu.set(cx,cy,pc) | |||
gpu.setForeground(fg) | |||
gpu.setBackground(bg) | |||
return rs | |||
end | |||
return termwrite | |||
end |