14 Commits
Author SHA1 Message Date
tema5002 a5de781471 refactor: move source files to src/ directory 2026-09-19 12:30:33 +03:00
tema5002 d2ad6be236 Add telnet (kinda) 2026-08-08 20:16:59 +03:00
tema5002 ca65d252c9 acidentally messed up mcplayers changes :( also fuck you your code sucks ok sorry that was probably rude but still go fu 2026-07-19 11:47:30 +03:00
mcplayer3 fc184ea591 Started to add custom colour palettes
I have literally no idea why it wont work but if anyone picks this up you'll know it works when the old Halyde colours show up
2026-07-19 11:47:23 +03:00
tema5002 8a76ca11c9 The last cutting-edge commit out of the lot making the terminal a lot nicer 2026-07-19 11:45:07 +03:00
tema5002 8a3a34efc0 Update halyde/kernel/modules/terminal.lua 2026-07-19 11:44:05 +03:00
tema5002 996d81129d I am a moron 2026-07-19 11:44:02 +03:00
tema5002 499dfd6843 Amiga Going Ball demo recreation 2026-07-19 11:43:58 +03:00
mcplayer3 8aa08814a1 Apparently I left in some unused variables that were supposed to be removed by Tema 2026-06-20 15:40:58 +03:00
mcplayer3 eaae852961 Started to add custom colour palettes
I have literally no idea why it wont work but if anyone picks this up you'll know it works when the old Halyde colours show up
2026-06-20 15:40:51 +03:00
tema5002 93c632ed6e unsuccessfull attempt at renaming terminal to io... 2026-06-20 14:30:26 +03:00
tema5002 ab48b57e1b Implement profiler 2026-06-20 14:25:40 +03:00
WahPlus 45a09284c2 bedit: Fixed addition of weird DC3 character when saving 2026-06-20 11:27:04 +03:00
mcplayer3 8fc249433b Added saving functionality to bedit
(The text field for the save path needs improving though.)
2026-06-20 17:14:21 +10:00
107 changed files with 2002 additions and 960 deletions
-9
View File
@@ -1,9 +0,0 @@
COMMAND echo
USAGE [TEXT]...
DESCRIPTION Concatenates and prints text to the terminal.
ARG1 TEXT
ARG1DESCRIPTION Text to print.
EXAMPLE1 echo test
EXAMPLE2 echo Hello World!
EXAMPLE1DESCRIPTION Prints "test" to the terminal.
EXAMPLE2DESCRIPTION Prints "Hello World!" to the terminal.
-821
View File
@@ -1,821 +0,0 @@
--[[
TODO:
```bash
echo -e "\033[?25l" # hide
echo -e "\033[?25h" # show
```
]]
local module = {}
function module.check()
return true -- Usually always loaded, but maybe it would be worth it to check if the computer has a GPU or not? I'm not sure.
end
function module.init()
local serialize = require("serialize")
local unicode = require("unicode")
local event = require("event")
local component = require("component")
local computer = require("computer")
local gpu = component.gpu
_G._PUBLIC.terminal = {}
local readHistory = {}
function _PUBLIC.terminal.getHistory(id)
checkArg(1,id,"string")
return table.copy(readHistory[id])
end
function _PUBLIC.terminal.setHistory(id,hist)
checkArg(1,id,"string")
checkArg(2,hist,"table")
for i=1,#hist do
hist[i]=tostring(hist[i])
end
readHistory[id]=hist
end
function _PUBLIC.terminal.addToHistory(id,hist)
checkArg(1,id,"string")
checkArg(2,hist,"string")
table.insert(readHistory[id],hist)
end
local function getColorPalette(depth)
if depth == 1 then
return {
["dark"] = {
[0] = 0x000000,
[1] = 0xffffff,
[2] = 0xffffff,
[3] = 0xffffff,
[4] = 0xffffff,
[5] = 0xffffff,
[6] = 0xffffff,
[7] = 0xffffff,
},
["bright"] = {
[0] = 0x000000,
[1] = 0xffffff,
[2] = 0xffffff,
[3] = 0xffffff,
[4] = 0xffffff,
[5] = 0xffffff,
[6] = 0xffffff,
[7] = 0xffffff,
}
}
end
if depth == 4 then
return {
-- Closest colors to the 4 bit OC pallete
-- Better than outright failure
["dark"] = {
[0] = 0x000000, -- black
[1] = 0x663300, -- brown (dark red)
[2] = 0x336600, -- green (dark green)
[3] = 0x336600, -- green (dark yellow)
[4] = 0x333399, -- blue (dark blue)
[5] = 0x9933CC, -- purple (dark purple)
[6] = 0x333399, -- blue (dark cyan)
[7] = 0xCCCCCC -- silver (dark white)
},
["bright"] = {
[0] = 0x333333, -- gray (bright black)
[1] = 0xff3333, -- red
[2] = 0x33cc33, -- lime (green)
[3] = 0xffff33, -- yellow
[4] = 0x333399, -- blue
[5] = 0xcc66cc, -- magenta (purple)
[6] = 0x336699, -- cyan
[7] = 0xffffff -- white
}
}
end
if depth == 8 then
return {
["dark"] = {
[0] = 0x0f0f0f, -- black
[1] = 0xcc2424, -- dark red
[2] = 0x339280, -- dark green
[3] = 0x996d00, -- dark yellow
[4] = 0x004980, -- dark blue
[5] = 0x9949c0, -- dark purple
[6] = 0x33b6c0, -- dark cyan
[7] = 0xc3c3c3 -- dark white
},
["bright"] = {
[0] = 0x666d80, -- brighter black
[1] = 0xff6d40, -- red
[2] = 0x33db80, -- green
[3] = 0xffb600, -- yellow
[4] = 0x336dff, -- blue
[5] = 0xcc6dc0, -- purple
[6] = 0x33dbc0, -- cyan
[7] = 0xffffff -- white
}
}
end
--[[ Original color palette:
{
["dark"] = {
[0] = 0x171421,
[1] = 0xc01c28,
[2] = 0x26a269,
[3] = 0xa2734c,
[4] = 0x12488b,
[5] = 0xa347ba,
[6] = 0x2aa1b3,
[7] = 0xd0cfcc
},
["bright"] = {
[0] = 0x5e5c64,
[1] = 0xf66151,
[2] = 0x33d17a,
[3] = 0xe9ad0c,
[4] = 0x2a7bde,
[5] = 0xc061cb,
[6] = 0x33c7de,
[7] = 0xffffff
}
}
]]
-- Shouldn't reach here
error()
end
local ANSIColorPalette = getColorPalette(gpu.maxDepth())
local expecting_unicode_bytes = 0
local unicode_bytes_left = 0
local unicode_codepoint = 0
local cursor = { x = 1, y = 1, X = nil, Y = nil } -- X and Y are managed by ESC s and ESC u
local printState = 0 -- 0:none 1:in ESC 2:in CSI
local color = {
FG = ANSIColorPalette["bright"][7], BG = ANSIColorPalette["dark"][0],
fg = nil, bg = nil, reverse = false
}
color.fg = color.FG
color.bg = color.BG
local current_codepoint = 0
local bytes_remaining = 0
local seq = {}
local writeBuf = {}
local function update_gpu_colors()
if color.reverse then
gpu.setForeground(color.bg)
gpu.setBackground(color.fg)
else
gpu.setForeground(color.fg)
gpu.setBackground(color.bg)
end
end
local width, height = gpu.getResolution()
function _G._PUBLIC.terminal.getResolution()
return width, height
end
gpu.setForeground(color.fg)
gpu.setBackground(color.bg)
local function scroll()
if gpu.copy(1, 2, width, height - 1, 0, -1) then
gpu.setForeground(color.FG)
gpu.setBackground(color.BG)
gpu.fill(1, height, width, 1, " ")
gpu.setForeground(color.fg)
gpu.setBackground(color.bg)
cursor.y = height
end
end
local function check_wrap_and_scroll()
if cursor.x > width then
cursor.x = 1
cursor.y = cursor.y + 1
end
while cursor.y > height do
scroll()
end
end
local function exec_csi()
local params = {}
local op = 0
local current_num = 0
local have_num = false
for i = 1, #seq do
local byte = seq[i]
if 0x30 <= byte and byte <= 0x39 then
current_num = current_num * 10 + (byte - 0x30)
have_num = true
elseif byte == 0x3b then
table.insert(params, have_num and current_num or 0)
current_num = 0
have_num = false
else
if have_num then
table.insert(params, current_num)
end
if 0x40 <= byte and byte <= 0x7e then
op = byte
end
break
end
end
local function get_param(idx, default)
if idx <= #params and params[idx] ~= nil then
return params[idx]
end
return default
end
if op == 0x48 or op == 0x66 then
local row = get_param(1, 1)
local col = get_param(2, 1)
cursor.y = row
cursor.x = col
if cursor.x < 1 then cursor.x = 1 end
if cursor.y < 1 then cursor.y = 1 end
if cursor.x > width then cursor.x = width end
if cursor.y > height then cursor.y = height end
return
end
if op == 0x41 then
local n = get_param(1, 1)
cursor.y = cursor.y - n
if cursor.y < 1 then cursor.y = 1 end
return
end
if op == 0x42 then
local n = get_param(1, 1)
cursor.y = cursor.y + n
if cursor.y > height then cursor.y = height end
return
end
if op == 0x43 then
local n = get_param(1, 1)
cursor.x = cursor.x + n
if cursor.x > width then cursor.x = width end
return
end
if op == 0x44 then
local n = get_param(1, 1)
cursor.x = cursor.x - n
if cursor.x < 1 then cursor.x = 1 end
return
end
if op == 0x47 then
local col = get_param(1, 1)
cursor.x = col
if cursor.x < 1 then cursor.x = 1 end
if cursor.x > width then cursor.x = width end
return
end
if op == 0x4a then
local mode = get_param(1, 0)
if mode == 0 then
update_gpu_colors()
gpu.fill(cursor.x, cursor.y, width - cursor.x + 1, height - cursor.y + 1, " ")
elseif mode == 1 then
update_gpu_colors()
gpu.fill(1, 1, cursor.x, cursor.y, " ")
elseif mode == 2 then
update_gpu_colors()
gpu.fill(1, 1, width, height, " ")
cursor.x = 1
cursor.y = 1
end
return
end
if op == 0x4b then
local mode = get_param(1, 0)
if mode == 0 then
update_gpu_colors()
gpu.fill(cursor.x, cursor.y, width - cursor.x + 1, 1, " ")
elseif mode == 1 then
update_gpu_colors()
gpu.fill(1, cursor.y, cursor.x, 1, " ")
elseif mode == 2 then
update_gpu_colors()
gpu.fill(1, cursor.y, width, 1, " ")
end
return
end
if op == 0x60 then
local col = get_param(1, 1)
cursor.x = col
if cursor.x < 1 then cursor.x = 1 end
if cursor.x > width then cursor.x = width end
return
end
if op == 0x64 then
local row = get_param(1, 1)
cursor.y = row
if cursor.y < 1 then cursor.y = 1 end
if cursor.y > height then cursor.y = height end
return
end
if op == 0x6d then
local j = 1
local function parse_extended_color()
local mode = get_param(j + 1, -1)
if mode == 5 then
local idx = get_param(j + 2, 0)
j = j + 2
if idx < 8 then
return ANSIColorPalette["dark"][idx]
elseif idx < 16 then
return ANSIColorPalette["bright"][idx - 8]
elseif idx < 232 then
local i = idx - 16
local b = (i % 6) * 51
local g = ((i // 6) % 6) * 51
local r = (i // 36) * 51
return (r << 16) | (g << 8) | b
else
local v = (idx - 232) * 10 + 8
return (v << 16) | (v << 8) | v
end
elseif mode == 2 then
local r = get_param(j + 2, 0)
local g = get_param(j + 3, 0)
local b = get_param(j + 4, 0)
j = j + 4
return (r << 16) | (g << 8) | b
end
return nil
end
if #params == 0 then
color.reverse = false
color.fg = color.FG
color.bg = color.BG
update_gpu_colors()
return
end
while j <= #params do
local p = params[j] or 0
if p == 0 then
color.reverse = false
color.fg = color.FG
color.bg = color.BG
elseif p == 1 then
elseif p == 2 then
elseif p == 3 then
elseif p == 4 then
elseif p == 5 or p == 6 then
elseif p == 7 then
color.reverse = true
elseif p == 8 then
color.fg = color.bg
elseif p == 9 then
elseif p == 21 then
elseif p == 22 then
elseif p == 23 then
elseif p == 24 then
elseif p == 25 then
elseif p == 27 then
color.reverse = false
elseif p == 28 then
color.fg = color.FG
elseif p == 29 then
elseif 30 <= p and p <= 37 then
color.fg = ANSIColorPalette["dark"][p - 30]
elseif p == 38 then
local c = parse_extended_color()
if c then color.fg = c end
elseif p == 39 then
color.fg = color.FG
elseif 40 <= p and p <= 47 then
color.bg = ANSIColorPalette["dark"][p - 40]
elseif p == 48 then
local c = parse_extended_color()
if c then color.bg = c end
elseif p == 49 then
color.bg = color.BG
elseif p == 58 then
parse_extended_color()
elseif p == 59 then
elseif 90 <= p and p <= 97 then
color.fg = ANSIColorPalette["bright"][p - 90]
elseif 100 <= p and p <= 107 then
color.bg = ANSIColorPalette["bright"][p - 100]
end
j = j + 1
end
update_gpu_colors()
return
end
if op == 0x73 then
cursor.X = cursor.x
cursor.Y = cursor.y
return
end
if op == 0x75 then
if cursor.X and cursor.Y then
cursor.x = cursor.X
cursor.y = cursor.Y
if cursor.x < 1 then cursor.x = 1 end
if cursor.y < 1 then cursor.y = 1 end
if cursor.x > width then cursor.x = width end
if cursor.y > height then cursor.y = height end
end
return
end
end
function _G._PUBLIC.terminal.writec(byte)
if byte == 0x1b then
_PUBLIC.terminal.flush()
printState = 1
seq = {}
return
end
if printState == 1 then
if byte == 0x5b then
printState = 2
else
printState = 0
end
return
end
if printState == 2 then
table.insert(seq, byte)
if 0x40 <= byte and byte <= 0x7e then
exec_csi()
printState = 0
seq = {}
end
return
end
if byte == 0xa then
_PUBLIC.terminal.flush()
cursor.y = cursor.y + 1
cursor.x = 1
check_wrap_and_scroll()
return
end
if byte == 0xd then
_PUBLIC.terminal.flush()
cursor.x = 1
return
end
if byte == 0x8 then
_PUBLIC.terminal.flush()
if cursor.x > 1 then
cursor.x = cursor.x - 1
end
return
end
if byte == 0x9 then
_PUBLIC.terminal.flush()
cursor.x = ((cursor.x - 1) // 8) * 8 + 9
if cursor.x < 1 then cursor.x = 1 end
if cursor.x > width then cursor.x = width end
return
end
if byte >= 0x20 and byte <= 0x7F then
table.insert(writeBuf, string.char(byte))
cursor.x = cursor.x + 1
check_wrap_and_scroll()
if cursor.y ~= writeBufY or #writeBuf >= 32 then
_PUBLIC.terminal.flush()
end
elseif byte >= 0xC2 and byte <= 0xDF then
current_codepoint = (byte & 0x1F)
bytes_remaining = 1
elseif byte >= 0xE0 and byte <= 0xEF then
current_codepoint = (byte & 0x0F)
bytes_remaining = 2
elseif byte >= 0xF0 and byte <= 0xF7 then
current_codepoint = (byte & 0x07)
bytes_remaining = 3
elseif byte >= 0x80 and byte <= 0xBF and bytes_remaining > 0 then
current_codepoint = (current_codepoint << 6) | (byte & 0x3F)
bytes_remaining = bytes_remaining - 1
if bytes_remaining == 0 then
table.insert(writeBuf, utf8.char(current_codepoint))
cursor.x = cursor.x + 1
check_wrap_and_scroll()
if cursor.y ~= writeBufY or #writeBuf >= 32 then
_PUBLIC.terminal.flush()
end
current_codepoint = 0
end
else
current_codepoint = 0
bytes_remaining = 0
end
end
function _G._PUBLIC.terminal.write(text)
text = tostring(text)
for i = 1, #text do
_PUBLIC.terminal.writec(string.byte(text, i))
end
end
function _G._PUBLIC.terminal.clear()
update_gpu_colors()
gpu.fill(1, 1, width, height, " ")
writeBuf = {}
cursor.x = 1
cursor.y = 1
end
function _G._PUBLIC.terminal.flush()
if #writeBuf == 0 then return end
update_gpu_colors()
gpu.set(cursor.x - #writeBuf, cursor.y, table.concat(writeBuf))
writeBuf = {}
end
function _G.print(...)
local args = {...}
local stringArgs = {}
for _, arg in pairs(args) do
if type(arg)=="table" then
table.insert(stringArgs, serialize(arg))
elseif tostring(arg) then
table.insert(stringArgs, tostring(arg))
end
end
_PUBLIC.terminal.write(table.concat(stringArgs, "\t") .. "\n")
end
function _G._PUBLIC.terminal.read(options)
checkArg(1, options, "table", "nil")
local function checkOption(name, value, neededType)
assert(not value or type(value) == neededType, ("%s option must be %s, %s provided"):format(name, neededType, type(value)))
end
if not options then
options = {}
end
checkOption("readHistoryType", options.readHistoryType, "string")
checkOption("prefix", options.prefix, "string")
checkOption("maxChars", options.maxChars, "number")
checkOption("defaultText", options.defaultText, "string")
checkOption("censor", options.censor, "string")
options.maxChars = options.maxChars or math.huge
local text = options.defaultText or ""
_G._PUBLIC.terminal.flush()
local historyIdx
if options.readHistoryType then
if not readHistory[options.readHistoryType] then
readHistory[options.readHistoryType] = {text}
elseif readHistory[options.readHistoryType][#readHistory[options.readHistoryType] ] ~= text then
table.insert(readHistory[options.readHistoryType], text)
end
historyIdx = #readHistory[options.readHistoryType]
end
local function updateHistory()
if not options.readHistoryType then return end
if historyIdx ~= #readHistory[options.readHistoryType] then return end
readHistory[options.readHistoryType][historyIdx]=text
end
local cur = unicode.len(text)+1
if options.prefix then _PUBLIC.terminal.write(options.prefix) end
local startX, startY = cursor.x, cursor.y
local fg, bg = gpu.getForeground(), gpu.getBackground()
local cursorBlink = true
local function checkScroll(y)
for i=1,y-height do
scrollDown()
startY=startY-1
end
return math.min(y,height)
end
local function set(index, character, invertedColors) -- HACK: Currently, this will uncensor all spaces in the inputted text.
if character==nil or character=="" then return end
if options.censor then
character = character:gsub("[^ ]", options.censor)
end
if invertedColors then
gpu.setForeground(bg)
gpu.setBackground(fg)
else
gpu.setForeground(fg)
gpu.setBackground(bg)
end
index=startX+index-1
local setX, setY = (index-1)%width+1, startY+((index-1)//width+1)-1
setY = checkScroll(setY)
gpu.set(setX,setY,unicode.sub(character,1,width-setX+1))
for i=1,math.ceil((#character+setX-1)/width)+1 do
gpu.set(1,setY+i,unicode.sub(character,2-setX+i*width,width+i*width-setX))
setY = checkScroll(setY)
end
end
local function strDef(a,b)
if #a==0 then return b end
return a
end
local function curPos(cur)
return unicode.wlen(unicode.sub(text,1,cur-1))+1
end
local function add(chr)
if type(chr)~="string" or #chr==0 then return end
if unicode.len(text)>=options.maxChars then return end
if options.maxChars<math.huge then
chr=unicode.sub(chr,1,options.maxChars-unicode.len(text))
end
text=unicode.sub(text,1,cur-1)..chr..unicode.sub(text,cur)
set(curPos(cur),chr,false)
cur=math.min(cur+unicode.len(chr),options.maxChars+1)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
set(curPos(cur+1),unicode.sub(text,cur+1),false)
end
local function moveCur(dir)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
cur=math.max(math.min(cur+dir,unicode.len(text)+1),1)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
end
local function isLetter(chr)
return not string.find("\x09 :@-./_~?&=%+#",chr,1,true)
end
local function nextCur(dir,chr,icur)
if icur==nil then icur=cur end
local next = math.max(math.min(icur+dir,unicode.len(text)+1),1)
if chr then return unicode.sub(text,next,next) end
return next
end
local function curAfterWord(dir)
local ncur = cur
while nextCur(dir,false,ncur)~=ncur and isLetter(nextCur(dir,true,ncur))==(dir==1) do
ncur=nextCur(dir,false,ncur)
end
while nextCur(dir,false,ncur)~=ncur and isLetter(nextCur(dir,true,ncur))==(dir==-1) do
ncur=nextCur(dir,false,ncur)
end
return ncur
end
local function moveWord(dir)
if nextCur(dir)==cur then return end
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
cur=curAfterWord(dir)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
end
local function deleteWord(dir)
local after = curAfterWord(dir)
local lenb = unicode.wlen(text)
if dir==1 then
text=unicode.sub(text,1,cur-1)..unicode.sub(text,after)
set(curPos(cur+1),unicode.sub(text,cur+1)..string.rep(" ",lenb-unicode.wlen(text)+1),false)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
else
text = unicode.sub(text,1,after-1)..unicode.sub(text,cur)
cur=after
set(curPos(cur+1),unicode.sub(text,cur+1)..string.rep(" ",lenb-unicode.wlen(text)+1),false)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
end
updateHistory()
cursorBlink = true
end
local function isLine(chr)
return chr=="\n" or chr=="\r"
end
--[[ gpu.set(startX,startY,unicode.sub(text,1,width-startX))
for i=1,(#text+startX)//width-1 do
gpu.set(startX,startY+i,unicode.sub(text,1+i*width,width-startX+i*width))
end ]]
set(1,text,false)
set(curPos(cur)," ",true)
local function reprint(new)
set(1,new..string.rep(" ",unicode.wlen(text)-unicode.wlen(new)+1),false)
cur=unicode.len(new)+1
text=new
set(curPos(cur)," ",true)
end
while true do
local args = {event.pull("key_down", "clipboard", 0.5)}
local ctrlDown = _PUBLIC.keyboard.getCtrlDown()
if args and args[1] == "key_down" and args[4] then
local key = _PUBLIC.keyboard.keys[args[4]]
if key=="up" and options.readHistoryType then
historyIdx=math.max(historyIdx-1,1)
reprint(readHistory[options.readHistoryType][historyIdx])
elseif key=="down" and options.readHistoryType then
historyIdx=math.min(historyIdx+1,#readHistory[options.readHistoryType])
reprint(readHistory[options.readHistoryType][historyIdx])
elseif key=="left" and ctrlDown then
moveWord(-1)
elseif key=="right" and ctrlDown then
moveWord(1)
elseif key=="left" then
moveCur(-1)
elseif key=="right" then
moveCur(1)
elseif key=="home" then
moveCur(-math.huge)
elseif key=="end" then
moveCur(math.huge)
elseif key=="back" and ctrlDown then
deleteWord(-1)
elseif key=="delete" and ctrlDown then
deleteWord(1)
elseif key=="back" and cur>1 then
text=unicode.sub(text,1,cur-2)..unicode.sub(text,cur)
cur=cur-1
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
set(curPos(cur)+1,unicode.sub(text,cur+1).." ",false)
updateHistory()
elseif key=="delete" then
text = unicode.sub(text,1,cur-1)..unicode.sub(text,cur+1)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
if cur<=unicode.len(text) then
set(curPos(cur+1),unicode.sub(text,cur+1).." ",false)
end
updateHistory()
elseif key=="enter" then
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
break
elseif not (args[3]<32 or (args[3]>0x7F and args[3]<=0x9F)) then
add(unicode.char(args[3]) or " ")
updateHistory()
end
elseif args and args[1]=="clipboard" then
local clip = args[3]
if not args[3] then goto continue end
while isLine(unicode.sub(clip,1,1)) do clip=unicode.sub(clip,2) end
while isLine(unicode.sub(clip,-1)) do clip=unicode.sub(clip,1,-2) end
add(clip)
updateHistory()
else
cursorBlink=not cursorBlink
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),cursorBlink)
end
::continue::
end
if options.readHistoryType then
if readHistory[options.readHistoryType][#readHistory[options.readHistoryType]]=="" then
table.remove(readHistory[options.readHistoryType],#readHistory[options.readHistoryType])
end
if historyIdx<#readHistory[options.readHistoryType] then
-- table.remove(readHistory[options.readHistoryType],historyIdx)
table.insert(readHistory[options.readHistoryType],text)
end
while #readHistory[options.readHistoryType] > 50 do
table.remove(readHistory[options.readHistoryType], 1)
end
end
cursor.x=1
cursor.y=cursor.y+math.ceil((unicode.wlen(text)+startX-1)/width)
if cursor.y>height then scroll() end
return text
end
end
function module.exit()
_G._PUBLIC.terminal = nil
end
return module
View File
@@ -69,6 +69,73 @@ local function removeLine(pos)
lines[length] = nil
end
local function save()
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
gpu.set(1, resY, "Enter a location to save:")
local savepath = file or ""
local saveCursorX = 27 + #savepath
local ready = false
local eventArgs = {}
gpu.fill(27, resY, resX - 27, 1, " ")
gpu.set(27, resY, savepath)
gpu.setForeground(0x000000)
gpu.setBackground(0xFFFFFF)
gpu.set(saveCursorX, resY, " ")
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
repeat
local shouldRender = false
coroutine.yield()
eventArgs = {event.pull("key_down", 0)}
if keyboard.keys[eventArgs[4]] == "enter" then
ready = true
end
if keyboard.keys[eventArgs[4]] == "back" then
savepath = string.sub(savepath, 1, #savepath - 1)
if saveCursorX > 27 then
saveCursorX = saveCursorX - 1
end
shouldRender = true
end
if not keyboard.keys.special[eventArgs[4]] and keyboard.keys[eventArgs[4]] then
savepath = savepath .. (string.char(eventArgs[3]) or "")
saveCursorX = saveCursorX + 1
shouldRender = true
end
if shouldRender then
gpu.fill(27, resY, resX - 27, 1, " ")
gpu.set(27, resY, savepath)
gpu.setForeground(0x000000)
gpu.setBackground(0xFFFFFF)
gpu.set(saveCursorX, resY, " ")
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
end
until ready
gpu.fill(1, resY, resX, 1, " ")
gpu.setForeground(0x000000)
gpu.setBackground(0xFFFFFF)
gpu.set(1, resY, "^X")
gpu.set(10, resY, "^S")
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
gpu.set(4, resY, "Exit")
gpu.set(13, resY, "Save")
local text = table.concat(lines, "\n")
local handle = fs.open(savepath, "w")
handle:write(text)
handle:close()
file = savepath
end
-- Initialize screen
renderText(0, 0)
gpu.setForeground(0x000000)
@@ -118,8 +185,10 @@ while true do
if keyboard.keys[eventArgs[4]] == "x" then
goto exit
end
if keyboard.keys[eventArgs[4]] == "s" then
save()
end
else
if keyboard.keys[eventArgs[4]] == "up" and cursorY > 1 then
if cursorY - scrollY <= 1 then
renderBufferFlag = true
@@ -213,6 +282,7 @@ while true do
renderBufferFlag = true
end
end
end
until next(eventArgs) == nil
local displayedCursorX = cursorX - scrollX
local displayedCursorY = cursorY - scrollY
+585
View File
@@ -0,0 +1,585 @@
local raster = require("raster")
local event = require("event")
local color_table = {
0xAAAAAA, 0x666666, 0xFF0000, 0xFF0000, 0xFFDDDD, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000,
0xAA00AA, 0x660066, 0xFF0000, 0xFF0000, 0xFFDDDD, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000
}
local ball_bitplanes = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0007, 0xff80, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0xffff, 0xfc00, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x00f8, 0x007f, 0xffff, 0xff80, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0fe6, 0x03ff, 0xffff, 0xfff0, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfd1b, 0x980f, 0xffff, 0xfffc, 0x0000, 0x0000,
0x0000, 0x0000, 0x000f, 0xc14e, 0xb410, 0xffff, 0xffff, 0x8000, 0x0000,
0x0000, 0x0000, 0x00fc, 0x927a, 0xe92a, 0x7fff, 0xffff, 0xf000, 0x0000,
0x0000, 0x0000, 0x00c5, 0x09db, 0xa26f, 0x6fff, 0xffff, 0xfe00, 0x0000,
0x0000, 0x0000, 0x01d0, 0x46ee, 0xc4d2, 0x0fff, 0xffff, 0xff80, 0x0000,
0x0000, 0x0000, 0x0bba, 0x3bbd, 0x99b2, 0xd5bf, 0xffff, 0xffc0, 0x0000,
0x0000, 0x0000, 0x0d76, 0x5ef6, 0x3324, 0xd57f, 0xffff, 0xffe0, 0x0000,
0x0000, 0x0000, 0x5dec, 0x8fdc, 0x4665, 0xd55f, 0xffff, 0xfff0, 0x0000,
0x0000, 0x0000, 0xab99, 0x18f8, 0x8ccd, 0x9455, 0xffff, 0xfff8, 0x0000,
0x0000, 0x0002, 0xd772, 0x3103, 0x19c9, 0x96aa, 0xffff, 0xfffc, 0x0000,
0x0000, 0x000d, 0xaecc, 0x6238, 0x3199, 0x96aa, 0x6fff, 0xfffe, 0x0000,
0x0000, 0x001a, 0xbd98, 0xc673, 0x8399, 0xb695, 0x97ff, 0xffff, 0x8000,
0x0000, 0x006d, 0x7331, 0x8c73, 0x1b39, 0xb255, 0xbbff, 0xffff, 0xc000,
0x0000, 0x00d2, 0xe663, 0x18e7, 0x30f3, 0x324a, 0x9dff, 0xffff, 0xe000,
0x0000, 0x0fa5, 0xccc3, 0x31ce, 0x31c3, 0x324b, 0xebff, 0xffff, 0xf000,
0x0000, 0x1917, 0xb986, 0x23ce, 0x618c, 0x336d, 0x71ff, 0xffff, 0xf800,
0x0000, 0x1ade, 0x670c, 0x639c, 0x639c, 0xc325, 0xa8ff, 0xffff, 0xfc00,
0x0000, 0x32a3, 0xce18, 0xc73c, 0xc319, 0xcf26, 0xf37f, 0xffff, 0xfe00,
0x0000, 0x35a6, 0x7c31, 0x8e38, 0xc719, 0xccf2, 0xd5df, 0xffff, 0xff00,
0x0000, 0x6946, 0xc463, 0x1e71, 0x8739, 0x8ccf, 0x7a6f, 0xffff, 0xff00,
0x0000, 0xcacc, 0xc707, 0x1c71, 0x8e31, 0x9ccc, 0x6d37, 0xffff, 0xff80,
0x0000, 0xd69d, 0x8e7e, 0x38e3, 0x0e33, 0x98cc, 0xcd4b, 0xffff, 0xff80,
0x0001, 0x9599, 0x8e73, 0xb9e3, 0x1c73, 0x98cc, 0xc9b7, 0xffff, 0xffc0,
0x0001, 0xad33, 0x1ce3, 0x81c6, 0x1c63, 0x98cc, 0xc92b, 0xffff, 0xffc0,
0x0003, 0x4b33, 0x1ce7, 0x0dc6, 0x3c63, 0x18cc, 0xc92b, 0xffff, 0xffe0,
0x0003, 0x5666, 0x39c7, 0x1c4c, 0x38e7, 0x18cc, 0xccaa, 0x3fff, 0xffe0,
0x0006, 0x96e6, 0x39ce, 0x1872, 0x78c7, 0x19cc, 0xc495, 0x3fff, 0xfff0,
0x000d, 0x2ccc, 0x738e, 0x38f3, 0xb0c7, 0x19cc, 0xc495, 0x1fff, 0xfff0,
0x000d, 0x5dcc, 0x739c, 0x30e7, 0x89c7, 0x39ce, 0xc495, 0x1fff, 0xfff0,
0x001a, 0x5b98, 0xe71c, 0x71e7, 0x0f8e, 0x31ce, 0x64d4, 0xffff, 0xfff8,
0x001a, 0xbb18, 0xe738, 0x71cf, 0x1e4e, 0x31ce, 0x64ca, 0x8fff, 0xfff8,
0x0008, 0xb731, 0xce38, 0xe1ce, 0x1c71, 0x31ce, 0x664a, 0x8fff, 0xfffc,
0x000a, 0xf631, 0xce78, 0xe38e, 0x3cf1, 0xf1ce, 0x664a, 0x77ff, 0xfffc,
0x000a, 0x9e63, 0x9c71, 0xc39e, 0x3ce3, 0xc9ce, 0x6649, 0x47ff, 0xfffe,
0x000a, 0x9063, 0x9cf1, 0xc71c, 0x38e3, 0x8ece, 0x6261, 0x5fff, 0xfffe,
0x0004, 0x9327, 0x38e3, 0x873c, 0x78e3, 0x9e36, 0x6265, 0x1bff, 0xffff,
0x0015, 0x933f, 0x39e3, 0x8e38, 0x79e3, 0x9c30, 0x6264, 0x23ff, 0xffff,
0x0015, 0x3339, 0xb1c7, 0x8e38, 0xf1c7, 0x9c71, 0x9324, 0xafff, 0xffff,
0x0015, 0x2639, 0x83c7, 0x0c78, 0xf1c7, 0x1c61, 0x9f30, 0x8dff, 0xffff,
0x0015, 0x2671, 0x8d8f, 0x1c70, 0xe3c7, 0x3c63, 0x9cf2, 0x91ff, 0xffff,
0x0015, 0x2673, 0x8c76, 0x1871, 0xe38f, 0x3863, 0x1cce, 0x16ff, 0xffff,
0x0009, 0x2673, 0x1c71, 0x38f1, 0xe38e, 0x38e3, 0x38cd, 0xc6ff, 0xffff,
0x000b, 0x2673, 0x1861, 0xf0e1, 0xc78e, 0x78c3, 0x39cd, 0xbbff, 0xffff,
0x000b, 0x6663, 0x18e3, 0xc9e3, 0xc70e, 0x70c7, 0x399d, 0xb47f, 0xffff,
0x000b, 0x6c67, 0x18e3, 0x8ec3, 0xc71e, 0x71c6, 0x3999, 0xb4ff, 0xffff,
0x004b, 0x6ce7, 0x38e3, 0x9e27, 0x871c, 0x71c6, 0x3199, 0x34ff, 0xffff,
0x002b, 0x6ce7, 0x30c3, 0x9c38, 0x4f1c, 0xf1c6, 0x339b, 0x2cff, 0xfffe,
0x0012, 0x6ce6, 0x31c7, 0x9c78, 0x761c, 0xe186, 0x739b, 0x6aff, 0xfffe,
0x0016, 0x4cc6, 0x31c7, 0x1c70, 0xf13c, 0xe38e, 0x739b, 0x69ff, 0xfffe,
0x0096, 0xccce, 0x3187, 0x3c70, 0xe1d8, 0xe38c, 0x733b, 0x69ff, 0xfffe,
0x00e6, 0xd8ce, 0x718f, 0x3871, 0xe3c1, 0xe38c, 0x6333, 0x69ff, 0xfffe,
0x0068, 0xd9ce, 0x618e, 0x38f1, 0xc386, 0xc30c, 0x6732, 0x69ff, 0xfffe,
0x0071, 0x198e, 0x638e, 0x78e1, 0xc78e, 0x271c, 0x6732, 0x59ff, 0xfffe,
0x0074, 0x219c, 0x630e, 0x70e3, 0xc70c, 0x3898, 0xe732, 0x55ff, 0xfffe,
0x0034, 0xa61c, 0xe31e, 0x71e3, 0x871c, 0x78f8, 0xc732, 0x55ff, 0xfffe,
0x0038, 0x866c, 0xc31c, 0x71c7, 0x8f18, 0x71e4, 0xce72, 0x55ff, 0xfffe,
0x003a, 0x9263, 0xc71c, 0xf1c7, 0x0e38, 0xf1c7, 0x0e66, 0xd5ff, 0xfffe,
0x001a, 0x1323, 0x261c, 0xe3c7, 0x1e38, 0xe3ce, 0x7664, 0xd5ff, 0xfffe,
0x001c, 0x5323, 0x393c, 0xe38f, 0x1c70, 0xe38e, 0x71e4, 0xb3ff, 0xfffc,
0x0015, 0x4323, 0x39d8, 0xe38e, 0x1c71, 0xc79c, 0xe304, 0xabff, 0xfffc,
0x0015, 0x0933, 0x39c1, 0xe38e, 0x3ce1, 0xc71c, 0xe33b, 0xabff, 0xfff8,
0x000f, 0x2933, 0x39c6, 0xc79e, 0x38e3, 0x8f39, 0xc636, 0x6bff, 0xfff8,
0x000a, 0xa933, 0x39c6, 0x3b1c, 0x39c3, 0x8e39, 0xc676, 0x97ff, 0xfff0,
0x000a, 0xa993, 0x39c6, 0x383c, 0x79c7, 0x0e73, 0x8c6c, 0xafff, 0xfff0,
0x0007, 0x9591, 0x39ce, 0x30d8, 0x73c7, 0x1c73, 0x8ccd, 0x2fff, 0xffe0,
0x0005, 0x5491, 0xb9cc, 0x71c4, 0xf386, 0x1ce7, 0x19db, 0x5fff, 0xffe0,
0x0005, 0x5491, 0x99cc, 0x7187, 0x678e, 0x38e7, 0x1992, 0x9fff, 0xffe0,
0x0002, 0xd491, 0x998c, 0x718e, 0x1b0c, 0x39ce, 0x33b4, 0xbfff, 0xffc0,
0x0001, 0x2a99, 0x998c, 0x638e, 0x389c, 0x71ce, 0x3325, 0x7fff, 0xffc0,
0x0000, 0x9249, 0x998c, 0x631c, 0x31f8, 0x739c, 0x6669, 0x7fff, 0xff80,
0x0000, 0x4849, 0x998c, 0xe31c, 0x71c4, 0xe39c, 0x665a, 0xffff, 0xff80,
0x0000, 0x26b9, 0x998c, 0xe718, 0x63cf, 0x0738, 0xccd4, 0xffff, 0xff00,
0x0000, 0x095f, 0x999c, 0xc638, 0xe38e, 0x3f38, 0xd8b5, 0xffff, 0xff00,
0x0000, 0x065b, 0x1998, 0xc630, 0xc71c, 0x71b1, 0x9969, 0xffff, 0xfe00,
0x0000, 0x032f, 0x6198, 0xce71, 0xc73c, 0xe301, 0xb153, 0xffff, 0xfe00,
0x0000, 0x01d5, 0xa619, 0xcc61, 0x8e38, 0xc61c, 0x32d7, 0xffff, 0xfc00,
0x0000, 0x02e7, 0xb279, 0x8c63, 0x9c71, 0xcc39, 0x82a7, 0xffff, 0xf800,
0x0000, 0x0112, 0xd367, 0x9cc3, 0x1ce3, 0x9873, 0x3baf, 0xffff, 0xe000,
0x0000, 0x0085, 0x5b26, 0x78c7, 0x39e7, 0x30e6, 0x748f, 0xffff, 0xc000,
0x0000, 0x004b, 0xe926, 0x6186, 0x39ce, 0x619d, 0xe96f, 0xffff, 0x8000,
0x0000, 0x001c, 0xad26, 0x664e, 0x739c, 0x6333, 0xa6df, 0xffff, 0x0000,
0x0000, 0x000e, 0xd5a6, 0xcefc, 0x6718, 0xc667, 0x4b7f, 0xfffe, 0x0000,
0x0000, 0x0004, 0xd4b6, 0xcce3, 0xe739, 0x8cce, 0xb6ff, 0xfff8, 0x0000,
0x0000, 0x000d, 0x2ab4, 0xcdc6, 0x3e73, 0x19bd, 0x6bff, 0xfff0, 0x0000,
0x0000, 0x0003, 0x6a94, 0xd9cc, 0x63e6, 0x3374, 0xb7ff, 0xffe0, 0x0000,
0x0000, 0x0000, 0xd954, 0xdb98, 0xc60c, 0x4eeb, 0x5fff, 0xffc0, 0x0000,
0x0000, 0x0000, 0x36d5, 0xd331, 0x1860, 0x99d6, 0x7fff, 0xff00, 0x0000,
0x0000, 0x0000, 0x0d85, 0x9662, 0x31ce, 0xf7ba, 0xffff, 0xfe00, 0x0000,
0x0000, 0x0000, 0x0313, 0xa6cc, 0x473b, 0x1eb3, 0xffff, 0xf800, 0x0000,
0x0000, 0x0000, 0x00c1, 0x4d99, 0x9cec, 0x42e7, 0xffff, 0xe000, 0x0000,
0x0000, 0x0000, 0x0030, 0x7722, 0x7362, 0x087f, 0xffff, 0x8000, 0x0000,
0x0000, 0x0000, 0x000c, 0xa185, 0xcb90, 0x81ff, 0xfffc, 0x0000, 0x0000,
0x0000, 0x0000, 0x0003, 0x0fef, 0x2e49, 0x1fff, 0xfff0, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0803, 0x7281, 0xffff, 0xff80, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0038, 0x481f, 0xffff, 0xfe00, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xf100, 0x007f, 0xf800, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x00fe, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0f7b, 0xfc00, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xf7ec, 0x3ff0, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x000f, 0x7e70, 0xc4ff, 0x8000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x00f7, 0xe383, 0x0fcd, 0xa000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x057e, 0x0e1c, 0x3f8f, 0x9800, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x1a60, 0x78f0, 0xff1c, 0xde00, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x2cc3, 0xc3c1, 0xfe3c, 0xeb80, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xd187, 0xdf07, 0xfc38, 0xe7e0, 0x0000, 0x0000, 0x0000,
0x0000, 0x0001, 0x660f, 0xf01f, 0xf879, 0xe798, 0x0000, 0x0000, 0x0000,
0x0000, 0x0006, 0xcc1f, 0xe0ff, 0xf0f1, 0xe798, 0x0000, 0x0000, 0x0000,
0x0000, 0x001b, 0x187f, 0xc1ff, 0xe1f1, 0xe7cd, 0x0000, 0x0000, 0x0000,
0x0000, 0x002e, 0x30ff, 0x83c1, 0xc1e1, 0xe7cc, 0xa000, 0x0000, 0x0000,
0x0000, 0x00dc, 0xc1ff, 0x0783, 0xe3e1, 0xc7e6, 0xd000, 0x0000, 0x0000,
0x0000, 0x0171, 0x83fe, 0x0f83, 0xe3c1, 0xc3e6, 0x5800, 0x0000, 0x0000,
0x0000, 0x06e3, 0x07fc, 0x1f07, 0xc0c3, 0xc3f3, 0x2c00, 0x0000, 0x0000,
0x0000, 0x0bc6, 0x0ffc, 0x3e0f, 0xc1f3, 0xc3f3, 0x3500, 0x0000, 0x0000,
0x0000, 0x1198, 0x3ff8, 0x3c0f, 0x81ff, 0xc3f1, 0x9a80, 0x0000, 0x0000,
0x0000, 0x13e0, 0x7ff0, 0x7c1f, 0x83ff, 0x03f9, 0xcd40, 0x0000, 0x0000,
0x0000, 0x23c3, 0xffe0, 0xf83f, 0x03fe, 0x0ff8, 0xc5a0, 0x0000, 0x0000,
0x0000, 0x27c7, 0x9fc1, 0xf03f, 0x07fe, 0x0f3c, 0xe6c0, 0x0000, 0x0000,
0x0000, 0x4f87, 0x0783, 0xe07e, 0x07fe, 0x0f0c, 0x6360, 0x0000, 0x0000,
0x0000, 0x8f0f, 0x07c7, 0xe07e, 0x0ffe, 0x1f0f, 0x71b0, 0x0000, 0x0000,
0x0000, 0x9f1e, 0x0f8f, 0xc0fc, 0x0ffc, 0x1f0f, 0x0198, 0x0000, 0x0000,
0x0001, 0x1e1e, 0x0f83, 0xc1fc, 0x1ffc, 0x1f0f, 0x0fda, 0x0000, 0x0000,
0x0001, 0x3e3c, 0x1f03, 0xf1f8, 0x1ffc, 0x1f0f, 0x0fcd, 0x0000, 0x0000,
0x0002, 0x7c3c, 0x1f07, 0xfff8, 0x3ffc, 0x1f0f, 0x0fcc, 0x8000, 0x0000,
0x0002, 0x7878, 0x3e07, 0xffb0, 0x3ff8, 0x1f0f, 0x0fcc, 0x8000, 0x0000,
0x0004, 0xf8f8, 0x3e0f, 0xff82, 0x7ff8, 0x1e0f, 0x07e6, 0x8000, 0x0000,
0x0009, 0xf0f0, 0x7c0f, 0xff03, 0xfff8, 0x1e0f, 0x07e6, 0x4000, 0x0000,
0x0009, 0xe1f0, 0x7c1f, 0xff07, 0xf7f8, 0x3e0f, 0x07e6, 0x4000, 0x0000,
0x0013, 0xe3e0, 0xf81f, 0xfe07, 0xf1f0, 0x3e0f, 0x87e7, 0x4000, 0x0000,
0x0013, 0xc3e0, 0xf83f, 0xfe0f, 0xe070, 0x3e0f, 0x87f3, 0x2000, 0x0000,
0x002f, 0xc7c1, 0xf03f, 0xfe0f, 0xe07e, 0x3e0f, 0x87f3, 0x2000, 0x0000,
0x002c, 0x87c1, 0xf07f, 0xfc0f, 0xc0fe, 0x3e0f, 0x87f3, 0xa800, 0x0000,
0x002c, 0xef83, 0xe07f, 0xfc1f, 0xc0fc, 0x0e0f, 0x87f1, 0x9000, 0x0000,
0x002c, 0xe383, 0xe0ff, 0xf81f, 0xc0fc, 0x0f0f, 0x83f9, 0x9000, 0x0000,
0x0028, 0xe3e7, 0xc0ff, 0xf83f, 0x80fc, 0x1fff, 0x83f9, 0xd400, 0x0000,
0x0059, 0xe3ff, 0xc1ff, 0xf03f, 0x81fc, 0x1fff, 0x83f8, 0xcc00, 0x0000,
0x0059, 0xc3fe, 0x01ff, 0xf03f, 0x01f8, 0x1ffe, 0x13f8, 0xc800, 0x0000,
0x0059, 0xc7fe, 0x03ff, 0xf07f, 0x01f8, 0x1ffe, 0x1ffc, 0xea00, 0x0000,
0x0059, 0xc7fe, 0x0fff, 0xe07f, 0x03f8, 0x3ffc, 0x1f3c, 0xe600, 0x0000,
0x0059, 0xc7fc, 0x0f87, 0xe07e, 0x03f0, 0x3ffc, 0x1f0c, 0x6500, 0x0000,
0x0051, 0xc7fc, 0x1f81, 0xc0fe, 0x03f0, 0x3ffc, 0x3f0e, 0x7500, 0x0000,
0x0053, 0xc7fc, 0x1f81, 0xc0fe, 0x07f0, 0x7ffc, 0x3e0e, 0x3200, 0x0000,
0x0053, 0x87fc, 0x1f03, 0xf1fc, 0x07f0, 0x7ff8, 0x3e1e, 0x3e80, 0x0000,
0x0053, 0x8ff8, 0x1f03, 0xf0fc, 0x07e0, 0x7ff8, 0x3e1e, 0x3e00, 0x0000,
0x0093, 0x8ff8, 0x3f03, 0xe038, 0x07e0, 0x7ff8, 0x3e1e, 0x3e00, 0x0000,
0x00b3, 0x8ff8, 0x3f03, 0xe03f, 0xcfe0, 0xfff8, 0x3c1c, 0x3e00, 0x0000,
0x00a3, 0x8ff8, 0x3e07, 0xe07f, 0xffe0, 0xfff8, 0x7c1c, 0x7c00, 0x0000,
0x00a7, 0x8ff8, 0x3e07, 0xe07f, 0xfec0, 0xfff0, 0x7c1c, 0x7d00, 0x0000,
0x00a7, 0x0ff0, 0x3e07, 0xc07f, 0xfe00, 0xfff0, 0x7c3c, 0x7c00, 0x0000,
0x00b7, 0x1ff0, 0x7e0f, 0xc07f, 0xfc01, 0xfff0, 0x7c3c, 0x7c00, 0x0000,
0x00ff, 0x1ff0, 0x7e0f, 0xc0ff, 0xfc07, 0xfff0, 0x783c, 0x7c00, 0x0000,
0x005e, 0x1ff0, 0x7c0f, 0x80ff, 0xf80f, 0xdfe0, 0x783c, 0x7c00, 0x0000,
0x005f, 0x3fe0, 0x7c0f, 0x80ff, 0xf80f, 0xc0e0, 0xf83c, 0x7800, 0x0000,
0x003f, 0x3860, 0xfc1f, 0x81ff, 0xf81f, 0x80e0, 0xf83c, 0x7800, 0x0000,
0x002f, 0x1870, 0xfc1f, 0x81ff, 0xf01f, 0x81f8, 0xf07c, 0x7800, 0x0000,
0x002f, 0x1c7c, 0xf81f, 0x01ff, 0xf03f, 0x01f8, 0x3078, 0xf800, 0x0000,
0x001f, 0x9c3c, 0x381f, 0x03ff, 0xe03f, 0x03f0, 0x7878, 0xf800, 0x0000,
0x0017, 0x9c3c, 0x3f3f, 0x03ff, 0xe07f, 0x03f0, 0x7ff8, 0xf800, 0x0000,
0x001f, 0x8c3c, 0x3fff, 0x03ff, 0xe07e, 0x07e0, 0xfff8, 0xf000, 0x0000,
0x001f, 0xce3c, 0x3ffe, 0x03ff, 0xc0fe, 0x07e0, 0xffc3, 0xf000, 0x0000,
0x000b, 0xce3c, 0x3ff8, 0x07ff, 0xc0fc, 0x0fc1, 0xffc7, 0xb000, 0x0000,
0x000f, 0xce3c, 0x3ff8, 0x3fff, 0xc1fc, 0x0fc1, 0xff87, 0x1800, 0x0000,
0x000f, 0xce1c, 0x3ff8, 0x3fff, 0x81f8, 0x0f83, 0xff8f, 0x3000, 0x0000,
0x0005, 0xe61e, 0x3ff0, 0x3f1f, 0x83f8, 0x1f83, 0xff0e, 0x3000, 0x0000,
0x0007, 0xe71e, 0x3ff0, 0x7e07, 0x03f8, 0x1f07, 0xfe1c, 0x6000, 0x0000,
0x0007, 0xe71e, 0x1ff0, 0x7e07, 0x87f0, 0x3f07, 0xfe1c, 0xe000, 0x0000,
0x0003, 0xe71e, 0x1ff0, 0x7e0f, 0xe3f0, 0x3e0f, 0xfc38, 0xc000, 0x0000,
0x0002, 0xf31e, 0x1ff0, 0x7c0f, 0xc0e0, 0x7e0f, 0xfc39, 0x8000, 0x0000,
0x0001, 0x5b8e, 0x1ff0, 0x7c1f, 0xc1e0, 0x7c1f, 0xf871, 0x8000, 0x0000,
0x0000, 0xad8e, 0x1ff0, 0xfc1f, 0x81fc, 0xfc1f, 0xf863, 0x0000, 0x0000,
0x0000, 0x54fe, 0x1ff0, 0xf81f, 0x83ff, 0xf83f, 0xf0e7, 0x0000, 0x0000,
0x0000, 0x2278, 0x1fe0, 0xf83f, 0x03ff, 0xc03f, 0xe0c6, 0x0000, 0x0000,
0x0000, 0x137c, 0x1fe0, 0xf83f, 0x07ff, 0x81ff, 0xe18e, 0x0000, 0x0000,
0x0000, 0x09bc, 0x7fe0, 0xf07e, 0x07ff, 0x03ff, 0xc19c, 0x0000, 0x0000,
0x0000, 0x049e, 0x3861, 0xf07e, 0x0fff, 0x07e0, 0xc318, 0x0000, 0x0000,
0x0000, 0x054e, 0x3c61, 0xf07c, 0x1ffe, 0x0fc1, 0xe338, 0x0000, 0x0000,
0x0000, 0x02a7, 0x1c79, 0xe0fc, 0x1ffc, 0x1f83, 0xc230, 0x0000, 0x0000,
0x0000, 0x0157, 0x9c38, 0x60f8, 0x3ff8, 0x3f07, 0x87f0, 0x0000, 0x0000,
0x0000, 0x00a3, 0x8e38, 0x79f8, 0x3ff0, 0x7e1e, 0x0f80, 0x0000, 0x0000,
0x0000, 0x0049, 0xce38, 0x7fb0, 0x7fe0, 0x7c3c, 0x3f00, 0x0000, 0x0000,
0x0000, 0x0024, 0xe638, 0xff00, 0x7fe0, 0xf878, 0x7c00, 0x0000, 0x0000,
0x0000, 0x0012, 0xe738, 0xff03, 0xffc1, 0xf0f0, 0xf800, 0x0000, 0x0000,
0x0000, 0x000c, 0x7338, 0xfe07, 0xcf83, 0xe1c1, 0xf000, 0x0000, 0x0000,
0x0000, 0x0003, 0x7318, 0xfe0f, 0x8307, 0xc387, 0xc000, 0x0000, 0x0000,
0x0000, 0x0000, 0xdd98, 0xfc1f, 0x07cf, 0x8f0f, 0x8000, 0x0000, 0x0000,
0x0000, 0x0000, 0x3799, 0xfc3e, 0x1f87, 0x1e1f, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0db9, 0xf87c, 0x3e0f, 0xf83c, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x033b, 0xf8f0, 0x783f, 0xe0f8, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x00cd, 0x91e1, 0xe0ff, 0x83f0, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0032, 0xbbc3, 0x83fc, 0x0c40, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x000c, 0xb1c6, 0x0fe0, 0xe100, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0003, 0x4ff0, 0x3f8e, 0x1000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0802, 0xfcf1, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0038, 0x6f90, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xfd00, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x00ec, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0fbc, 0xf800, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xf9f0, 0x3ff0, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x000f, 0x8f80, 0xfb1f, 0x8000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x00f8, 0xfc03, 0xf1ce, 0xa000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0687, 0xf01f, 0xc3f1, 0xd800, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x1c7f, 0x80ff, 0x07e0, 0xea00, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x30fc, 0x03fe, 0x1fc0, 0xf2c0, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xe1f8, 0x5ff8, 0x3fc0, 0xf9b0, 0x0000, 0x0000, 0x0000,
0x0000, 0x0001, 0x87f0, 0xffe0, 0x7f81, 0xf9ec, 0x0000, 0x0000, 0x0000,
0x0000, 0x0007, 0x0fe1, 0xff00, 0xff01, 0xf8e3, 0x0000, 0x0000, 0x0000,
0x0000, 0x001c, 0x1f83, 0xfe03, 0xfe01, 0xf8f1, 0xc000, 0x0000, 0x0000,
0x0000, 0x0030, 0x3f0f, 0xfc01, 0xfe01, 0xf8f0, 0xf000, 0x0000, 0x0000,
0x0000, 0x00e0, 0xfe1f, 0xf803, 0xfc01, 0xf8f8, 0xf800, 0x0000, 0x0000,
0x0000, 0x0181, 0xfc3f, 0xf003, 0xfc01, 0xfc78, 0x6c00, 0x0000, 0x0000,
0x0000, 0x0703, 0xf87f, 0xe007, 0xff03, 0xfc7c, 0x3600, 0x0000, 0x0000,
0x0000, 0x0c07, 0xf0ff, 0xc00f, 0xfe03, 0xfc7c, 0x3a00, 0x0000, 0x0000,
0x0000, 0x1e1f, 0xc1ff, 0xc00f, 0xfe0f, 0xfc7e, 0x1d00, 0x0000, 0x0000,
0x0000, 0x1cff, 0x87ff, 0x801f, 0xfc1f, 0xfc3e, 0x0e80, 0x0000, 0x0000,
0x0000, 0x3cfc, 0x0fff, 0x003f, 0xfc1f, 0xf03f, 0x0640, 0x0000, 0x0000,
0x0000, 0x39f8, 0x1ffe, 0x003f, 0xf81f, 0xf03f, 0x0760, 0x0000, 0x0000,
0x0000, 0x71f8, 0x07fc, 0x007f, 0xf83f, 0xf00f, 0x83b0, 0x0000, 0x0000,
0x0000, 0xf3f0, 0x07f8, 0x007f, 0xf03f, 0xe00f, 0x81d8, 0x0000, 0x0000,
0x0000, 0xe7e0, 0x0ff0, 0x00ff, 0xf03f, 0xe00f, 0xf1ec, 0x0000, 0x0000,
0x0001, 0xe7e0, 0x0ffc, 0x01ff, 0xe07f, 0xe00f, 0xf1e4, 0x0000, 0x0000,
0x0001, 0xcfc0, 0x1ffc, 0x01ff, 0xe07f, 0xe00f, 0xf1f2, 0x0000, 0x0000,
0x0003, 0x8fc0, 0x1ff8, 0x0fff, 0xc07f, 0xe00f, 0xf1f1, 0x0000, 0x0000,
0x0003, 0x9f80, 0x3ff8, 0x1fff, 0xc0ff, 0xe00f, 0xf0f0, 0xc000, 0x0000,
0x0007, 0x1f00, 0x3ff0, 0x1ffd, 0x80ff, 0xe00f, 0xf8f8, 0xc000, 0x0000,
0x000e, 0x3f00, 0x7ff0, 0x3ffc, 0x00ff, 0xe00f, 0xf8f8, 0x6000, 0x0000,
0x000e, 0x7e00, 0x7fe0, 0x3ff8, 0x01ff, 0xc00f, 0xf8f8, 0x6000, 0x0000,
0x001c, 0x7c00, 0xffe0, 0x7ff8, 0x01ff, 0xc00f, 0xf8f8, 0x6000, 0x0000,
0x001c, 0xfc00, 0xffc0, 0x7ff0, 0x007f, 0xc00f, 0xf8fc, 0x3000, 0x0000,
0x0030, 0xf801, 0xffc0, 0xfff0, 0x007f, 0xc00f, 0xf87c, 0x3000, 0x0000,
0x0030, 0xf801, 0xff80, 0xfff0, 0x00ff, 0xc00f, 0xf87c, 0x3000, 0x0000,
0x0030, 0xf003, 0xff81, 0xffe0, 0x00ff, 0xf00f, 0xf87e, 0x1800, 0x0000,
0x0030, 0xfc03, 0xff01, 0xffe0, 0x00ff, 0xf00f, 0xfc7e, 0x1800, 0x0000,
0x0030, 0xfc27, 0xff03, 0xffc0, 0x00ff, 0xe03f, 0xfc7e, 0x1800, 0x0000,
0x0061, 0xfc3f, 0xfe03, 0xffc0, 0x01ff, 0xe03f, 0xfc7f, 0x0800, 0x0000,
0x0061, 0xfc3f, 0xfe07, 0xffc0, 0x01ff, 0xe07f, 0xec3f, 0x0c00, 0x0000,
0x0061, 0xf83f, 0xfc07, 0xff80, 0x01ff, 0xe07f, 0xe03f, 0x0c00, 0x0000,
0x0061, 0xf87f, 0xf00f, 0xff80, 0x03ff, 0xc07f, 0xe03f, 0x0400, 0x0000,
0x0061, 0xf87f, 0xf007, 0xff80, 0x03ff, 0xc07f, 0xe00f, 0x8600, 0x0000,
0x0061, 0xf87f, 0xe001, 0xff00, 0x03ff, 0xc0ff, 0xc00f, 0x8600, 0x0000,
0x0063, 0xf87f, 0xe001, 0xff00, 0x07ff, 0x80ff, 0xc00f, 0xc300, 0x0000,
0x0063, 0xf87f, 0xe003, 0xfe00, 0x07ff, 0x80ff, 0xc01f, 0xc700, 0x0000,
0x0063, 0xf07f, 0xe003, 0xff00, 0x07ff, 0x81ff, 0xc01f, 0xc700, 0x0000,
0x00e3, 0xf0ff, 0xc003, 0xffc0, 0x07ff, 0x81ff, 0xc01f, 0xc700, 0x0000,
0x00c3, 0xf0ff, 0xc003, 0xffc0, 0x4fff, 0x01ff, 0xc01f, 0xcf00, 0x0000,
0x00c3, 0xf0ff, 0xc007, 0xff80, 0x7fff, 0x01ff, 0x801f, 0x8f00, 0x0000,
0x00c7, 0xf0ff, 0xc007, 0xff80, 0xffff, 0x03ff, 0x801f, 0x8e00, 0x0000,
0x00c7, 0xf0ff, 0xc007, 0xff80, 0xffff, 0x03ff, 0x803f, 0x8e00, 0x0000,
0x00c7, 0xe0ff, 0x800f, 0xff81, 0xfffe, 0x03ff, 0x803f, 0x8e00, 0x0000,
0x00cf, 0xe1ff, 0x800f, 0xff01, 0xfff8, 0x03ff, 0x803f, 0x8e00, 0x0000,
0x0067, 0xe1ff, 0x800f, 0xff01, 0xfff0, 0x07ff, 0x803f, 0x9e00, 0x0000,
0x0067, 0xc1ff, 0x800f, 0xff03, 0xfff0, 0x00ff, 0x003f, 0x9e00, 0x0000,
0x0027, 0xc07f, 0x001f, 0xfe03, 0xffe0, 0x00ff, 0x003f, 0x9e00, 0x0000,
0x0033, 0xe07f, 0x001f, 0xfe07, 0xffe0, 0x01ff, 0x007f, 0x9e00, 0x0000,
0x0033, 0xe07f, 0x001f, 0xfe07, 0xffc0, 0x01ff, 0xc07f, 0x1e00, 0x0000,
0x0013, 0xe03f, 0xc01f, 0xfc07, 0xffc0, 0x03ff, 0x807f, 0x1e00, 0x0000,
0x0019, 0xe03f, 0xc13f, 0xfc0f, 0xff80, 0x03ff, 0x81ff, 0x3c00, 0x0000,
0x0019, 0xf03f, 0xc1ff, 0xfc0f, 0xff80, 0x07ff, 0x03ff, 0x3c00, 0x0000,
0x0019, 0xf03f, 0xc1ff, 0xfc0f, 0xff00, 0x07ff, 0x03fc, 0x3c00, 0x0000,
0x000d, 0xf03f, 0xc1ff, 0xf81f, 0xff00, 0x0ffe, 0x07f8, 0x3c00, 0x0000,
0x000c, 0xf03f, 0xc1ff, 0xc01f, 0xfe00, 0x0ffe, 0x07f8, 0x1c00, 0x0000,
0x000c, 0xf01f, 0xc1ff, 0xc03f, 0xfe00, 0x0ffc, 0x0ff0, 0x3800, 0x0000,
0x0006, 0xf81f, 0xc1ff, 0xc01f, 0xfc00, 0x1ffc, 0x0ff0, 0x3800, 0x0000,
0x0006, 0x781f, 0xc1ff, 0x8007, 0xfc00, 0x1ff8, 0x1fe0, 0x7000, 0x0000,
0x0006, 0x781f, 0xe1ff, 0x8007, 0xf800, 0x3ff8, 0x1fe0, 0xf000, 0x0000,
0x0003, 0x781f, 0xe1ff, 0x800f, 0xfc00, 0x3ff0, 0x3fc0, 0xe000, 0x0000,
0x0003, 0x3c1f, 0xe1ff, 0x800f, 0xff00, 0x7ff0, 0x3fc1, 0xc000, 0x0000,
0x0001, 0x9c0f, 0xe1ff, 0x801f, 0xfe00, 0x7fe0, 0x7f81, 0xc000, 0x0000,
0x0000, 0xce0f, 0xe1ff, 0x001f, 0xfe04, 0xffe0, 0x7f83, 0x8000, 0x0000,
0x0000, 0x673f, 0xe1ff, 0x001f, 0xfc0f, 0xffc0, 0xff07, 0x8000, 0x0000,
0x0000, 0x339f, 0xe1ff, 0x003f, 0xfc0f, 0xffc0, 0xff07, 0x0000, 0x0000,
0x0000, 0x1b9f, 0xe1ff, 0x003f, 0xf81f, 0xfe01, 0xfe0f, 0x0000, 0x0000,
0x0000, 0x0dcf, 0x81ff, 0x007f, 0xf83f, 0xfc01, 0xfe1e, 0x0000, 0x0000,
0x0000, 0x06e7, 0xc07e, 0x007f, 0xf03f, 0xf800, 0xfc1c, 0x0000, 0x0000,
0x0000, 0x0677, 0xc07e, 0x007f, 0xe07f, 0xf001, 0xfc3c, 0x0000, 0x0000,
0x0000, 0x033b, 0xe07e, 0x00ff, 0xe0ff, 0xe003, 0xfc38, 0x0000, 0x0000,
0x0000, 0x0199, 0xe03f, 0x80ff, 0xc1ff, 0xc007, 0xf8f8, 0x0000, 0x0000,
0x0000, 0x00cd, 0xf03f, 0x81ff, 0xc1ff, 0x801f, 0xf1f0, 0x0000, 0x0000,
0x0000, 0x006e, 0xf03f, 0x87ff, 0x83ff, 0x803f, 0xc7e0, 0x0000, 0x0000,
0x0000, 0x0037, 0xf83f, 0x0fff, 0x87ff, 0x007f, 0x8f80, 0x0000, 0x0000,
0x0000, 0x001b, 0x783f, 0x0ffc, 0x07fe, 0x00ff, 0x3f00, 0x0000, 0x0000,
0x0000, 0x000f, 0xbc3f, 0x0ff8, 0x0ffc, 0x01fe, 0x7c00, 0x0000, 0x0000,
0x0000, 0x0003, 0xbc1f, 0x1ff0, 0x03f8, 0x03f8, 0xf800, 0x0000, 0x0000,
0x0000, 0x0000, 0xee1f, 0x1fe0, 0x07f0, 0x0ff3, 0xe000, 0x0000, 0x0000,
0x0000, 0x0000, 0x3b1e, 0x1fc0, 0x1ff8, 0x1fe7, 0x8000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0ede, 0x1f80, 0x3ff0, 0xffdf, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x03ac, 0x3f00, 0x7fc3, 0xff3c, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x00ee, 0x1e01, 0xff0f, 0xfcf8, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0039, 0x3c03, 0xfc7f, 0xf060, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x000e, 0x3e07, 0xf3ff, 0x0100, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0003, 0x77ff, 0xcff0, 0x1000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x09fc, 0x7f01, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0008, 0x7010, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0500, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x000f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x003f, 0xfc00, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x01ff, 0xc7f0, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0fff, 0x030f, 0x8000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfffc, 0x01f0, 0xe000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0707, 0xffe0, 0x03f9, 0xe800, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x1f9f, 0xff00, 0x07ff, 0xf200, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x3f03, 0xfc00, 0x1fff, 0x0c80, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xfe00, 0x6000, 0x3fff, 0x0020, 0x0000, 0x0000, 0x0000,
0x0000, 0x0001, 0xf800, 0xfc00, 0x7ffe, 0x01c8, 0x0000, 0x0000, 0x0000,
0x0000, 0x0007, 0xf001, 0xff80, 0xfffe, 0x00fe, 0x0000, 0x0000, 0x0000,
0x0000, 0x001f, 0xe003, 0xffe3, 0xfffe, 0x00fe, 0x0000, 0x0000, 0x0000,
0x0000, 0x003f, 0xc00f, 0xffff, 0xfffe, 0x00ff, 0x3000, 0x0000, 0x0000,
0x0000, 0x00ff, 0x001f, 0xfffc, 0x1ffe, 0x00ff, 0x1800, 0x0000, 0x0000,
0x0000, 0x01fe, 0x003f, 0xfffc, 0x03fe, 0x007f, 0x8c00, 0x0000, 0x0000,
0x0000, 0x07fc, 0x007f, 0xfff8, 0x003c, 0x007f, 0xc600, 0x0000, 0x0000,
0x0000, 0x03f8, 0x00ff, 0xfff0, 0x000c, 0x007f, 0xc300, 0x0000, 0x0000,
0x0000, 0x0060, 0x01ff, 0xfff0, 0x000f, 0x007f, 0xe180, 0x0000, 0x0000,
0x0000, 0x00f0, 0x07ff, 0xffe0, 0x001f, 0xf03f, 0xf0c0, 0x0000, 0x0000,
0x0000, 0x00ff, 0x0fff, 0xffc0, 0x001f, 0xfc3f, 0xf860, 0x0000, 0x0000,
0x0000, 0x01ff, 0xffff, 0xffc0, 0x001f, 0xffff, 0xf860, 0x0000, 0x0000,
0x0000, 0x01ff, 0xfbff, 0xff80, 0x003f, 0xfff3, 0xfc30, 0x0000, 0x0000,
0x0000, 0x03ff, 0xf83f, 0xff80, 0x003f, 0xfff0, 0xfe18, 0x0000, 0x0000,
0x0000, 0x07ff, 0xf00f, 0xff00, 0x003f, 0xfff0, 0x0e0c, 0x0000, 0x0000,
0x0000, 0x07ff, 0xf000, 0x3e00, 0x007f, 0xfff0, 0x0106, 0x0000, 0x0000,
0x0000, 0x0fff, 0xe000, 0x0e00, 0x007f, 0xfff0, 0x01e3, 0x0000, 0x0000,
0x0000, 0x0fff, 0xe000, 0x0e00, 0x007f, 0xfff0, 0x01ff, 0x8000, 0x0000,
0x0000, 0x1fff, 0xc000, 0x1fc0, 0x00ff, 0xfff0, 0x00ff, 0x0000, 0x0000,
0x0000, 0x1fff, 0xc000, 0x1ffe, 0x00ff, 0xfff0, 0x00ff, 0x0000, 0x0000,
0x0000, 0x3fff, 0x8000, 0x3fff, 0xc0ff, 0xfff0, 0x00ff, 0x8000, 0x0000,
0x0000, 0x7fff, 0x8000, 0x3fff, 0xf9ff, 0xfff0, 0x00ff, 0x8000, 0x0000,
0x0000, 0x7fff, 0x0000, 0x7fff, 0xffff, 0xfff0, 0x00ff, 0x8000, 0x0000,
0x0000, 0xffff, 0x0000, 0x7fff, 0xffbf, 0xfff0, 0x00ff, 0xc000, 0x0000,
0x003c, 0xfffe, 0x0000, 0xffff, 0xff80, 0xfff0, 0x007f, 0xc000, 0x0000,
0x003f, 0x7ffe, 0x0000, 0xffff, 0xff00, 0x3ff0, 0x007f, 0xc000, 0x0000,
0x003f, 0x0ffc, 0x0001, 0xffff, 0xff00, 0x07f0, 0x007f, 0xe000, 0x0000,
0x003f, 0x03fc, 0x0001, 0xffff, 0xff00, 0x00f0, 0x007f, 0xe000, 0x0000,
0x003f, 0x0038, 0x0003, 0xffff, 0xff00, 0x0038, 0x007f, 0xe000, 0x0000,
0x007e, 0x0038, 0x0003, 0xffff, 0xfe00, 0x003e, 0x007f, 0xf000, 0x0000,
0x007e, 0x003f, 0xc007, 0xffff, 0xfe00, 0x007f, 0xf03f, 0xf000, 0x0000,
0x007e, 0x003f, 0xf007, 0xffff, 0xfe00, 0x007f, 0xfc3f, 0xf000, 0x0000,
0x007e, 0x007f, 0xfe0f, 0xffff, 0xfc00, 0x007f, 0xffff, 0xf800, 0x0000,
0x007e, 0x007f, 0xffff, 0xffff, 0xfc00, 0x007f, 0xfff3, 0xf800, 0x0000,
0x007e, 0x007f, 0xfffe, 0xffff, 0xfc00, 0x00ff, 0xfff0, 0x7800, 0x0000,
0x007c, 0x007f, 0xfffe, 0x3fff, 0xf800, 0x00ff, 0xfff0, 0x0c00, 0x0000,
0x007c, 0x007f, 0xfffc, 0x07ff, 0xf800, 0x00ff, 0xffe0, 0x0700, 0x0000,
0x007c, 0x007f, 0xfffc, 0x00ff, 0xf800, 0x01ff, 0xffe0, 0x0780, 0x0000,
0x00fc, 0x00ff, 0xfffc, 0x001f, 0xf800, 0x01ff, 0xffe0, 0x0780, 0x0000,
0x00fc, 0x00ff, 0xfffc, 0x0000, 0x7000, 0x01ff, 0xffe0, 0x0f80, 0x0000,
0x00fc, 0x00ff, 0xfff8, 0x0000, 0x7800, 0x01ff, 0xffe0, 0x0f00, 0x0000,
0x00f8, 0x00ff, 0xfff8, 0x0000, 0xff00, 0x03ff, 0xffe0, 0x0f00, 0x0000,
0x0078, 0x00ff, 0xfff8, 0x0000, 0xffe0, 0x03ff, 0xffc0, 0x0f00, 0x0000,
0x0008, 0x00ff, 0xfff0, 0x0001, 0xfff8, 0x03ff, 0xffc0, 0x0f00, 0x0000,
0x000e, 0x01ff, 0xfff0, 0x0001, 0xffff, 0x03ff, 0xffc0, 0x0f00, 0x0000,
0x0007, 0xc1ff, 0xfff0, 0x0001, 0xffff, 0xe7ff, 0xffc0, 0x1f00, 0x0000,
0x0007, 0xf9ff, 0xfff0, 0x0003, 0xffff, 0xff7f, 0xffc0, 0x1e00, 0x0000,
0x0007, 0xffff, 0xffe0, 0x0003, 0xffff, 0xff1f, 0xffc0, 0x1e00, 0x0000,
0x0003, 0xff8f, 0xffe0, 0x0007, 0xffff, 0xfe03, 0xff80, 0x1e00, 0x0000,
0x0003, 0xff80, 0xffe0, 0x0007, 0xffff, 0xfe00, 0x3f80, 0x1e00, 0x0000,
0x0003, 0xffc0, 0x1fe0, 0x0007, 0xffff, 0xfc00, 0x0780, 0x1e00, 0x0000,
0x0001, 0xffc0, 0x01c0, 0x000f, 0xffff, 0xfc00, 0x0180, 0x3e00, 0x0000,
0x0001, 0xffc0, 0x01e0, 0x000f, 0xffff, 0xf800, 0x03e0, 0x3c00, 0x0000,
0x0001, 0xffc0, 0x01f8, 0x000f, 0xffff, 0xf800, 0x03ff, 0x3c00, 0x0000,
0x0001, 0xffc0, 0x01ff, 0x001f, 0xffff, 0xf000, 0x07ff, 0xfc00, 0x0000,
0x0000, 0xffc0, 0x01ff, 0xfc1f, 0xffff, 0xf000, 0x07ff, 0xe000, 0x0000,
0x0000, 0xffe0, 0x01ff, 0xff3f, 0xffff, 0xf000, 0x0fff, 0xc000, 0x0000,
0x0000, 0xffe0, 0x01ff, 0xffff, 0xffff, 0xe000, 0x0fff, 0xc000, 0x0000,
0x0000, 0x7fe0, 0x01ff, 0xfffb, 0xffff, 0xe000, 0x1fff, 0x8000, 0x0000,
0x0000, 0x7fe0, 0x01ff, 0xfff8, 0x7fff, 0xc000, 0x1fff, 0x0000, 0x0000,
0x0000, 0x7fe0, 0x01ff, 0xfff0, 0x03ff, 0xc000, 0x3fff, 0x0000, 0x0000,
0x0003, 0xbfe0, 0x01ff, 0xfff0, 0x007f, 0x8000, 0x3ffe, 0x0000, 0x0000,
0x0001, 0xe7f0, 0x01ff, 0xffe0, 0x001f, 0x8000, 0x7ffe, 0x0000, 0x0000,
0x0000, 0xf1f0, 0x01ff, 0xffe0, 0x0007, 0x0000, 0x7ffc, 0x0000, 0x0000,
0x0000, 0x7830, 0x01ff, 0xffe0, 0x000f, 0xe000, 0xfff8, 0x0000, 0x0000,
0x0000, 0x3c1e, 0x01ff, 0xffc0, 0x000f, 0xf800, 0xfff8, 0x0000, 0x0000,
0x0000, 0x1c1f, 0x81ff, 0xffc0, 0x001f, 0xffc1, 0xfff0, 0x0000, 0x0000,
0x0000, 0x0e0f, 0xf9ff, 0xff80, 0x003f, 0xfff1, 0xffe0, 0x0000, 0x0000,
0x0000, 0x0707, 0xffff, 0xff80, 0x003f, 0xffff, 0xffe0, 0x0000, 0x0000,
0x0000, 0x0787, 0xff9f, 0xff80, 0x007f, 0xfffe, 0x1fc0, 0x0000, 0x0000,
0x0000, 0x03c3, 0xff81, 0xff00, 0x00ff, 0xfffc, 0x01c0, 0x0000, 0x0000,
0x0000, 0x01e1, 0xffc0, 0x1f00, 0x01ff, 0xfff8, 0x00c0, 0x0000, 0x0000,
0x0000, 0x00f1, 0xffc0, 0x0600, 0x01ff, 0xffe0, 0x01f0, 0x0000, 0x0000,
0x0000, 0x0070, 0xffc0, 0x07c0, 0x03ff, 0xffc0, 0x07e0, 0x0000, 0x0000,
0x0000, 0x0038, 0xffc0, 0x0ff0, 0x07ff, 0xff80, 0x0f80, 0x0000, 0x0000,
0x0000, 0x001c, 0x7fc0, 0x0fff, 0x07ff, 0xff00, 0x3f00, 0x0000, 0x0000,
0x0000, 0x0000, 0x3fc0, 0x0fff, 0xffff, 0xfe00, 0x7c00, 0x0000, 0x0000,
0x0000, 0x0000, 0x7fe0, 0x1fff, 0xfcff, 0xfc00, 0xf800, 0x0000, 0x0000,
0x0000, 0x0000, 0x13e0, 0x1fff, 0xf83f, 0xf003, 0xe000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0460, 0x1fff, 0xe007, 0xe007, 0x8000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0110, 0x1fff, 0xc000, 0xc01f, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x004e, 0x3fff, 0x8003, 0xf03c, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0017, 0xfffe, 0x000f, 0xfff8, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0005, 0xc3fc, 0x007f, 0xff80, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0001, 0xc038, 0x03ff, 0xfe00, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x87f8, 0x0fff, 0xe000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x07ff, 0x7ffe, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0007, 0x8fe0, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
}
--local SCREEN_W = 336
--local SCREEN_H = 216
local SCREEN_W = 320
local SCREEN_H = 200
local function l(x1, y1, x2, y2, c)
raster.drawLine(x1-8, y1-8, x2-8, y2-8, c)
end
local function g(x, y)
return raster.get(x-8, y-8)
end
local function s(x, y, c)
raster.set(x-8, y-8, c)
end
local BALL_W = 144
local BALL_H = 100
local ONE_PLANE_LEN = BALL_W * BALL_H / 16
local function ball()
local color_cycle = 2
local pos = { x = 0.0, y = 0.0 }
local scroll = { x = -1, y = -1 }
local pixel_index = {}
local is_shadow = {}
local this = {}
function this.pos()
return -pos.x + 77, -pos.y
end
function this.step()
pos.x = pos.x + scroll.x
if pos.x <= -95 or pos.x >= 95 then scroll.x = -scroll.x end
local adj = scroll.y
if pos.y > -10.0 then adj = adj * 1.0
elseif pos.y > -30.0 then adj = adj * 2.0
elseif pos.y > -60.0 then adj = adj * 3.0
else adj = adj * 4.0 end
pos.y = pos.y + adj
if pos.y <= -100 or pos.y >= 0 then scroll.y = -scroll.y end
end
local function orderbits(value)
local result = 0
for i = 0, 15 do
if (value >> i) & 1 == 1 then
result = result | (1 << (15 - i))
end
end
return result
end
function this.decode()
for y = 0, BALL_H - 1 do
for x = 0, BALL_W - 1 do
local pos = y * BALL_W + x
local offset = pos // 16
local bitpos = pos % 16
local value = 0
for plane = 0, 3 do
local word = orderbits(ball_bitplanes[offset + plane * ONE_PLANE_LEN + 1])
if (word & (1 << bitpos)) ~= 0 then
value = value | (1 << plane)
end
end
if (value == 1) then
is_shadow[pos + 1] = true
pixel_index[pos + 1] = 0
else
is_shadow[pos + 1] = false
pixel_index[pos + 1] = value
end
end
end
end
function this.cycle_palette()
if scroll.x > 0 then color_cycle = color_cycle - 1
else color_cycle = color_cycle + 1 end
if color_cycle == -1 then color_cycle = 13
elseif color_cycle == 14 then color_cycle = 0 end
for i = 0, 6 do
if color_cycle + i < 14 then
color_table[color_cycle + i + 3] = 0xFFFFFF
color_table[color_cycle + i + 19] = 0xFFFFFF
else
color_table[color_cycle + i - 11] = 0xFFFFFF
color_table[color_cycle + i + 5] = 0xFFFFFF
end
end
for i = 7, 13 do
if color_cycle + i < 14 then
color_table[color_cycle + i + 3] = 0xFF0000
color_table[color_cycle + i + 19] = 0xFF0000
else
color_table[color_cycle + i - 11] = 0xFF0000
color_table[color_cycle + i + 5] = 0xFF0000
end
end
if scroll.x > -1 then
color_table[color_cycle + 3] = 0xFFDDDD
color_table[color_cycle + 19] = 0xFFDDDD
elseif color_cycle + 6 < 14 then
color_table[color_cycle + 9] = 0xFFDDDD
color_table[color_cycle + 25] = 0xFFDDDD
else
color_table[color_cycle - 5] = 0xFFDDDD
color_table[color_cycle + 11] = 0xFFDDDD
end
end
function this.draw(x, y, shadow)
for oy = 0, BALL_H - 1 do
for ox = 0, BALL_W - 1 do
local pos = oy * BALL_W + ox + 1
if shadow then
if is_shadow[pos] then
local c = g(ox+x, oy+y)
if c == 0xAAAAAA then s(ox+x, oy+y, 0x666666) end
end
else
local idx = pixel_index[pos]
if idx ~= 0 then
local c = color_table[idx + 1]
s(ox+x, oy+y, c)
end
end
end
end
end
return this
end
function draw_background()
raster.clear()
local lc = color_table[17]
local k = 20
for j = 48, 300, 16 do
l(j, 0, j, 192, lc)
l(j, 192, k, 215, lc)
k = k + 20
end
for j = 0, 200, 16 do
l(48, j, 288, j, lc)
end
l(45, 194, 291, 194, lc)
l(41, 197, 295, 197, lc)
l(37, 201, 300, 201, lc)
l(30, 207, 308, 207, lc)
l(20, 215, 319, 215, lc)
end
local b = ball()
b.decode()
raster.init(SCREEN_W/2, SCREEN_H/4, color_table[1])
local i = 0
while true do
i = i + 1
draw_background()
b.cycle_palette()
b.step()
local x, y = b.pos()
b.draw(x, y, true)
b.draw(x, y)
raster.update()
if event.pull("key_down", 0.01) then
break
end
end
raster.free()
terminal.clear()
+9
View File
@@ -0,0 +1,9 @@
COMMAND echo
USAGE [TEXT]...
DESCRIPTION Concatenates and prints text to the standard output.
ARG1 TEXT
ARG1DESCRIPTION Text to print.
EXAMPLE1 echo test
EXAMPLE2 echo Hello World!
EXAMPLE1DESCRIPTION Prints "test" to the standard output.
EXAMPLE2DESCRIPTION Prints "Hello World!" to the standard output.
+222
View File
@@ -0,0 +1,222 @@
-- TODO: make it somehow not depend on ESC s and ESC u
local profiler = require("profiler")
local PAL = {
{ fg = "\27[31m", bg = "\27[41m" },
{ fg = "\27[32m", bg = "\27[42m" },
{ fg = "\27[33m", bg = "\27[43m" },
{ fg = "\27[34m", bg = "\27[44m" },
{ fg = "\27[35m", bg = "\27[45m" },
{ fg = "\27[36m", bg = "\27[46m" },
{ fg = "\27[37m", bg = "\27[47m" }
}
local function pal(i) return PAL[((i - 1) % #PAL) + 1] end
local results = profiler.results()
if not results then
print("No profiling data")
return
end
local radius
local W = terminal.getResolution()
if (W == 160) then radius = 20
elseif (W == 80) then radius = 6
else radius = 0; PAL = {{fg = "", bg = ""}} end
local MIN_PC = math.min(3, 100 / (radius * 2))
local total = 0
for _, r in ipairs(results) do total = total + r.time end
local main = {}
local other = {}
local ot = 0
local on_ = 0
for _, r in ipairs(results) do
if r.time / total * 100 >= MIN_PC then
table.insert(main, r)
else
table.insert(other, r)
ot = ot + r.time;
on_ = on_ + 1
end
end
if on_ then
table.insert(main, { label = "other (" .. on_ .. ")", time = ot })
end
local START = -math.pi / 2
local slices = {}
local cur = START
for i, m in ipairs(main) do
local sw = m.time / total * 2 * math.pi
slices[i] = {
label = m.label,
time = m.time,
pc = ("%.1f%%"):format(m.time / total * 100),
color = pal(i),
sa = cur,
sw = sw
}
cur = cur + sw
end
if on_ then slices[#slices].color={fg = "\27[30m", bg = "\27[40m"} end
local ASP = 2
local cx = radius * ASP
local cy = radius
local function slice_at(sx, sy)
local dy = sy - cy
local dx = (sx - cx) / ASP
if dx * dx + dy * dy > radius * radius then return nil end
local a = math.atan2(dy, dx)
if a < START then a = a + 2 * math.pi end
for i, sl in ipairs(slices) do
if a >= sl.sa and a < sl.sa + sl.sw then return i end
end
return #slices
end
local SUB = {
{ dx = -0.25, dy = -0.375 },
{ dx = -0.25, dy = -0.125 },
{ dx = -0.25, dy = 0.125 },
{ dx = 0.25, dy = -0.375 },
{ dx = 0.25, dy = -0.125 },
{ dx = 0.25, dy = 0.125 },
{ dx = -0.25, dy = 0.375 },
{ dx = 0.25, dy = 0.375 },
}
for y = 0, radius * 2 do
local lx, rx = math.ceil(cx - radius * ASP), math.floor(cx + radius * ASP)
terminal.write(("\27[%dC"):format(lx))
for x = lx, rx do
local c = {}
local n = 0
for k = 1, 8 do
local s = slice_at(x + SUB[k].dx, y + SUB[k].dy)
c[k] = s
if s then n = n + 1 end
end
if n == 0 then
terminal.write("\27[0m ")
else
local counts = {}
local order = {}
for k = 1, 8 do
if c[k] then
local key = c[k]
if not counts[key] then
counts[key] = 0
table.insert(order, key)
end
counts[key] = counts[key] + 1
end
end
table.sort(order, function(a, b) return counts[a] > counts[b] end)
local dom = order[1]
local sub = order[2]
if n == 8 then
terminal.write(slices[dom].color.bg)
if sub == nil then
terminal.write(" ")
else
local mask = 0
for k = 1, 8 do
if c[k] == sub then mask = mask + (1 << (k - 1)) end
end
terminal.write(slices[sub].color.fg)
terminal.write(utf8.char(0x2800 + mask))
end
else
local mask = 0
for k = 1, 8 do
if c[k] == dom then mask = mask + (1 << (k - 1)) end
end
terminal.write("\27[0m")
terminal.write(slices[dom].color.fg)
terminal.write(utf8.char(0x2800 + mask))
end
end
end
terminal.write('\n')
end
terminal.write("\27[" .. radius * 2 + 1 .. "A\27[s")
local function draw_text(col, row, s)
terminal.write("\27[u\27[" .. col .. "C\27[" .. row - 1 .. "B" .. s)
end
terminal.write("\27[0m")
if radius == 0 then goto tier1gpu end
for _, sl in ipairs(slices) do
local y = math.floor(cy + radius * 0.62 * math.sin(sl.sa + sl.sw / 2) + 0.5)
local function in_slice(x, row)
local a = math.atan2(row - cy, (x - cx) / ASP)
if a < START then
a = a + 2 * math.pi
end
return a >= sl.sa and a < sl.sa + sl.sw
end
local function centered_draw(row, text)
local dy = row - cy
local half_w = math.sqrt(radius * radius - dy * dy) * ASP
local lx, rx = math.ceil(cx - half_w), math.floor(cx + half_w)
while lx <= rx and not in_slice(lx, row) do
lx = lx + 1
end
while rx >= lx and not in_slice(rx, row) do
rx = rx - 1
end
local avail = rx - lx + 1
if avail < 3 then
return
end
local t = #text > avail and text:sub(1, avail - 3) .. "..." or text
local start_x = lx + math.floor((avail - #t) / 2)
draw_text(start_x, row, sl.color.bg .. t)
end
centered_draw(y, sl.label)
centered_draw(y + 1, sl.pc)
end
::tier1gpu::
local max_w = 0
for _, sl in pairs(slices) do
max_w = math.max(#sl.label + 1, max_w)
end
for _, sl in pairs(other) do
max_w = math.max(#sl.label + 3, max_w)
end
local x = radius * 2 * ASP + 2
if radius == 0 then x = 0 end
local cw = W - x - 1
local suffix_w = 18
local max_lbl = math.max(4, cw - suffix_w)
terminal.write("\27[u\27[" .. x .. "C" .. ("\27[0m%" .. max_w .. "s %9s %6s"):format("label", "time", "share"))
terminal.write("\n")
for _, sl in ipairs(slices) do
local lbl = sl.label
if #lbl > max_lbl then
lbl = sl.label:sub(1, max_lbl - 1) .. "…"
end
terminal.write("\n\27[" .. x .. "C" .. ("%s%" .. max_w .. "s\27[0m %9.4fs %6s"):format(sl.color.bg, lbl, sl.time, sl.pc))
end
for _, sl in ipairs(other) do
local lbl = sl.label
if #lbl > max_lbl - 2 then
lbl = sl.label:sub(1, max_lbl - 3) .. "…"
end
terminal.write("\n\27[" .. x .. "C" .. ("%s%" .. max_w .. "s\27[0m %9.4fs %6s"):format(slices[#slices].color.bg, lbl, sl.time, ("%.1f%%"):format(sl.time / total * 100)))
end
if radius * 2 + 2 > #slices + #other then
terminal.write("\27[" .. radius * 2 + 2 .. "B")
end
terminal.write("\n")
+60
View File
@@ -0,0 +1,60 @@
-- Despite the name it's not telnet
local component = require("component")
if not component.isAvailable("internet") then
terminal.write("telnet: this program requires an internet card to run\n")
return
end
local internet = component.internet
if not internet.isTcpEnabled() then
terminal.write("telnet: TCP disabled\n")
return
end
local arg = {...}
local host = arg[1]
local port = tonumber(arg[2])
local sock = internet.connect(host, port)
local connected = false
local err
for _ = 1, 5 do
local ok
ok, err = sock.finishConnect()
if ok then
connected = true
break
end
coroutine.yield()
end
if not connected then
print("telnet: " .. err)
return
end
print(("connected to %s:%d"):format(host, port))
while true do
local fromSocket = sock.read(math.maxinteger or math.huge)
if fromSocket == nil then
print("telnet: connection closed")
sock.close()
return
end
terminal.write(fromSocket)
terminal.flush()
local fromTerminal = terminal.read()
if fromTerminal == "" then
sock.close()
return
end
while fromTerminal ~= "" do
local nbytes, err = sock.write(fromTerminal .. "\r\n")
if err then
print("telnet: " .. err)
return
end
fromTerminal = fromTerminal:sub(nbytes + 1)
end
end
+1
View File
@@ -0,0 +1 @@
{"palette":{"dark":{"0":"171421","1":"c01c28","2":"26a269","3":"a2734c","4":"12488b","5":"a347ba","6":"2aa1b3","7":"d0cfcc"},"bright":{"0":"5e5c64","1":"f66151","2":"33d17a","3":"e9ad0c","4":"2a7bde","5":"c061cb","6":"33c7de","7":"ffffff"}}}
+24
View File
@@ -0,0 +1,24 @@
{
"palette": {
"dark": {
"0": "0x0f0f0f",
"1": "0xcc2424",
"2": "0x339280",
"3": "0x996d00",
"4": "0x004980",
"5": "0x9949c0",
"6": "0x33b6c0",
"7": "0xc3c3c3"
},
"bright": {
"0": "0x666d80",
"1": "0xff6d40",
"2": "0x33db80",
"3": "0xffb600",
"4": "0x336dff",
"5": "0xcc6dc0",
"6": "0x33dbc0",
"7": "0xffffff"
}
}
}
@@ -11,6 +11,7 @@ gpu.bind(screenAddress)
gpu.setResolution(gpu.maxResolution())
local log = assert(loadfile("/lib/log.lua")(loadfile))
_G.profiler = assert(loadfile("/lib/profiler.lua")())
log.kernel.info("Bound GPU to screen " .. tostring(screenAddress))
@@ -67,10 +68,10 @@ require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modloa
log.kernel.info("Loading modules")
require("/halyde/kernel/modload.lua")
package.preload("component")
package.preload("computer")
package.preload("log")
package.preload("event")
local toPreload = { "component", "computer", "log", "event" }
for _, p in pairs(toPreload) do
profiler.profile("pre-loading " .. p, package.preload, p)
end
local computer = require("computer")
function wait(seconds)
@@ -19,8 +19,10 @@ local moduleTypes = {}
local modulesLoaded = {}
local function loadModule(modName)
local stop = profiler.start("loadModule(" .. tostring(modName) .. ")")
if table.find(modulesLoaded, modName) then
log.kernel.warn(string.format("[modload: %s] Module was already loaded - skipping", modName))
stop()
return true
end
@@ -28,6 +30,7 @@ local function loadModule(modName)
if not moduleData then
log.kernel.warn(string.format("[modload: %s] Could not find module data.", modName))
table.remove(moduleList, table.find(moduleList, modName))
stop()
return true
end
local ready = false
@@ -42,6 +45,7 @@ local function loadModule(modName)
end
if not ready then
log.kernel.info(string.format("[modload: %s] Module not ready - skipping", modName))
stop()
return false
end
if type(moduleData.dependencies) == "table" then
@@ -74,16 +78,19 @@ local function loadModule(modName)
tostring(err or "unknown error")
)
)
stop()
return false
else
table.insert(modulesLoaded, modName)
table.remove(moduleList, table.find(moduleList, modName))
end
end
stop()
return true
end
for _, modName in pairs(moduleList) do -- Get all the module types
local stop = profiler.start("getting module " .. modName .. ")")
log.kernel.info(string.format("[modload: %s] Getting data from module", modName))
local moduleData
local status, err = pcall(function()
@@ -123,6 +130,7 @@ for _, modName in pairs(moduleList) do -- Get all the module types
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
end
::continue::
stop()
end
local function loadAllModules() -- attempt at loading all modules, unless if they're not ready
+859
View File
@@ -0,0 +1,859 @@
--[[
TODO:
```bash
echo -e "\033[?25l" # hide
echo -e "\033[?25h" # show
```
]]
local module = {}
function module.check()
return true -- Usually always loaded, but maybe it would be worth it to check if the computer has a GPU or not? I'm not sure.
end
function module.init()
local serialize = require("serialize")
local unicode = require("unicode")
local event = require("event")
local fs = require("filesystem")
local json = require("json")
local component = require("component")
local gpu = component.gpu
_G._PUBLIC.terminal = {}
local readHistory = {}
function _PUBLIC.terminal.getHistory(id)
checkArg(1, id, "string")
return table.copy(readHistory[id])
end
function _PUBLIC.terminal.setHistory(id, hist)
checkArg(1, id, "string")
checkArg(2, hist, "table")
for i = 1, #hist do
hist[i] = tostring(hist[i])
end
readHistory[id] = hist
end
function _PUBLIC.terminal.addToHistory(id, hist)
checkArg(1, id, "string")
checkArg(2, hist, "string")
table.insert(readHistory[id], hist)
end
if not fs.exists("/halyde/config/terminal.json") then
fs.copy("/halyde/config/generate/terminal.json", "/halyde/config/terminal.json")
end
local config = ""
local tmpdata
local handle = fs.open("/halyde/config/terminal.json")
repeat
tmpdata = handle:read(math.huge)
config = config .. (tmpdata or "")
until not tmpdata
config = json.decode(config)
require("log").terminal.info("Loaded config file: " .. serialize(config))
local function getColorPalette(depth)
if depth == 1 then
return {
["dark"] = {
[0] = 0x000000,
[1] = 0xffffff,
[2] = 0xffffff,
[3] = 0xffffff,
[4] = 0xffffff,
[5] = 0xffffff,
[6] = 0xffffff,
[7] = 0xffffff,
},
["bright"] = {
[0] = 0x000000,
[1] = 0xffffff,
[2] = 0xffffff,
[3] = 0xffffff,
[4] = 0xffffff,
[5] = 0xffffff,
[6] = 0xffffff,
[7] = 0xffffff,
}
}
end
if depth == 4 then
return {
-- Closest colors to the 4 bit OC palette
-- Better than outright failure
["dark"] = {
[0] = 0x000000, -- black
[1] = 0x663300, -- brown (dark red)
[2] = 0x336600, -- green (dark green)
[3] = 0x336600, -- green (dark yellow)
[4] = 0x333399, -- blue (dark blue)
[5] = 0x9933CC, -- purple (dark purple)
[6] = 0x333399, -- blue (dark cyan)
[7] = 0xCCCCCC -- silver (dark white)
},
["bright"] = {
[0] = 0x333333, -- gray (bright black)
[1] = 0xff3333, -- red
[2] = 0x33cc33, -- lime (green)
[3] = 0xffff33, -- yellow
[4] = 0x333399, -- blue
[5] = 0xcc66cc, -- magenta (purple)
[6] = 0x336699, -- cyan
[7] = 0xffffff -- white
}
}
end
if depth == 8 then
local palette = {["dark"] = {}, ["bright"] = {}}
for i = 0, 7 do
palette["dark"][i] = tonumber(config.palette.dark[tostring(i)])
end
for i = 0, 7 do
palette["bright"][i] = tonumber(config.palette.bright[tostring(i)])
end
require("log").terminal.info("Set color palette: " .. serialize(palette, nil))
return palette
--[[ return {
["dark"] = {
[0] = 0x0f0f0f, -- black
[1] = 0xcc2424, -- dark red
[2] = 0x339280, -- dark green
[3] = 0x996d00, -- dark yellow
[4] = 0x004980, -- dark blue
[5] = 0x9949c0, -- dark purple
[6] = 0x33b6c0, -- dark cyan
[7] = 0xc3c3c3 -- dark white
},
["bright"] = {
[0] = 0x666d80, -- brighter black
[1] = 0xff6d40, -- red
[2] = 0x33db80, -- green
[3] = 0xffb600, -- yellow
[4] = 0x336dff, -- blue
[5] = 0xcc6dc0, -- purple
[6] = 0x33dbc0, -- cyan
[7] = 0xffffff -- white
}
} ]]
end
--[[ Original color palette:
{
["dark"] = {
[0] = 0x171421,
[1] = 0xc01c28,
[2] = 0x26a269,
[3] = 0xa2734c,
[4] = 0x12488b,
[5] = 0xa347ba,
[6] = 0x2aa1b3,
[7] = 0xd0cfcc
},
["bright"] = {
[0] = 0x5e5c64,
[1] = 0xf66151,
[2] = 0x33d17a,
[3] = 0xe9ad0c,
[4] = 0x2a7bde,
[5] = 0xc061cb,
[6] = 0x33c7de,
[7] = 0xffffff
}
}
]]
-- Shouldn't reach here
error()
end
local ANSIColorPalette = getColorPalette(gpu.maxDepth())
local cursor = { x = 1, y = 1, X = nil, Y = nil } -- X and Y are managed by ESC s and ESC u
local printState = 0 -- 0:none 1:in ESC 2:in CSI
local DEFAULT_FG = ANSIColorPalette["bright"][7]
local DEFAULT_BG = ANSIColorPalette["dark"][0]
require("log").terminal.info("FG and BG: " .. DEFAULT_FG .. " " .. DEFAULT_BG)
local fg = DEFAULT_FG
local bg = DEFAULT_BG
local gpuFg = nil
local gpuBg = nil
local reverse = false
local current_codepoint = 0
local bytes_remaining = 0
local seq = {}
local writeBuf = ""
local bufStartX = 1
local bufStartY = 1
local width, height = gpu.getResolution()
function _G._PUBLIC.terminal.getResolution()
return width, height
end
local function update_gpu_colors()
if reverse then
if gpuBg ~= fg then gpu.setBackground(fg) gpuBg = fg end
if gpuFg ~= bg then gpu.setForeground(bg) gpuFg = bg end
else
if gpuBg ~= bg then gpu.setBackground(bg) gpuBg = bg end
if gpuFg ~= fg then gpu.setForeground(fg) gpuFg = fg end
end
end
local function scroll(n)
if n <= 0 then return end
if writeBuf ~= "" then
update_gpu_colors()
gpu.set(bufStartX, bufStartY, writeBuf)
writeBuf = ""
end
local keep = height - n
if keep > 0 then
gpu.copy(1, n + 1, width, keep, 0, -n)
end
if gpuBg ~= bg then
gpu.setBackground(bg)
gpuBg = bg
end
gpu.fill(1, keep + 1, width, n, " ")
cursor.y = cursor.y - n
if cursor.y > height then cursor.y = height end
if cursor.y < 1 then cursor.y = 1 end
end
local function check_wrap_and_scroll()
if cursor.x > width then
cursor.x = 1
cursor.y = cursor.y + 1
end
scroll(cursor.y - height)
end
-- must be called before any operation that moves the cursor or changes colors!!!!!!!
local function flush()
if writeBuf == "" then return end
update_gpu_colors()
gpu.set(bufStartX, bufStartY, writeBuf)
writeBuf = ""
end
local function buf_append(s, len)
if writeBuf == "" then
bufStartX = cursor.x
bufStartY = cursor.y
end
writeBuf = writeBuf .. s
cursor.x = cursor.x + len
end
local function exec_csi()
local params = {}
local op = 0
local current_num = 0
local have_num = false
for i = 1, #seq do
local byte = seq[i]
if 0x30 <= byte and byte <= 0x39 then
current_num = current_num * 10 + (byte - 0x30)
have_num = true
elseif byte == 0x3b then
table.insert(params, have_num and current_num or 0)
current_num = 0
have_num = false
else
if have_num then
table.insert(params, current_num)
end
if 0x40 <= byte and byte <= 0x7e then
op = byte
end
break
end
end
-- TODO maybe use a lookup table like this?
-- local thing = things[op]
-- if thing ~= nil then thing() end
if op == 0x41 then
flush()
cursor.y = cursor.y - (params[1] or 1)
if cursor.y < 1 then cursor.y = 1 end
elseif op == 0x42 then
flush()
cursor.y = cursor.y + (params[1] or 1)
if cursor.y > height then cursor.y = height end
elseif op == 0x43 then
flush()
cursor.x = cursor.x + (params[1] or 1)
if cursor.x > width then cursor.x = width end
elseif op == 0x44 then
flush()
cursor.x = cursor.x - (params[1] or 1)
if cursor.x < 1 then cursor.x = 1 end
elseif op == 0x47 or op == 0x60 then
flush()
cursor.x = params[1] or 1
if cursor.x < 1 then cursor.x = 1 end
if cursor.x > width then cursor.x = width end
elseif op == 0x48 or op == 0x66 then
flush()
cursor.y = params[1] or 1
cursor.x = params[2] or 1
if cursor.x < 1 then cursor.x = 1 end
if cursor.y < 1 then cursor.y = 1 end
if cursor.x > width then cursor.x = width end
if cursor.y > height then cursor.y = height end
elseif op == 0x4a then
flush()
local mode = params[1] or 0
update_gpu_colors()
if mode == 0 then
gpu.fill(cursor.x, cursor.y, width - cursor.x + 1, 1, " ")
if cursor.y < height then
gpu.fill(1, cursor.y + 1, width, height - cursor.y, " ")
end
elseif mode == 1 then
if cursor.y > 1 then
gpu.fill(1, 1, width, cursor.y - 1, " ")
end
gpu.fill(1, cursor.y, cursor.x, 1, " ")
elseif mode == 2 then
gpu.fill(1, 1, width, height, " ")
cursor.x = 1
cursor.y = 1
end
elseif op == 0x4b then
flush()
local mode = params[1] or 0
update_gpu_colors()
if mode == 0 then
gpu.fill(cursor.x, cursor.y, width - cursor.x + 1, 1, " ")
elseif mode == 1 then
gpu.fill(1, cursor.y, cursor.x, 1, " ")
elseif mode == 2 then
gpu.fill(1, cursor.y, width, 1, " ")
end
elseif op == 0x64 then
flush()
cursor.y = params[1] or 1
if cursor.y < 1 then
cursor.y = 1
end
if cursor.y > height then
cursor.y = height
end
elseif op == 0x6d then
flush()
local j = 1
local function parse_extended_color()
local mode = params[j + 1] or -1
if mode == 5 then
local idx = params[j + 2] or 0
j = j + 2
if idx < 8 then
return ANSIColorPalette["dark"][idx]
elseif idx < 16 then
return ANSIColorPalette["bright"][idx - 8]
elseif idx < 232 then
local i = idx - 16
local b = (i % 6) * 51
local g = ((i // 6) % 6) * 51
local r = (i // 36) * 51
return (r << 16) | (g << 8) | b
else
local v = (idx - 232) * 10 + 8
return (v << 16) | (v << 8) | v
end
elseif mode == 2 then
local r = params[j + 2] or 0
local g = params[j + 3] or 0
local b = params[j + 4] or 0
j = j + 4
return (r << 16) | (g << 8) | b
end
return nil
end
if #params == 0 then
reverse = false
fg = DEFAULT_FG
bg = DEFAULT_BG
return
end
while j <= #params do
local p = params[j] or 0
if p == 0 then
reverse = false
fg = DEFAULT_FG
bg = DEFAULT_BG
--elseif p == 1 then
--elseif p == 2 then
--elseif p == 3 then
--elseif p == 4 then
--elseif p == 5 or p == 6 then
elseif p == 7 then
reverse = true
elseif p == 8 then
fg = bg
--elseif p == 9 then
--elseif p == 21 then
--elseif p == 22 then
--elseif p == 23 then
--elseif p == 24 then
--elseif p == 25 then
elseif p == 27 then
reverse = false
elseif p == 28 then
fg = DEFAULT_FG
--elseif p == 29 then
elseif 30 <= p and p <= 37 then
fg = ANSIColorPalette["dark"][p - 30]
elseif p == 38 then
local c = parse_extended_color()
if c then
fg = c
end
elseif p == 39 then
fg = DEFAULT_FG
elseif 40 <= p and p <= 47 then
bg = ANSIColorPalette["dark"][p - 40]
elseif p == 48 then
local c = parse_extended_color()
if c then
bg = c
end
elseif p == 49 then
bg = DEFAULT_BG
elseif 90 <= p and p <= 97 then
fg = ANSIColorPalette["bright"][p - 90]
elseif 100 <= p and p <= 107 then
bg = ANSIColorPalette["bright"][p - 100]
end
j = j + 1
end
elseif op == 0x73 then
flush()
cursor.X = cursor.x
cursor.Y = cursor.y
elseif op == 0x75 then
flush()
if cursor.X and cursor.Y then
cursor.x = cursor.X
cursor.y = cursor.Y
if cursor.x < 1 then
cursor.x = 1
end
if cursor.y < 1 then
cursor.y = 1
end
if cursor.x > width then
cursor.x = width
end
if cursor.y > height then
cursor.y = height
end
end
end
end
function _G._PUBLIC.terminal.write(text)
text = tostring(text)
local len = #text
local i = 1
while i <= len do
local byte = string.byte(text, i)
if byte == 0x1b then
printState = 1
seq = {}
i = i + 1
elseif printState == 1 then
printState = byte == 0x5b and 2 or 0
i = i + 1
elseif printState == 2 then
table.insert(seq, byte)
if 0x40 <= byte and byte <= 0x7e then
exec_csi()
printState = 0
seq = {}
end
i = i + 1
elseif byte == 0xa then
flush()
cursor.y = cursor.y + 1
cursor.x = 1
check_wrap_and_scroll()
bufStartX = cursor.x
bufStartY = cursor.y
i = i + 1
elseif byte == 0xd then
flush()
cursor.x = 1
bufStartX = 1
bufStartY = cursor.y
i = i + 1
elseif byte == 0x8 then
flush()
if cursor.x > 1 then cursor.x = cursor.x - 1 end
i = i + 1
elseif byte == 0x9 then
flush()
cursor.x = ((cursor.x - 1) // 8) * 8 + 9
if cursor.x > width then cursor.x = width end
i = i + 1
elseif byte >= 0x20 and byte <= 0x7E then
local j = i + 1
while j <= len do
local b = string.byte(text, j)
if b < 0x20 or b > 0x7E then break end
j = j + 1
end
local runLen = j - i
local space = width - cursor.x + 1
if runLen <= space then
buf_append(text:sub(i, j - 1), runLen)
if cursor.x > width then
flush()
cursor.x = 1
cursor.y = cursor.y + 1
check_wrap_and_scroll()
bufStartX = cursor.x
bufStartY = cursor.y
end
i = j
else
buf_append(text:sub(i, i + space - 1), space)
flush()
cursor.x = 1
cursor.y = cursor.y + 1
check_wrap_and_scroll()
bufStartX = cursor.x
bufStartY = cursor.y
i = i + space
end
elseif byte >= 0xC2 and byte <= 0xDF then
current_codepoint = (byte & 0x1F)
bytes_remaining = 1
i = i + 1
elseif byte >= 0xE0 and byte <= 0xEF then
current_codepoint = (byte & 0x0F)
bytes_remaining = 2
i = i + 1
elseif byte >= 0xF0 and byte <= 0xF7 then
current_codepoint = (byte & 0x07)
bytes_remaining = 3
i = i + 1
elseif byte >= 0x80 and byte <= 0xBF and bytes_remaining > 0 then
current_codepoint = (current_codepoint << 6) | (byte & 0x3F)
bytes_remaining = bytes_remaining - 1
if bytes_remaining == 0 then
buf_append(unicode.char(current_codepoint), 1)
if cursor.x > width then
flush()
cursor.x = 1
cursor.y = cursor.y + 1
check_wrap_and_scroll()
bufStartX = cursor.x
bufStartY = cursor.y
end
current_codepoint = 0
end
i = i + 1
else
current_codepoint = 0
bytes_remaining = 0
i = i + 1
end
end
end
function _G._PUBLIC.terminal.flush()
flush()
end
function _G._PUBLIC.terminal.clear()
flush()
update_gpu_colors()
gpu.fill(1, 1, width, height, " ")
cursor.x = 1
cursor.y = 1
end
function _G.print(...)
local args = { ... }
local stringArgs = {}
for _, arg in pairs(args) do
if type(arg)=="table" then
table.insert(stringArgs, serialize(arg))
elseif tostring(arg) then
table.insert(stringArgs, tostring(arg))
end
end
_PUBLIC.terminal.write(table.concat(stringArgs, "\t") .. "\n")
end
function _G._PUBLIC.terminal.read(options)
checkArg(1, options, "table", "nil")
local function checkOption(name, value, neededType)
assert(not value or type(value) == neededType, ("%s option must be %s, %s provided"):format(name, neededType, type(value)))
end
if not options then
options = {}
end
checkOption("readHistoryType", options.readHistoryType, "string")
checkOption("prefix", options.prefix, "string")
checkOption("maxChars", options.maxChars, "number")
checkOption("defaultText", options.defaultText, "string")
checkOption("censor", options.censor, "string")
options.maxChars = options.maxChars or math.huge
local text = options.defaultText or ""
local historyIdx
if options.readHistoryType then
if not readHistory[options.readHistoryType] then
readHistory[options.readHistoryType] = { text }
elseif readHistory[options.readHistoryType][#readHistory[options.readHistoryType]] ~= text then
table.insert(readHistory[options.readHistoryType], text)
end
historyIdx = #readHistory[options.readHistoryType]
end
local function updateHistory()
if not options.readHistoryType then return end
if historyIdx ~= #readHistory[options.readHistoryType] then return end
readHistory[options.readHistoryType][historyIdx] = text
end
local cur = unicode.len(text) + 1
if options.prefix then _PUBLIC.terminal.write(options.prefix) end
flush()
local startX, startY = cursor.x, cursor.y
local cursorBlink = true
local function checkScroll(y)
if y > height then
local n = y - height
scroll(n)
startY = startY - n
y = height
end
return y
end
local function set(index, character, invertedColors) -- HACK: Currently, this will uncensor all spaces in the inputted text.
if character == nil or character == "" then return end
if options.censor then
character = character:gsub("[^ ]", options.censor)
end
if invertedColors then
if gpuFg ~= bg then gpu.setForeground(bg); gpuFg = bg end
if gpuBg ~= fg then gpu.setBackground(fg); gpuBg = fg end
else
if gpuFg ~= fg then gpu.setForeground(fg); gpuFg = fg end
if gpuBg ~= bg then gpu.setBackground(bg); gpuBg = bg end
end
index = startX + index - 1
local setX = (index - 1) % width + 1
local setY = startY + ((index - 1) // width)
setY = checkScroll(setY)
local firstLen = width - setX + 1
gpu.set(setX, setY, unicode.sub(character, 1, firstLen))
local charLen = unicode.len(character)
if charLen > firstLen then
local offset = firstLen + 1
while offset <= charLen do
setY = setY + 1
setY = checkScroll(setY)
local segEnd = offset + width - 1
gpu.set(1, setY, unicode.sub(character, offset, segEnd))
offset = segEnd + 1
end
end
end
local function strDef(a, b)
if #a == 0 then return b end
return a
end
local function curPos(c)
return unicode.wlen(unicode.sub(text, 1, c - 1)) + 1
end
local function add(chr)
if type(chr) ~= "string" or #chr == 0 then
return
end
if unicode.len(text) >= options.maxChars then
return
end
if options.maxChars < math.huge then
chr = unicode.sub(chr, 1, options.maxChars - unicode.len(text))
end
text = unicode.sub(text, 1, cur - 1) .. chr .. unicode.sub(text, cur)
set(curPos(cur), chr, false)
cur = math.min(cur + unicode.len(chr), options.maxChars + 1)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
cursorBlink = true
set(curPos(cur + 1), unicode.sub(text, cur + 1), false)
end
local function moveCur(dir)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), false)
cur = math.max(math.min(cur + dir, unicode.len(text) + 1), 1)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
cursorBlink = true
end
local function isLetter(chr)
return not string.find("\x09 :@-./_~?&=%+#", chr, 1, true)
end
local function nextCur(dir, chr, icur)
if icur == nil then icur = cur end
local next = math.max(math.min(icur + dir, unicode.len(text) + 1), 1)
if chr then return unicode.sub(text, next, next) end
return next
end
local function curAfterWord(dir)
local ncur = cur
while nextCur(dir, false, ncur) ~= ncur and isLetter(nextCur(dir, true, ncur)) == (dir == 1) do
ncur = nextCur(dir, false, ncur)
end
while nextCur(dir, false, ncur) ~= ncur and isLetter(nextCur(dir, true, ncur)) == (dir == -1) do
ncur = nextCur(dir, false, ncur)
end
return ncur
end
local function moveWord(dir)
if nextCur(dir) == cur then return end
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), false)
cur = curAfterWord(dir)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
cursorBlink = true
end
local function deleteWord(dir)
local after = curAfterWord(dir)
local lenb = unicode.wlen(text)
if dir == 1 then
text = unicode.sub(text, 1, cur - 1) .. unicode.sub(text, after)
set(curPos(cur + 1), unicode.sub(text, cur + 1) .. string.rep(" ", lenb - unicode.wlen(text) + 1), false)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
else
text = unicode.sub(text, 1, after - 1) .. unicode.sub(text, cur)
cur = after
set(curPos(cur + 1), unicode.sub(text, cur + 1) .. string.rep(" ", lenb - unicode.wlen(text) + 1), false)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
end
updateHistory()
cursorBlink = true
end
local function isLine(chr)
return chr == "\n" or chr == "\r"
end
set(1, text, false)
set(curPos(cur), " ", true)
local function reprint(new)
set(1, new .. string.rep(" ", unicode.wlen(text) - unicode.wlen(new) + 1), false)
cur = unicode.len(new) + 1
text = new
set(curPos(cur), " ", true)
end
while true do
local args = { event.pull("key_down", "clipboard", 0.5) }
local ctrlDown = _PUBLIC.keyboard.getCtrlDown()
if args and args[1] == "key_down" and args[4] then
local key = _PUBLIC.keyboard.keys[args[4]]
if key == "up" and options.readHistoryType then
historyIdx = math.max(historyIdx - 1, 1)
reprint(readHistory[options.readHistoryType][historyIdx])
elseif key == "down" and options.readHistoryType then
historyIdx = math.min(historyIdx + 1, #readHistory[options.readHistoryType])
reprint(readHistory[options.readHistoryType][historyIdx])
elseif key == "left" and ctrlDown then
moveWord(-1)
elseif key == "right" and ctrlDown then
moveWord(1)
elseif key == "left" then
moveCur(-1)
elseif key == "right" then
moveCur(1)
elseif key == "home" then
moveCur(-math.huge)
elseif key == "end" then
moveCur(math.huge)
elseif key == "back" and ctrlDown then
deleteWord(-1)
elseif key == "delete" and ctrlDown then
deleteWord(1)
elseif key == "back" and cur > 1 then
text = unicode.sub(text, 1, cur - 2) .. unicode.sub(text, cur)
cur = cur - 1
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
cursorBlink = true
set(curPos(cur) + 1, unicode.sub(text, cur + 1) .. " ", false)
updateHistory()
elseif key == "delete" then
text = unicode.sub(text, 1, cur - 1) .. unicode.sub(text, cur + 1)
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), true)
cursorBlink = true
if cur <= unicode.len(text) then
set(curPos(cur + 1), unicode.sub(text, cur + 1) .. " ", false)
end
updateHistory()
elseif key == "enter" then
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), false)
break
elseif not (args[3] < 32 or (args[3] > 0x7F and args[3] <= 0x9F)) then
add(unicode.char(args[3]) or " ")
updateHistory()
end
elseif args and args[1] == "clipboard" then
local clip = args[3]
if not clip then goto continue end
while isLine(unicode.sub(clip, 1, 1)) do clip = unicode.sub(clip, 2) end
while isLine(unicode.sub(clip, -1)) do clip = unicode.sub(clip, 1, -2) end
add(clip)
updateHistory()
else
cursorBlink = not cursorBlink
set(curPos(cur), strDef(unicode.sub(text, cur, cur), " "), cursorBlink)
end
::continue::
end
if options.readHistoryType then
if readHistory[options.readHistoryType][#readHistory[options.readHistoryType]] == "" then
table.remove(readHistory[options.readHistoryType], #readHistory[options.readHistoryType])
end
if historyIdx < #readHistory[options.readHistoryType] then
table.insert(readHistory[options.readHistoryType], text)
end
while #readHistory[options.readHistoryType] > 50 do
table.remove(readHistory[options.readHistoryType], 1)
end
end
cursor.x = 1
cursor.y = cursor.y + math.ceil((unicode.wlen(text) + startX - 1) / width)
if cursor.y > height then
scroll(cursor.y - height)
end
return text
end
end
function module.exit()
_G._PUBLIC.terminal = nil
end
return module
View File
+4 -6
View File
@@ -47,15 +47,13 @@ function event.pull(...)
end
end
-- Check if we've timed out
if timeout and computer.uptime() >= startTime + timeout then
return nil -- Timed out, return nil
if timeout ~= nil and computer.uptime() >= startTime + timeout then
return nil
end
-- Yield to allow other processes to run and more events to be added
if timeout and timeout > 0 then
if timeout == nil then
coroutine.yield()
elseif not timeout then
elseif timeout > 0 then
coroutine.yield()
end
end
View File
View File
View File

Some files were not shown because too many files have changed in this diff Show More