blob: f298d3c8e56baf8ea8595ae0427e4687fad7813f [file] [log] [blame] [raw]
local pipes = require("pipes")
local blinkState = false
local args = {...}
--local screen = component.list('screen')()
--for address in component.list('screen') do
-- if #component.invoke(address, 'getKeyboards') > 0 then
-- screen = address
-- end
--end
local gpu = args[1] --component.list("gpu", true)()
local screen = args[2]
local blink = true
local w, h
if gpu then
--component.invoke(gpu, "bind", screen)
w, h = component.invoke(gpu, "getResolution")
component.invoke(gpu, "setResolution", w, h)
component.invoke(gpu, "setBackground", 0x000000)
component.invoke(gpu, "setForeground", 0xFFFFFF)
component.invoke(gpu, "fill", 1, 1, w, h, " ")
end
local y = 1
local x = 1
local function checkCoord()
if x < 1 then x = 1 end
if x > w then x = w end
if y < 1 then y = 1 end
if y > h then y = h end
end
local preblinkbg = 0x000000
local preblinkfg = 0x000000
local function unblink()
if blinkState then
blinkState = not blinkState
local char, fg, bg = component.invoke(gpu, "get", x, y)
preblinkbg = blinkState and bg or preblinkbg
preblinkfg = blinkState and fg or preblinkfg
local oribg, obpal = component.invoke(gpu, "setBackground", blinkState and 0xFFFFFF or preblinkbg)
local orifg, ofpal = component.invoke(gpu, "setForeground", blinkState and 0x000000 or preblinkfg)
component.invoke(gpu, "set", x, y, char or " ")
component.invoke(gpu, "setBackground", oribg)
component.invoke(gpu, "setForeground", orifg)
end
end
local function reblink()
if not blinkState then
blinkState = not blinkState
local char, fg, bg = component.invoke(gpu, "get", x, y)
preblinkbg = blinkState and bg or preblinkbg
preblinkfg = blinkState and fg or preblinkfg
local oribg, obpal = component.invoke(gpu, "setBackground", blinkState and 0xFFFFFF or preblinkbg)
local orifg, ofpal = component.invoke(gpu, "setForeground", blinkState and 0x000000 or preblinkfg)
component.invoke(gpu, "set", x, y, char or " ")
component.invoke(gpu, "setBackground", oribg)
component.invoke(gpu, "setForeground", orifg)
end
end
local scrTop = 1
local scrBot = nil
local function scroll()
unblink()
scrBot = scrBot or h
x = 1
if y == h then
component.invoke(gpu, "copy", 1, scrTop + 1, w, scrBot - scrTop, 0, -1)
component.invoke(gpu, "fill", 1, scrBot, w, 1, " ")
else
y = y + 1
end
reblink()
end
local printBuf = ""
local function printBuffer()
if #printBuf < 1 then return end
component.invoke(gpu, "set", x, y, printBuf)
if x == w then
scroll()
else
x = x + unicode.len(printBuf)
checkCoord()
end
printBuf = ""
if pipes.shouldYield() then
os.sleep()
end
end
local function backDelChar()
if #printBuf > 0 then
printBuf = unicode.sub(printBuf, 1, unicode.len(printBuf) - 1)
else
x = x - 1
unblink()
component.invoke(gpu, "set", x, y, " ")
reblink()
end
end
---Char handlers
local charHandlers = {}
function charHandlers.base(char)
if char == "\n" then
printBuffer()
scroll()
elseif char == "\r" then
unblink()
printBuffer()
x = 1
reblink()
elseif char == "\t" then
printBuf = printBuf .. " "
elseif char == "\b" then
backDelChar()
elseif char == "\x1b" then
charHandlers.active = charHandlers.control
charHandlers.control(char)
elseif char:match("[%g%s]") then
printBuf = printBuf .. char
end
end
local mcommands = {}
local swap = false
mcommands["7"] = function()
local fc, fp = component.invoke(gpu, "getForeground")
local bc, bp = component.invoke(gpu, "getBackground")
component.invoke(gpu, "setForeground", bc, bp)
component.invoke(gpu, "setBackground", fc, fp)
swap = true
end
mcommands["0"] = function()
if swap then
local fc, fp = component.invoke(gpu, "getForeground")
local bc, bp = component.invoke(gpu, "getBackground")
component.invoke(gpu, "setForeground", bc, bp)
component.invoke(gpu, "setBackground", fc, fp)
end
swap = false
end
mcommands["1"] = function()end --Bold font
mcommands["2"] = function()end --Dim font
mcommands["3"] = function()end --Italic
mcommands["4"] = function()end --Underscore
mcommands["10"] = function()end --Select primary font (LA100)
mcommands["30"] = function()component.invoke(gpu, "setForeground", 0x000000)end
mcommands["31"] = function()component.invoke(gpu, "setForeground", 0xFF0000)end
mcommands["32"] = function()component.invoke(gpu, "setForeground", 0x00FF00)end
mcommands["33"] = function()component.invoke(gpu, "setForeground", 0xFFFF00)end
mcommands["34"] = function()component.invoke(gpu, "setForeground", 0x0000FF)end
mcommands["35"] = function()component.invoke(gpu, "setForeground", 0xFF00FF)end
mcommands["36"] = function()component.invoke(gpu, "setForeground", 0x00FFFF)end
mcommands["37"] = function()component.invoke(gpu, "setForeground", 0xFFFFFF)end
mcommands["40"] = function()component.invoke(gpu, "setBackground", 0x000000)end
mcommands["41"] = function()component.invoke(gpu, "setBackground", 0xFF0000)end
mcommands["42"] = function()component.invoke(gpu, "setBackground", 0x00FF00)end
mcommands["43"] = function()component.invoke(gpu, "setBackground", 0xFFFF00)end
mcommands["44"] = function()component.invoke(gpu, "setBackground", 0x0000FF)end
mcommands["45"] = function()component.invoke(gpu, "setBackground", 0xFF00FF)end
mcommands["46"] = function()component.invoke(gpu, "setBackground", 0x00FFFF)end
mcommands["47"] = function()component.invoke(gpu, "setBackground", 0xFFFFFF)end
mcommands["39"] = function()component.invoke(gpu, "setForeground", 0xFFFFFF)end
mcommands["49"] = function()component.invoke(gpu, "setBackground", 0x000000)end
local lcommands = {}
lcommands["4"] = function()end --Reset to replacement mode
local ncommands = {}
ncommands["6"] = function()io.write("\x1b[" .. math.floor(y) .. ";" .. math.floor(x) .. "R")end
local commandMode = ""
local commandBuf = ""
local commandList = {}
--TODO \x1b[C -- reset term to initial state
--TODO: REFACTOR INTO FUNCTION ARRAY
--TODO: p9-codes:
-- \x1b9[H];[W]R - set resolution
-- \x1b9[Row];[Col];[Height];[Width]F -- fill
-- \x1b9[Row];[Col];[Height];[Width];[Dest Row];[Dest Col]c -- copy
--Add fake gpu component for compat(?)
local control = {}
control["\x1b"] = function(char) --Begin
commandList = {}
commandBuf = ""
commandMode = ""
unblink()
return true
end
control["["] = function(char)
if commandMode ~= "" or commandBuf ~= "" then
charHandlers.active = charHandlers.base
reblink()
return true
end
commandMode = "["
return true
end
control["("] = function(char)
if commandMode ~= "" or commandBuf ~= "" then
charHandlers.active = charHandlers.base
reblink()
return true
end
commandMode = "("
return true
end
control["9"] = function(char)
if commandMode == "" and commandBuf == "" then
commandMode = "9"
else
commandBuf = commandBuf .. char
return true
end
return true
end
control[";"] = function(char)
commandList[#commandList + 1] = commandBuf
commandBuf = ""
return true
end
control["m"] = function(char)
commandList[#commandList + 1] = commandBuf
if not commandList[1] or commandList[1] == "" then
commandList[1] = "0"
end
for _, command in ipairs(commandList) do
if not mcommands[command] then
pipes.log("Unknown escape code: " .. tostring(command))
break
end
mcommands[command]()
end
end
control["l"] = function(char)
commandList[#commandList + 1] = commandBuf
if not commandList[1] or commandList[1] == "" then
commandList[1] = "0"
end
for _, command in ipairs(commandList) do
if not lcommands[command] then
pipes.log("Unknown escape code: " .. tostring(command))
break
end
lcommands[command]()
end
end
control["n"] = function(char)
commandList[#commandList + 1] = commandBuf
if not commandList[1] or commandList[1] == "" then
commandList[1] = "0"
end
for _, command in ipairs(commandList) do
if not ncommands[command] then
pipes.log("Unknown escape code: " .. tostring(command))
break
end
ncommands[command]()
end
end
control["d"] = function(char)
commandList[#commandList + 1] = commandBuf
local n = tonumber(commandList[1]) or 1
y = math.max(n, 1)
checkCoord()
end
control["R"] = function(char) --Set resolution
if commandMode == "9" then
commandList[#commandList + 1] = commandBuf
local nh, nw = tonumber(commandList[1]) or h, tonumber(commandList[2]) or w
if x > nw then x = math.max(nw, 1) end
if y > nh then y = math.max(nw, 1) end
if component.invoke(gpu, "setResolution", nw, nh) then
w = nw
h = nh
end
end
end
control["I"] = function(char) --Term info
if commandMode == "9" then
io.write("\x1b9" .. gpu .. ";" .. screen .. "I")
end
end
control["!"] = function(char) --Disable
if commandMode == "9" then
charHandlers.active = function(c)
if c == "\255" or c == "!" then
commandList = {}
commandBuf = ""
commandMode = ""
charHandlers.active = charHandlers.base
blink = true
end
end
blink = false
return true
end
end
control["r"] = function(char) --Set scroll region
commandList[#commandList + 1] = commandBuf
local nt, nb = tonumber(commandList[1]) or 1, tonumber(commandList[2]) or h
scrTop = nt
scrBot = nb
end
control["H"] = function(char) --set pos
commandList[#commandList + 1] = commandBuf
local ny, nx = tonumber(commandList[1]), tonumber(commandList[2])
x = math.min(nx or 1, w)
y = math.min(ny or 1, h)
checkCoord()
end
control["f"] = control["H"]
control["A"] = function(char) --Move up
commandList[#commandList + 1] = commandBuf
local n = tonumber(commandList[1]) or 1
y = y - n
checkCoord()
end
control["B"] = function(char) --Move down
if commandMode == "(" then
charHandlers.active = charHandlers.base
reblink()
return true
end
commandList[#commandList + 1] = commandBuf
local n = tonumber(commandList[1]) or 1
y = math.max(y - n, 1)
checkCoord()
end
control["C"] = function(char) --Move forward
commandList[#commandList + 1] = commandBuf
local n = tonumber(commandList[1]) or 1
x = x + n
checkCoord()
end
control["D"] = function(char)
commandList[#commandList + 1] = commandBuf
local n = tonumber(commandList[1]) or 1
x = math.max(x - n, 1)
checkCoord()
end
control["G"] = function(char) --Cursor Horizontal position Absolute
commandList[#commandList + 1] = commandBuf
x = tonumber(commandList[1]) or 1
checkCoord()
end
control["J"] = function(char) --Clear
commandList[#commandList + 1] = commandBuf
if commandList[1] == "2" then
component.invoke(gpu, "fill", 1, 1, w, h, " ")
x, y = 1, 1
end
end
control["K"] = function(char) --Erase to end of line
commandList[#commandList + 1] = commandBuf
component.invoke(gpu, "fill", x, y, w - x, 1, " ")
end
control["X"] = function(char) --Erase next chars
commandList[#commandList + 1] = commandBuf
component.invoke(gpu, "fill", x, y, tonumber(commandList[1]) or 1, 1, " ")
end
function charHandlers.control(char)
if control[char] and not control[char](char) then
charHandlers.active = charHandlers.base
reblink()
commandList = {}
commandBuf = ""
commandMode = ""
elseif not control[char] then
commandBuf = commandBuf .. char
end
end
---Char handler end
charHandlers.active = charHandlers.base
local function _print(msg)
if gpu then
for char in msg:gmatch(".") do
charHandlers.active(char)
end
printBuffer()
end
end
pipes.setTimer(function()
if blink then
blinkState = not blinkState
local char, fg, bg = component.invoke(gpu, "get", x, y)
preblinkbg = blinkState and bg or preblinkbg
preblinkfg = blinkState and fg or preblinkfg
local oribg, obpal = component.invoke(gpu, "setBackground", blinkState and 0xFFFFFF or preblinkbg)
local orifg, ofpal = component.invoke(gpu, "setForeground", blinkState and 0x000000 or preblinkfg)
component.invoke(gpu, "set", x, y, char or " ")
component.invoke(gpu, "setBackground", oribg)
component.invoke(gpu, "setForeground", orifg)
end
end, 0.5)
while true do
local data = io.read(1)
if io.input().remaining() > 0 then
data = data .. io.read(io.input().remaining())
end
unblink()
_print(data)
end