Compare commits

...

4 Commits

6 changed files with 163 additions and 39 deletions

View File

@ -21,24 +21,29 @@ end
function shell.interactive() function shell.interactive()
local shenv = setmetatable({}, {__index=shindex}) local shenv = setmetatable({}, {__index=shindex})
local run = true local run = true
os.setenv("PATH",{"/boot/exec","/pkg/exec"})
function shenv.quit() function shenv.quit()
run = false run = false
end end
while run do while run do
io.write(string.format("\27[32m%s:%s>\27[0m ",os.getenv("HOSTNAME") or "localhost",(os.getenv("PWD") or _VERSION))) io.write(string.format("\27[32m%s:%s>\27[0m ",os.getenv("HOSTNAME") or "localhost",(os.getenv("PWD") or _VERSION)))
local input = io.read() local w,input = pcall(io.read)
if input:sub(1,1) == "=" then if not w then
input = "return "..input:sub(2) print("\27[31m^C")
end
local f, r = load(input, "shell", "t", shenv)
if not f then
print("\27[31m"..r)
else else
local rt = {pcall(f)} if input:sub(1,1) == "=" then
local rs = table.remove(rt,1) input = "return "..input:sub(2)
if not rs then io.write("\27[31m") end end
for k,v in pairs(rt) do local f, r = load(input, "shell", "t", shenv)
print(formatValue(v)) if not f then
print("\27[31m"..r)
else
local rt = {pcall(f)}
local rs = table.remove(rt,1)
if not rs then io.write("\27[31m") end
for k,v in pairs(rt) do
print(formatValue(v))
end
end end
end end
end end

View File

@ -119,9 +119,49 @@ function shutil.free() -- Displays used and free memory.
print(string.format("%5s %5s %5s",wrapUnits(computer.totalMemory()),wrapUnits(computer.totalMemory()-computer.freeMemory()),wrapUnits(computer.freeMemory()))) print(string.format("%5s %5s %5s",wrapUnits(computer.totalMemory()),wrapUnits(computer.totalMemory()-computer.freeMemory()),wrapUnits(computer.freeMemory())))
end end
local function pread(self,len)
syslog(tostring(self))
syslog(tostring(len))
io.input(self.input)
local b = io.read(len)
io.input(self)
if b:match("\3") then
error("terminated")
end
return b
end
function shutil.which(name)
local fpath
for _,dir in ipairs(os.getenv("PATH")) do
fpath = fpath or fs.exists(string.format("%s/%s.lua",dir,name)) and string.format("%s/%s.lua",dir,name) or fs.exists(string.format("%s/%s",dir,name)) and string.format("%s/%s",dir,name)
end
return fpath
end
shutil.cd = os.chdir shutil.cd = os.chdir
shutil.mkdir = fs.makeDirectory shutil.mkdir = fs.makeDirectory
shutil.cp = fs.copy shutil.cp = fs.copy
shutil.rm = fs.remove shutil.rm = fs.remove
return shutil return setmetatable({}, {__index = function(t,k)
if shutil[k] then
return shutil[k]
end
local path = shutil.which(k)
if path then
local fn, e = loadfile(path)
if not fn then error(string.format("\n - %s",e)) end
return function()
local pid = os.spawn(fn,path)
local ret = {require("event").pull("process_finished",pid)}
if not ret[3] then
error(string.format("\n - %s",ret[4]))
end
for i = 1, 3 do
table.remove(ret,1)
end
return table.unpack(ret)
end
end
end})

View File

@ -1,4 +1,6 @@
local vtansi = {} local vtansi = {}
local keyboardIgnore = {}
vtansi.activeBuffers = {}
vtansi.sequences = { vtansi.sequences = {
[28] = "\n", -- newline [28] = "\n", -- newline
[200] = "\27[A", -- up [200] = "\27[A", -- up
@ -8,9 +10,26 @@ vtansi.sequences = {
[201] = "\27[5~", -- page up [201] = "\27[5~", -- page up
[209] = "\27[6~" -- page down [209] = "\27[6~" -- page down
} }
function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal 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 colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF}
local mx, my = gpu.maxResolution() local mx, my = gpu.maxResolution()
local buffer = nil
local cx, cy = 1, 1 local cx, cy = 1, 1
local pc = " " local pc = " "
local lc = "" local lc = ""
@ -21,8 +40,19 @@ function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gp
local bg, fg = 0, 0xFFFFFF local bg, fg = 0, 0xFFFFFF
-- setup -- setup
gpu.setResolution(mx,my) if gpu.getActiveBuffer then
gpu.fill(1,1,mx,my," ") buffer = bn or gpu.allocateBuffer(mx,my)
vtansi.activeBuffers[gpu.address] = vtansi.activeBuffers[gpu.address] or buffer
local oldActiveBuffer = vtansi.activeBuffers[gpu.address]
gpu.setActiveBuffer(buffer)
gpu.setResolution(mx,my)
gpu.fill(1,1,mx,my," ")
gpu.setActiveBuffer(oldActiveBuffer)
else
gpu.setResolution(mx,my)
gpu.fill(1,1,mx,my," ")
end
local function checkCursor() local function checkCursor()
if cx > mx and lw then if cx > mx and lw then
cx, cy = 1, cy+1 cx, cy = 1, cy+1
@ -37,6 +67,13 @@ function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gp
end end
local function termwrite(s) local function termwrite(s)
if buffer then
if vtansi.activeBuffers[gpu.address] == buffer then
gpu.setActiveBuffer(0)
else
gpu.setActiveBuffer(buffer)
end
end
local wb = "" local wb = ""
local lb, ec = nil, nil local lb, ec = nil, nil
local function flushwb() local function flushwb()
@ -161,13 +198,14 @@ function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gp
return rs, lb, ec return rs, lb, ec
end end
return termwrite return termwrite, buffer
end end
function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions. 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) local gpu = component.proxy(gpua)
gpu.bind(scra) -- gpu.bind(scra)
local write = vtansi.vtemu(gpu) local write, bn = vtansi.vtemu(gpu,bn)
local kba = {} local kba = {}
for k,v in ipairs(component.invoke(scra,"getKeyboards")) do for k,v in ipairs(component.invoke(scra,"getKeyboards")) do
kba[v]=true kba[v]=true
@ -176,19 +214,45 @@ function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a proc
os.spawn(function() os.spawn(function()
while true do while true do
local ty,ka,ch,kc = coroutine.yield() local ty,ka,ch,kc = coroutine.yield()
if ty == "key_down" and kba[ka] then if kba[ka] and keyboardIgnore[ka] == bn then
local outs keyboardIgnore[ka] = nil
if ch > 0 then end
outs = string.char(ch) if kba[ka] and vtansi.keys[kc] then
end modifiers[vtansi.keys[kc]] = ty == "key_down"
outs = vtansi.sequences[kc] or outs end
if outs then if ty == "key_down" and kba[ka] and (bn == nil or vtansi.activeBuffers[gpua] == bn) then
if echo then write(outs) end if bn and ty == "key_down" and kba[ka] and ch == 46 and kc == 52 and (modifiers.lalt or modifiers.ralt) then
buf=buf..outs -- 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 bn and 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
end end
end,string.format("ttyd[%s:%s]",gpua:sub(1,8),scra:sub(1,8))) end,string.format("ttyd[%s:%s/%i]",gpua:sub(1,8),scra:sub(1,8),tonumber(bn) or 0))
local function bread(n) local function bread(n)
coroutine.yield() coroutine.yield()
local r = buf local r = buf

View File

@ -307,6 +307,8 @@ function buffer:read(...)
if #buffer > 0 and pos <= #buffer then if #buffer > 0 and pos <= #buffer then
buffer = buffer:sub(1, (#buffer - pos)) .. buffer:sub((#buffer - pos) + 2) buffer = buffer:sub(1, (#buffer - pos)) .. buffer:sub((#buffer - pos) + 2)
end end
elseif char == "\3" then -- ^C, error
error("terminated")
elseif char == "\1" then -- ^A, go to start of line elseif char == "\1" then -- ^A, go to start of line
pos = buffer:len()+1 pos = buffer:len()+1
elseif char == "\5" then -- ^E, go to end of line elseif char == "\5" then -- ^E, go to end of line

View File

@ -54,7 +54,7 @@ function fs.open(path,mode) -- string string -- table -- Opens file *path* with
if mode:find("r") then if mode:find("r") then
fobj.read = fread fobj.read = fread
end end
if mode:find("w") then if mode:find("w") or mode:find("a") then
fobj.write = fwrite fobj.write = fwrite
end end
return fobj return fobj

View File

@ -37,20 +37,32 @@ local function spawnShell(fin,fout)
io.input(fin) io.input(fin)
io.output(fout):setvbuf("no") io.output(fout):setvbuf("no")
print(_OSVERSION.." - "..tostring(math.floor(computer.totalMemory()/1024)).."K RAM") print(_OSVERSION.." - "..tostring(math.floor(computer.totalMemory()/1024)).."K RAM")
return os.spawn(function() local w,r = pcall(shell.interactive) if not w then syslog(r) end end, "shell: "..tostring(fin)) 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))
return os.spawn(shell.interactive, "shell: "..tostring(fin))
end end
local function allocate() local function allocate()
for k,v in pairs(gpus) do for k,v in pairs(gpus) do
dprint(k) dprint("Setting up display "..k)
local sA = nextScreen(v[2]) local sA = nextScreen(v[2])
if v[1] == false and sA then if v[1] == false and sA then
local r,w = vtansi.vtsession(k,sA) local terminals = 1
devfs.register("tty"..tostring(ttyn), function() return r,w,function() end end) local gpu = component.proxy(k)
gpu.bind(sA)
if gpu.buffers then
gpu.freeAllBuffers()
local mw, mh = gpu.maxResolution()
terminals = math.floor(gpu.freeMemory() / (mw * mh))
end
for i = 1, terminals do
local r,w = vtansi.vtsession(k,sA)
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 gpus[k][1] = true
screens[sA][1] = true screens[sA][1] = true
pids["tty"..tostring(ttyn)] = {-1}
ttyn = ttyn + 1
end end
end end
end end
@ -59,14 +71,15 @@ function start()
basepid = os.spawn(function() basepid = os.spawn(function()
scan() scan()
allocate() allocate()
dprint("screens ready") dprint("Display setup complete.")
while true do while true do
coroutine.yield() coroutine.yield()
for k,v in pairs(pids) do for k,v in pairs(pids) do
if not os.taskInfo(v[1]) then if not os.taskInfo(v[1]) then
dprint("Spawning new shell for "..k) dprint("Spawning new shell for "..k)
pids[k][1] = spawnShell(v[2] or "/dev/"..k, v[3] or "/dev/"..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() pids[k][2], pids[k][3] = pids[k][2] or "/dev/"..k, pids[k][3] or "/dev/"..k
coroutine.yield()
end end
end end
end end