remove multiterm as it's now standard.
This commit is contained in:
parent
9b6bbf508b
commit
b852241638
@ -1,268 +0,0 @@
|
|||||||
local vtansi = {}
|
|
||||||
local keyboardIgnore = {}
|
|
||||||
vtansi.activeBuffers = {}
|
|
||||||
vtansi.sequences = {
|
|
||||||
[28] = "\n", -- newline
|
|
||||||
[200] = "\27[A", -- up
|
|
||||||
[203] = "\27[D", -- left
|
|
||||||
[205] = "\27[C", -- right
|
|
||||||
[208] = "\27[B", -- down
|
|
||||||
[201] = "\27[5~", -- page up
|
|
||||||
[209] = "\27[6~" -- page down
|
|
||||||
}
|
|
||||||
vtansi.keys = {}
|
|
||||||
vtansi.keys[0x38] = "lalt"
|
|
||||||
vtansi.keys[0xB8] = "ralt"
|
|
||||||
function vtansi.saveToBuffer(gpu,idx)
|
|
||||||
gpu.bitblt(idx, nil, nil, nil, nil, 0)
|
|
||||||
end
|
|
||||||
function vtansi.loadFromBuffer(gpu,idx)
|
|
||||||
gpu.bitblt(0, nil, nil, nil, nil, idx)
|
|
||||||
end
|
|
||||||
function vtansi.switchToBuffer(gpu,idx)
|
|
||||||
-- copy screen to the active buffer
|
|
||||||
vtansi.saveToBuffer(gpu,vtansi.activeBuffers[gpu.address])
|
|
||||||
-- copy the new buffer to the screen
|
|
||||||
vtansi.loadFromBuffer(gpu,idx)
|
|
||||||
vtansi.activeBuffers[gpu.address] = idx
|
|
||||||
end
|
|
||||||
function vtansi.vtemu(gpu,bn) -- table number -- function -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal, either allocating a new buffer or using *bn*.
|
|
||||||
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
|
|
||||||
|
|
||||||
local buffer = bn or gpu.allocateBuffer(mx,my)
|
|
||||||
if not vtansi.activeBuffers[gpu.address] then
|
|
||||||
vtansi.activeBuffers[gpu.address] = buffer
|
|
||||||
end
|
|
||||||
local oldActiveBuffer = vtansi.activeBuffers[gpu.address]
|
|
||||||
gpu.setActiveBuffer(buffer)
|
|
||||||
-- 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
|
|
||||||
gpu.setActiveBuffer(oldActiveBuffer)
|
|
||||||
|
|
||||||
local function termwrite(s)
|
|
||||||
if vtansi.activeBuffers[gpu.address] == buffer then
|
|
||||||
gpu.setActiveBuffer(0)
|
|
||||||
else
|
|
||||||
gpu.setActiveBuffer(buffer)
|
|
||||||
end
|
|
||||||
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
|
|
||||||
checkCursor()
|
|
||||||
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 = math.min(mx,tA[1] or 1), math.min(my,tA[2] or 1)
|
|
||||||
elseif cc == "A" then
|
|
||||||
for i = 1, (tA[1] or 1) do
|
|
||||||
cy = cy - 1
|
|
||||||
checkCursor()
|
|
||||||
end
|
|
||||||
elseif cc == "B" then
|
|
||||||
for i = 1, (tA[1] or 1) do
|
|
||||||
cy = cy + 1
|
|
||||||
checkCursor()
|
|
||||||
end
|
|
||||||
elseif cc == "C" then
|
|
||||||
for i = 1, (tA[1] or 1) do
|
|
||||||
cx = cx + 1
|
|
||||||
checkCursor()
|
|
||||||
end
|
|
||||||
elseif cc == "D" then
|
|
||||||
for i = 1, (tA[1] or 1) do
|
|
||||||
cx = cx - 1
|
|
||||||
checkCursor()
|
|
||||||
end
|
|
||||||
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)
|
|
||||||
dprint(string.format("reporting %d;%d as current cursor position",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,false,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 or num == 8 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, buffer
|
|
||||||
end
|
|
||||||
|
|
||||||
function vtansi.vtsession(gpua,scra,bn) -- string string number -- function function function -- creates a process to handle the GPU and screen address combination *gpua*/*scra*, optionally using buffer number *bn* specifically. Returns read, write and "close" functions.
|
|
||||||
local modifiers = {}
|
|
||||||
local gpu = component.proxy(gpua)
|
|
||||||
-- gpu.bind(scra)
|
|
||||||
local write, bn = vtansi.vtemu(gpu,bn)
|
|
||||||
local kba = {}
|
|
||||||
for k,v in ipairs(component.invoke(scra,"getKeyboards")) do
|
|
||||||
kba[v]=true
|
|
||||||
end
|
|
||||||
local buf, lbuf, echo = "", false, false
|
|
||||||
os.spawn(function()
|
|
||||||
while true do
|
|
||||||
local ty,ka,ch,kc = coroutine.yield()
|
|
||||||
if keyboardIgnore[ka] == bn then
|
|
||||||
keyboardIgnore[ka] = nil
|
|
||||||
end
|
|
||||||
if kba[ka] and vtansi.keys[kc] then
|
|
||||||
modifiers[vtansi.keys[kc]] = ty == "key_down"
|
|
||||||
end
|
|
||||||
if ty == "key_down" and kba[ka] and vtansi.activeBuffers[gpua] == bn then
|
|
||||||
if false then
|
|
||||||
elseif ty == "key_down" and kba[ka] and ch == 46 and kc == 52 and (modifiers.lalt or modifiers.ralt) then
|
|
||||||
-- next buffer
|
|
||||||
local allBuffers = gpu.buffers()
|
|
||||||
for k,v in ipairs(allBuffers) do
|
|
||||||
if v == vtansi.activeBuffers[gpu.address] and allBuffers[k+1] and not keyboardIgnore[ka] then
|
|
||||||
keyboardIgnore[ka] = bn
|
|
||||||
vtansi.switchToBuffer(gpu,allBuffers[k+1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif ty == "key_down" and kba[ka] and ch == 44 and kc == 51 and (modifiers.lalt or modifiers.ralt) then
|
|
||||||
-- previous buffer
|
|
||||||
local allBuffers = gpu.buffers()
|
|
||||||
for k,v in ipairs(allBuffers) do
|
|
||||||
if v == vtansi.activeBuffers[gpu.address] and allBuffers[k-1] and not keyboardIgnore[ka] then
|
|
||||||
keyboardIgnore[ka] = bn
|
|
||||||
vtansi.switchToBuffer(gpu,allBuffers[k-1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local outs
|
|
||||||
if ch > 0 then
|
|
||||||
outs = string.char(ch)
|
|
||||||
end
|
|
||||||
outs = vtansi.sequences[kc] or outs
|
|
||||||
if outs then
|
|
||||||
if echo then write(outs) end
|
|
||||||
buf=buf..outs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,string.format("ttyd[%s:%s/%i]",gpua:sub(1,8),scra:sub(1,8),bn))
|
|
||||||
local function bread(n)
|
|
||||||
coroutine.yield()
|
|
||||||
local r = buf
|
|
||||||
buf = ""
|
|
||||||
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
|
|
@ -1,4 +0,0 @@
|
|||||||
{["name"]="multiterm",
|
|
||||||
["description"]="Patched vtansi and getty to support multiple virtual terminals per display, using video memory",
|
|
||||||
["authors"]="Izaya",
|
|
||||||
["system"]=true}
|
|
@ -1,88 +0,0 @@
|
|||||||
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
|
|
||||||
for a,t in pairs(component.list()) do
|
|
||||||
if t == "gpu" then
|
|
||||||
gpus[a] = gpus[a] or {false, tonumber(di[a].capacity)}
|
|
||||||
elseif t == "screen" then
|
|
||||||
screens[a] = screens[a] or {false, tonumber(di[a].capacity)}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
dprint("no getDevInfo")
|
|
||||||
for a,t in pairs(component.list()) do
|
|
||||||
if t == "gpu" then
|
|
||||||
gpus[a] = gpus[a] or {false, 8000}
|
|
||||||
elseif t == "screen" then
|
|
||||||
screens[a] = screens[a] or {false, 8000}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function nextScreen(n)
|
|
||||||
local rt = {}
|
|
||||||
for k,v in pairs(screens) do
|
|
||||||
if not v[1] then
|
|
||||||
rt[v[2]] = rt[v[2]] or k
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return rt[n] or rt[24000] or rt[8000] or rt[4000] or rt[2000] or rt[800] or rt[640] or rt[600]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function spawnShell(fin,fout)
|
|
||||||
io.input(fin)
|
|
||||||
io.output(fout):setvbuf("no")
|
|
||||||
print(_OSVERSION.." - "..tostring(math.floor(computer.totalMemory()/1024)).."K RAM")
|
|
||||||
print((os.getenv("HOSTNAME") or "unknown") .. " on " .. fin)
|
|
||||||
return os.spawn(function() local w,r = pcall(shell.interactive) if not w then syslog(r) end end, "shell: "..tostring(fin))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function allocate()
|
|
||||||
for k,v in pairs(gpus) do
|
|
||||||
dprint(k)
|
|
||||||
local sA = nextScreen(v[2])
|
|
||||||
if v[1] == false and sA then
|
|
||||||
component.invoke(k,"freeAllBuffers")
|
|
||||||
component.invoke(k,"bind",sA)
|
|
||||||
local mw, mh = component.invoke(k,"maxResolution")
|
|
||||||
local bufferSize = mw * mh
|
|
||||||
for i = 1, math.floor(component.invoke(k,"totalMemory") / bufferSize) do
|
|
||||||
local r,w = vtansi.vtsession(k,sA,i == 0 and i)
|
|
||||||
devfs.register("tty"..tostring(ttyn), function() return r,w,function() end end)
|
|
||||||
pids["tty"..tostring(ttyn)] = {-1}
|
|
||||||
ttyn = ttyn + 1
|
|
||||||
end
|
|
||||||
gpus[k][1] = true
|
|
||||||
screens[sA][1] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function start()
|
|
||||||
basepid = os.spawn(function()
|
|
||||||
scan()
|
|
||||||
allocate()
|
|
||||||
dprint("screens ready")
|
|
||||||
while true do
|
|
||||||
coroutine.yield()
|
|
||||||
for k,v in pairs(pids) do
|
|
||||||
if not os.taskInfo(v[1]) then
|
|
||||||
dprint("Spawning new shell for "..k)
|
|
||||||
pids[k][1] = spawnShell(v[2] or "/dev/"..k, v[3] or "/dev/"..k)
|
|
||||||
pids[k][2], pids[k][3] = pids[k][2] or io.input(), pids[k][3] or io.output()
|
|
||||||
coroutine.yield()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,"getty")
|
|
||||||
return basepid
|
|
||||||
end
|
|
||||||
function stop()
|
|
||||||
os.kill(basepid)
|
|
||||||
basepid = nil
|
|
||||||
end
|
|
||||||
return {start=start,stop=stop}
|
|
Loading…
Reference in New Issue
Block a user