PRE-ALPHA 3.0.0 - Rewrote the kernel to use a more modular design, changed some terms, added process sandboxing for security.
COMING IN THE FULL RELEASE: - A user system - A functional IPC (Inter-Process Communication) system THINGS CAN AND WILL CHANGE FROM NOW UNTIL THE FINAL RELEASE.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
local module = {}
|
||||
|
||||
module.dependencies = {"terminal"}
|
||||
|
||||
function module.check()
|
||||
return true -- This module should always be loaded
|
||||
end
|
||||
|
||||
function module.init()
|
||||
local publicTable = {
|
||||
"print",
|
||||
"require",
|
||||
"_VERSION",
|
||||
"_OSVERSION",
|
||||
"assert",
|
||||
"error",
|
||||
"getmetatable",
|
||||
"ipairs",
|
||||
"load",
|
||||
"next",
|
||||
"pairs",
|
||||
"pcall",
|
||||
"rawequal",
|
||||
"rawget",
|
||||
"rawlen",
|
||||
"rawset",
|
||||
"select",
|
||||
"setmetatable",
|
||||
"tonumber",
|
||||
"tostring",
|
||||
"type",
|
||||
"xpcall",
|
||||
"bit32",
|
||||
"coroutine",
|
||||
"debug",
|
||||
"math",
|
||||
"os",
|
||||
"string",
|
||||
"table",
|
||||
"checkArg",
|
||||
"utf8",
|
||||
"convert"
|
||||
}
|
||||
for _, value in ipairs(publicTable) do
|
||||
_G._PUBLIC[value] = table.copy(_G[value])
|
||||
end
|
||||
end
|
||||
|
||||
function module.exit()
|
||||
_G._PUBLIC = nil
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,15 @@
|
||||
local module = {}
|
||||
|
||||
function module.check()
|
||||
return true -- This module should always be loaded
|
||||
end
|
||||
|
||||
function module.init()
|
||||
|
||||
end
|
||||
|
||||
function module.exit()
|
||||
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,157 @@
|
||||
local module = {}
|
||||
|
||||
function module.check()
|
||||
return true -- This module should always be loaded
|
||||
end
|
||||
|
||||
function module.init()
|
||||
_G._PUBLIC.keyboard = {["keys"] = {}}
|
||||
|
||||
_PUBLIC.keyboard.keys["1"] = 0x02
|
||||
_PUBLIC.keyboard.keys["2"] = 0x03
|
||||
_PUBLIC.keyboard.keys["3"] = 0x04
|
||||
_PUBLIC.keyboard.keys["4"] = 0x05
|
||||
_PUBLIC.keyboard.keys["5"] = 0x06
|
||||
_PUBLIC.keyboard.keys["6"] = 0x07
|
||||
_PUBLIC.keyboard.keys["7"] = 0x08
|
||||
_PUBLIC.keyboard.keys["8"] = 0x09
|
||||
_PUBLIC.keyboard.keys["9"] = 0x0A
|
||||
_PUBLIC.keyboard.keys["0"] = 0x0B
|
||||
_PUBLIC.keyboard.keys.a = 0x1E
|
||||
_PUBLIC.keyboard.keys.b = 0x30
|
||||
_PUBLIC.keyboard.keys.c = 0x2E
|
||||
_PUBLIC.keyboard.keys.d = 0x20
|
||||
_PUBLIC.keyboard.keys.e = 0x12
|
||||
_PUBLIC.keyboard.keys.f = 0x21
|
||||
_PUBLIC.keyboard.keys.g = 0x22
|
||||
_PUBLIC.keyboard.keys.h = 0x23
|
||||
_PUBLIC.keyboard.keys.i = 0x17
|
||||
_PUBLIC.keyboard.keys.j = 0x24
|
||||
_PUBLIC.keyboard.keys.k = 0x25
|
||||
_PUBLIC.keyboard.keys.l = 0x26
|
||||
_PUBLIC.keyboard.keys.m = 0x32
|
||||
_PUBLIC.keyboard.keys.n = 0x31
|
||||
_PUBLIC.keyboard.keys.o = 0x18
|
||||
_PUBLIC.keyboard.keys.p = 0x19
|
||||
_PUBLIC.keyboard.keys.q = 0x10
|
||||
_PUBLIC.keyboard.keys.r = 0x13
|
||||
_PUBLIC.keyboard.keys.s = 0x1F
|
||||
_PUBLIC.keyboard.keys.t = 0x14
|
||||
_PUBLIC.keyboard.keys.u = 0x16
|
||||
_PUBLIC.keyboard.keys.v = 0x2F
|
||||
_PUBLIC.keyboard.keys.w = 0x11
|
||||
_PUBLIC.keyboard.keys.x = 0x2D
|
||||
_PUBLIC.keyboard.keys.y = 0x15
|
||||
_PUBLIC.keyboard.keys.z = 0x2C
|
||||
|
||||
_PUBLIC.keyboard.keys.apostrophe = 0x28
|
||||
_PUBLIC.keyboard.keys.at = 0x91
|
||||
_PUBLIC.keyboard.keys.back = 0x0E -- backspace
|
||||
_PUBLIC.keyboard.keys.backslash = 0x2B
|
||||
_PUBLIC.keyboard.keys.capital = 0x3A -- capslock
|
||||
_PUBLIC.keyboard.keys.colon = 0x92
|
||||
_PUBLIC.keyboard.keys.comma = 0x33
|
||||
_PUBLIC.keyboard.keys.enter = 0x1C
|
||||
_PUBLIC.keyboard.keys.equals = 0x0D
|
||||
_PUBLIC.keyboard.keys.grave = 0x29 -- accent grave
|
||||
_PUBLIC.keyboard.keys.lbracket = 0x1A
|
||||
_PUBLIC.keyboard.keys.lcontrol = 0x1D
|
||||
_PUBLIC.keyboard.keys.lmenu = 0x38 -- left Alt
|
||||
_PUBLIC.keyboard.keys.lshift = 0x2A
|
||||
_PUBLIC.keyboard.keys.minus = 0x0C
|
||||
_PUBLIC.keyboard.keys.numlock = 0x45
|
||||
_PUBLIC.keyboard.keys.pause = 0xC5
|
||||
_PUBLIC.keyboard.keys.period = 0x34
|
||||
_PUBLIC.keyboard.keys.rbracket = 0x1B
|
||||
_PUBLIC.keyboard.keys.rcontrol = 0x9D
|
||||
_PUBLIC.keyboard.keys.rmenu = 0xB8 -- right Alt
|
||||
_PUBLIC.keyboard.keys.rshift = 0x36
|
||||
_PUBLIC.keyboard.keys.scroll = 0x46 -- Scroll Lock
|
||||
_PUBLIC.keyboard.keys.semicolon = 0x27
|
||||
_PUBLIC.keyboard.keys.slash = 0x35 -- / on main _PUBLIC.keyboard
|
||||
_PUBLIC.keyboard.keys.space = 0x39
|
||||
_PUBLIC.keyboard.keys.stop = 0x95
|
||||
_PUBLIC.keyboard.keys.tab = 0x0F
|
||||
_PUBLIC.keyboard.keys.underline = 0x93
|
||||
|
||||
-- Keypad (and numpad with numlock off)
|
||||
_PUBLIC.keyboard.keys.up = 0xC8
|
||||
_PUBLIC.keyboard.keys.down = 0xD0
|
||||
_PUBLIC.keyboard.keys.left = 0xCB
|
||||
_PUBLIC.keyboard.keys.right = 0xCD
|
||||
_PUBLIC.keyboard.keys.home = 0xC7
|
||||
_PUBLIC.keyboard.keys["end"] = 0xCF
|
||||
_PUBLIC.keyboard.keys.pageUp = 0xC9
|
||||
_PUBLIC.keyboard.keys.pageDown = 0xD1
|
||||
_PUBLIC.keyboard.keys.insert = 0xD2
|
||||
_PUBLIC.keyboard.keys.delete = 0xD3
|
||||
|
||||
-- Function keys
|
||||
_PUBLIC.keyboard.keys.f1 = 0x3B
|
||||
_PUBLIC.keyboard.keys.f2 = 0x3C
|
||||
_PUBLIC.keyboard.keys.f3 = 0x3D
|
||||
_PUBLIC.keyboard.keys.f4 = 0x3E
|
||||
_PUBLIC.keyboard.keys.f5 = 0x3F
|
||||
_PUBLIC.keyboard.keys.f6 = 0x40
|
||||
_PUBLIC.keyboard.keys.f7 = 0x41
|
||||
_PUBLIC.keyboard.keys.f8 = 0x42
|
||||
_PUBLIC.keyboard.keys.f9 = 0x43
|
||||
_PUBLIC.keyboard.keys.f10 = 0x44
|
||||
_PUBLIC.keyboard.keys.f11 = 0x57
|
||||
_PUBLIC.keyboard.keys.f12 = 0x58
|
||||
_PUBLIC.keyboard.keys.f13 = 0x64
|
||||
_PUBLIC.keyboard.keys.f14 = 0x65
|
||||
_PUBLIC.keyboard.keys.f15 = 0x66
|
||||
_PUBLIC.keyboard.keys.f16 = 0x67
|
||||
_PUBLIC.keyboard.keys.f17 = 0x68
|
||||
_PUBLIC.keyboard.keys.f18 = 0x69
|
||||
_PUBLIC.keyboard.keys.f19 = 0x71
|
||||
|
||||
-- Japanese keyboards
|
||||
_PUBLIC.keyboard.keys.kana = 0x70
|
||||
_PUBLIC.keyboard.keys.kanji = 0x94
|
||||
_PUBLIC.keyboard.keys.convert = 0x79
|
||||
_PUBLIC.keyboard.keys.noconvert = 0x7B
|
||||
_PUBLIC.keyboard.keys.yen = 0x7D
|
||||
_PUBLIC.keyboard.keys.circumflex = 0x90
|
||||
_PUBLIC.keyboard.keys.ax = 0x96
|
||||
|
||||
-- Numpad
|
||||
_PUBLIC.keyboard.keys.numpad0 = 0x52
|
||||
_PUBLIC.keyboard.keys.numpad1 = 0x4F
|
||||
_PUBLIC.keyboard.keys.numpad2 = 0x50
|
||||
_PUBLIC.keyboard.keys.numpad3 = 0x51
|
||||
_PUBLIC.keyboard.keys.numpad4 = 0x4B
|
||||
_PUBLIC.keyboard.keys.numpad5 = 0x4C
|
||||
_PUBLIC.keyboard.keys.numpad6 = 0x4D
|
||||
_PUBLIC.keyboard.keys.numpad7 = 0x47
|
||||
_PUBLIC.keyboard.keys.numpad8 = 0x48
|
||||
_PUBLIC.keyboard.keys.numpad9 = 0x49
|
||||
_PUBLIC.keyboard.keys.numpadmul = 0x37
|
||||
_PUBLIC.keyboard.keys.numpaddiv = 0xB5
|
||||
_PUBLIC.keyboard.keys.numpadsub = 0x4A
|
||||
_PUBLIC.keyboard.keys.numpadadd = 0x4E
|
||||
_PUBLIC.keyboard.keys.numpaddecimal = 0x53
|
||||
_PUBLIC.keyboard.keys.numpadcomma = 0xB3
|
||||
_PUBLIC.keyboard.keys.numpadenter = 0x9C
|
||||
_PUBLIC.keyboard.keys.numpadequals = 0x8D
|
||||
|
||||
-- Create inverse mapping for name lookup.
|
||||
setmetatable(_PUBLIC.keyboard.keys,
|
||||
{
|
||||
__index = function(tbl, k)
|
||||
if type(k) ~= "number" then return end
|
||||
for name,value in pairs(tbl) do
|
||||
if value == k then
|
||||
return name
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function module.exit()
|
||||
_G._PUBLIC.keyboard = nil
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,466 @@
|
||||
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 ocelot = component.proxy(component.list("ocelot")())
|
||||
local component = require("component")
|
||||
local computer = require("computer")
|
||||
local gpu = component.gpu
|
||||
_G._PUBLIC.terminal = {}
|
||||
_PUBLIC.terminal.cursorPosX = 1
|
||||
_PUBLIC.terminal.cursorPosY = 1
|
||||
_PUBLIC.terminal.readHistory = {}
|
||||
|
||||
local width, height = gpu.getResolution()
|
||||
|
||||
local ANSIColorPalette = {
|
||||
["dark"] = {
|
||||
[0] = 0x000000,
|
||||
[1] = 0x800000,
|
||||
[2] = 0x008000,
|
||||
[3] = 0x808000,
|
||||
[4] = 0x000080,
|
||||
[5] = 0x800080,
|
||||
[6] = 0x008080,
|
||||
[7] = 0xC0C0C0
|
||||
},
|
||||
["bright"] = {
|
||||
[0] = 0x808080,
|
||||
[1] = 0xFF0000,
|
||||
[2] = 0x00FF00,
|
||||
[3] = 0xFFFF00,
|
||||
[4] = 0x0000FF,
|
||||
[5] = 0xFF00FF,
|
||||
[6] = 0x00FFFF,
|
||||
[7] = 0xFFFFFF
|
||||
}
|
||||
}
|
||||
|
||||
defaultForegroundColor = ANSIColorPalette["bright"][7]
|
||||
defaultBackgroundColor = ANSIColorPalette["dark"][0]
|
||||
|
||||
gpu.setForeground(defaultForegroundColor)
|
||||
gpu.setBackground(defaultBackgroundColor)
|
||||
|
||||
local function scrollDown()
|
||||
local width, height = gpu.getResolution()
|
||||
if gpu.copy(1,1,width,height,0,-1) then
|
||||
local prevForeground = gpu.getForeground()
|
||||
local prevBackground = gpu.getBackground()
|
||||
gpu.setForeground(defaultForegroundColor)
|
||||
gpu.setBackground(defaultBackgroundColor)
|
||||
gpu.fill(1, height, width, 1, " ")
|
||||
gpu.setForeground(prevForeground)
|
||||
gpu.setBackground(prevBackground)
|
||||
_PUBLIC.terminal.cursorPosY=height
|
||||
end
|
||||
end
|
||||
|
||||
local function newLine()
|
||||
_PUBLIC.terminal.cursorPosX=1
|
||||
_PUBLIC.terminal.cursorPosY = _PUBLIC.terminal.cursorPosY + 1
|
||||
if _PUBLIC.terminal.cursorPosY>height then
|
||||
scrollDown()
|
||||
end
|
||||
end
|
||||
|
||||
local function parseCodeNumbers(code)
|
||||
local o = {}
|
||||
for num in code:sub(3,-2):gmatch("[^;]+") do
|
||||
table.insert(o,tonumber(num))
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
local function from8BitColor(num)
|
||||
num=math.floor(num)&255
|
||||
if num<16 then return 0x444444*((num>>3)&1)+(0xBB0000*((num>>2)&1)|0x00BB00*((num>>1)&1)|0x0000BB*(num&1)) end
|
||||
if num>=232 then return 0x10101*(8+(num-232)*10) end
|
||||
num=num-16
|
||||
local palette = {0,95,135,175,215,255}
|
||||
return (palette[(num//36)%6+1]<<16)|(palette[(num//6)%6+1]<<8)|palette[num%6+1]
|
||||
end
|
||||
|
||||
local function from24BitColor(r,g,b)
|
||||
r,g,b=math.floor(r)&255,math.floor(g)&255,math.floor(b)&255
|
||||
return (r<<16)|(g<<8)|b
|
||||
end
|
||||
|
||||
local function findCodeEnd(text,i)
|
||||
local function inRange(v,min,max)
|
||||
return v>=min and v<=max
|
||||
end
|
||||
i=i+2
|
||||
while i<=#text and not inRange(text:byte(i),0x40,0x7F) do i=i+1 end
|
||||
return i
|
||||
end
|
||||
|
||||
function _PUBLIC.terminal.write(text, textWrap)
|
||||
local width, height = gpu.getResolution()
|
||||
|
||||
-- you don't know how tiring this was just for ANSI escape code support
|
||||
|
||||
if textWrap == nil then
|
||||
textWrap = true
|
||||
end
|
||||
|
||||
if not text or not tostring(text) then
|
||||
return
|
||||
end
|
||||
if text:find("\a") then
|
||||
computer.beep()
|
||||
end
|
||||
text = tostring(text)
|
||||
text = "\27[0m" .. text:gsub("\t", " ")
|
||||
local readBreak = 0
|
||||
-- readBreak is for when, inside the for loop, there normally would have been an increase in the "i" variable because it has read more than one character.
|
||||
-- unfortunately, changing the "i" variable would have unpredictable effects, so to not risk anything, this workaround was done.
|
||||
local section = ""
|
||||
|
||||
local function printSection()
|
||||
if #section==0 then
|
||||
return
|
||||
end
|
||||
while true do
|
||||
gpu.set(_PUBLIC.terminal.cursorPosX,_PUBLIC.terminal.cursorPosY,section)
|
||||
if unicode.wlen(section) > width - _PUBLIC.terminal.cursorPosX + 1 and textWrap then
|
||||
section = section:sub(width - _PUBLIC.terminal.cursorPosX + 2)
|
||||
newLine()
|
||||
else
|
||||
_PUBLIC.terminal.cursorPosX = _PUBLIC.terminal.cursorPosX+unicode.wlen(section)
|
||||
break
|
||||
end
|
||||
end
|
||||
section = ""
|
||||
end
|
||||
|
||||
for i=1,#text do
|
||||
if readBreak>0 then
|
||||
readBreak = readBreak - 1
|
||||
goto continue
|
||||
end
|
||||
|
||||
if string.byte(text,i)==10 then
|
||||
printSection()
|
||||
newLine()
|
||||
elseif string.byte(text,i)==13 then
|
||||
printSection()
|
||||
_PUBLIC.terminal.cursorPosX=1
|
||||
elseif string.byte(text,i)==0x1b and i<=#text-2 then
|
||||
printSection()
|
||||
--ocelot.log("0x1b char detected")
|
||||
local codeType = string.sub(text,i+1,i+1)
|
||||
if codeType=="[" then
|
||||
-- Control Sequence Introducer
|
||||
--ocelot.log("Control Sequence Introducer")
|
||||
local codeEndIdx = findCodeEnd(text,i)
|
||||
-- codeEndIdx = string.find(text,"m",i)
|
||||
local code = string.sub(text,i,codeEndIdx)
|
||||
--ocelot.log("Code: "..code.." ("..i..", "..codeEndIdx..")")
|
||||
readBreak = readBreak + #code - 1
|
||||
local nums = parseCodeNumbers(code)
|
||||
local codeEnd = code:sub(-1)
|
||||
--ocelot.log("Code end: "..codeEnd..", "..#codeEnd)
|
||||
if codeEnd == "m" then
|
||||
-- Select Graphic Rendition
|
||||
--ocelot.log("Select Graphic Rendition, ID "..nums[1])
|
||||
if nums[1]>=30 and nums[1]<=37 then
|
||||
gpu.setForeground(ANSIColorPalette["dark"][nums[1]%10])
|
||||
end
|
||||
if nums[1]==38 and nums[2]==5 then
|
||||
gpu.setForeground(from8BitColor(nums[3]))
|
||||
end
|
||||
if nums[1]==38 and nums[2]==2 then
|
||||
gpu.setForeground(from24BitColor(nums[3],nums[4],nums[5]))
|
||||
end
|
||||
if nums[1]==39 or nums[1]==0 then
|
||||
gpu.setForeground(defaultForegroundColor)
|
||||
end
|
||||
if nums[1]>=40 and nums[1]<=47 then
|
||||
gpu.setBackground(ANSIColorPalette["dark"][nums[1]%10])
|
||||
end
|
||||
if nums[1]==48 and nums[2]==5 then
|
||||
gpu.setBackground(from8BitColor(nums[3]))
|
||||
end
|
||||
if nums[1]==48 and nums[2]==2 then
|
||||
gpu.setBackground(from24BitColor(nums[3],nums[4],nums[5]))
|
||||
end
|
||||
if nums[1]==49 or nums[1]==0 then
|
||||
gpu.setBackground(defaultBackgroundColor)
|
||||
end
|
||||
if nums[1]>=90 and nums[1]<=97 then
|
||||
gpu.setForeground(ANSIColorPalette["bright"][nums[1]%10])
|
||||
end
|
||||
if nums[1]>=100 and nums[1]<=107 then
|
||||
gpu.setBackground(ANSIColorPalette["bright"][nums[1]%10])
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--gpu.set(_PUBLIC.terminal.cursorPosX,_PUBLIC.terminal.cursorPosY,string.sub(text,i,i))
|
||||
section = section..string.sub(text,i,i)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
printSection()
|
||||
end
|
||||
|
||||
function _G.print(...)
|
||||
local args = {...}
|
||||
local stringArgs = {}
|
||||
for _, arg in pairs(args) do
|
||||
if type(arg)=="table" then
|
||||
table.insert(stringArgs, serialize.table(arg,true))
|
||||
elseif tostring(arg) then
|
||||
table.insert(stringArgs, tostring(arg))
|
||||
end
|
||||
end
|
||||
_PUBLIC.terminal.write(table.concat(stringArgs, " ") .. "\n")
|
||||
end
|
||||
|
||||
function _G._PUBLIC.terminal.clear()
|
||||
width, height = gpu.getResolution()
|
||||
gpu.setForeground(defaultForegroundColor)
|
||||
gpu.setBackground(defaultBackgroundColor)
|
||||
gpu.fill(1,1,width,height," ")
|
||||
_PUBLIC.terminal.cursorPosX, _PUBLIC.terminal.cursorPosY = 1, 1
|
||||
end
|
||||
|
||||
function _G._PUBLIC.terminal.read(readHistoryType, prefix, defaultText, maxChars)
|
||||
checkArg(1, readHistoryType, "string", "nil")
|
||||
checkArg(2, prefix, "string", "nil")
|
||||
checkArg(3, defaultText, "string", "nil")
|
||||
checkArg(4, maxChars, "number", "nil")
|
||||
maxChars = maxChars or math.huge
|
||||
|
||||
local text = defaultText or ""
|
||||
|
||||
local historyIdx
|
||||
if readHistoryType then
|
||||
if not _PUBLIC.terminal.readHistory[readHistoryType] then
|
||||
_PUBLIC.terminal.readHistory[readHistoryType] = {text}
|
||||
elseif _PUBLIC.terminal.readHistory[readHistoryType][#_PUBLIC.terminal.readHistory[readHistoryType] ] ~= "" then
|
||||
table.insert(_PUBLIC.terminal.readHistory[readHistoryType], text)
|
||||
end
|
||||
historyIdx = #_PUBLIC.terminal.readHistory[readHistoryType]
|
||||
end
|
||||
|
||||
local function updateHistory()
|
||||
if not readHistoryType then return end
|
||||
_PUBLIC.terminal.readHistory[readHistoryType][historyIdx]=text
|
||||
end
|
||||
|
||||
local cur = unicode.len(text)+1
|
||||
if prefix then _PUBLIC.terminal.write(prefix) end
|
||||
local startX, startY = _PUBLIC.terminal.cursorPosX, _PUBLIC.terminal.cursorPosY
|
||||
local fg, bg = gpu.getForeground(), gpu.getBackground()
|
||||
local cursorBlink = true
|
||||
local function get(idx)
|
||||
idx=startX+idx-1
|
||||
return gpu.get(idx%width,startY+(idx//width))
|
||||
end
|
||||
local function checkScroll(y)
|
||||
for i=1,y-height do
|
||||
scrollDown()
|
||||
startY=startY-1
|
||||
end
|
||||
return math.min(y,height)
|
||||
end
|
||||
local function set(idx,chr,rev)
|
||||
if chr==nil or chr=="" then return end
|
||||
if rev then
|
||||
gpu.setForeground(bg)
|
||||
gpu.setBackground(fg)
|
||||
else
|
||||
gpu.setForeground(fg)
|
||||
gpu.setBackground(bg)
|
||||
end
|
||||
idx=startX+idx-1
|
||||
local setX, setY = (idx-1)%width+1, startY+((idx-1)//width+1)-1
|
||||
setY = checkScroll(setY)
|
||||
gpu.set(setX,setY,unicode.sub(chr,1,width-setX+1))
|
||||
for i=1,math.ceil((#chr+setX-1)/width)+1 do
|
||||
gpu.set(1,setY+i,unicode.sub(chr,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)>=maxChars then return end
|
||||
if maxChars<math.huge then
|
||||
chr=unicode.sub(chr,1,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),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)}
|
||||
if args and args[1] == "key_down" and args[4] then
|
||||
local key = _PUBLIC.keyboard.keys[args[4]]
|
||||
if key=="up" and readHistoryType then
|
||||
historyIdx=math.max(historyIdx-1,1)
|
||||
reprint(_PUBLIC.terminal.readHistory[readHistoryType][historyIdx])
|
||||
elseif key=="down" and readHistoryType then
|
||||
historyIdx=math.min(historyIdx+1,#_PUBLIC.terminal.readHistory[readHistoryType])
|
||||
reprint(_PUBLIC.terminal.readHistory[readHistoryType][historyIdx])
|
||||
elseif key=="left" and _PUBLIC.keyboard.ctrlDown then
|
||||
moveWord(-1)
|
||||
elseif key=="right" and _PUBLIC.keyboard.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 _PUBLIC.keyboard.ctrlDown then
|
||||
deleteWord(-1)
|
||||
elseif key=="delete" and _PUBLIC.keyboard.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 readHistoryType then
|
||||
if _PUBLIC.terminal.readHistory[readHistoryType][#_PUBLIC.terminal.readHistory[readHistoryType]]=="" then
|
||||
table.remove(_PUBLIC.terminal.readHistory[readHistoryType],#_PUBLIC.terminal.readHistory[readHistoryType])
|
||||
end
|
||||
if historyIdx<#_PUBLIC.terminal.readHistory[readHistoryType] then
|
||||
table.remove(_PUBLIC.terminal.readHistory[readHistoryType],historyIdx)
|
||||
table.insert(_PUBLIC.terminal.readHistory[readHistoryType],text)
|
||||
end
|
||||
while #_PUBLIC.terminal.readHistory[readHistoryType] > 50 do
|
||||
table.remove(_PUBLIC.terminal.readHistory[readHistoryType], 1)
|
||||
end
|
||||
end
|
||||
|
||||
_PUBLIC.terminal.cursorPosX=1
|
||||
_PUBLIC.terminal.cursorPosY=_PUBLIC.terminal.cursorPosY+math.ceil((unicode.wlen(text)+startX-1)/width)
|
||||
if _PUBLIC.terminal.cursorPosY>height then scrollDown() end
|
||||
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
function module.exit()
|
||||
_G._PUBLIC.terminal = nil
|
||||
end
|
||||
|
||||
return module
|
||||
Reference in New Issue
Block a user