formating better for spm packages

This commit is contained in:
2026-03-26 08:12:37 -04:00
parent 22b5021e9d
commit ab0a10105c
193 changed files with 4228 additions and 464 deletions

View File

@@ -0,0 +1,387 @@
--:Minify:--
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
---@diagnostic disable-next-line: undefined-global
local term = term
local os = os
local function write(text)
local x, y = term.getCursorPos()
local w, h = term.getSize()
for i = 1, #text do
local c = text:sub(i, i)
if c == "\n" then
y = y + 1
x = 1
elseif c == "\t" then
local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize)
term.write(string.rep(" ", spaces))
x = x + spaces
elseif c == "\b" then
if x > 1 then
x = x - 1
term.setCursorPos(x, y)
term.write(" ")
term.setCursorPos(x, y)
end
else
if x <= w and y <= h then
term.setCursorPos(x, y)
term.write(c)
x = x + 1
end
end
if x > w then
x = 1
y = y + 1
end
if y - 1 >= h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
local function displaySuperBadError(err)
term.setBackgroundColor(0x1)
term.setTextColor(0x4)
term.clear()
term.setCursorPos(1, 1)
term.write("A critical error occurred while loading the system:")
term.setCursorPos(1, 3)
write(err)
while true do end
end
term.setCursorBlink(false)
local ok, err = xpcall(function()
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
local lua = {
coroutine = true,
debug = true,
_VERSION = true,
assert = true,
collectgarbage = true,
error = true,
gcinfo = true,
getmetatable = true,
ipairs = true,
__inext = true,
load = true,
math = true,
next = true,
pairs = true,
pcall = true,
rawequal = true,
rawget = true,
rawlen = true,
rawset = true,
select = true,
setmetatable = true,
string = true,
table = true,
tonumber = true,
tostring = true,
type = true,
xpcall = true,
_G = true
}
local debug = debug
for i, v in pairs(_G) do
if not lua[i] or lua[i] == nil then
apis[i] = v
_G[i] = nil
end
end
local acekeys={
[apis.keys.enter]="\n",
[apis.keys.tab]="\t",
[apis.keys.backspace]="\b",
[apis.keys.up]="\17",
[apis.keys.down]="\18",
[apis.keys.left]="\19",
[apis.keys.right]="\20",
}
function sleep(time)
local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end
end
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
local function getFile(path)
local file = apis.fs.open(path, "r")
if not file then
displaySuperBadError("Could not open file: " .. path)
end
local content = file.readAll()
file.close()
return content
end
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
if not Kernel then displaySuperBadError("Could not load kernel.") end
if not initFs then displaySuperBadError("Could not load initdisks.") end
if not fs then displaySuperBadError("Could not load initfs.") end
if not apis.fs.exists("/nvram.dat") then
local file = apis.fs.open("/nvram.dat", "w")
file.write("Hello, World!")
file.close()
end
local eeprom
if apis.fs.exists("/startup.lua") then
eeprom="/startup.lua"
elseif apis.fs.exists("/eeprom") then
eeprom="/eeprom"
end
local eventQueue = {}
local function queueEvent(event, ...)
table.insert(eventQueue, {event, ...})
end
local colors = {
[0x000000]=0x0001,
[0xFFFFFF]=0x0002,
[0xFF0000]=0x0004,
[0x00FF00]=0x0008,
[0x0000FF]=0x0010,
[0x00FFFF]=0x0020,
[0xFF00FF]=0x0040,
[0xFFFF00]=0x0080,
[0xFF6D00]=0x0100,
[0x6DFF55]=0x0200,
[0x24FFFF]=0x0400,
[0x924900]=0x0800,
[0x6D6D55]=0x1000,
[0xDBDBAA]=0x2000,
[0x6D00FF]=0x4000,
[0xB6FF00]=0x8000
}
local fg,bg=0x6D6D55,0x000000
local l1f,l1d,l2,ops={},{},{},0
local function findClosest(tbl, target)
local closest = nil
local smallestDiff = math.huge
for k, _ in pairs(tbl) do
local diff = math.abs(k - target)
if diff < smallestDiff then
smallestDiff = diff
closest = k
end
end
return closest
end
local function aprox(c24)
ops = ops + 1
if ops % 1024 == 0 then
l1d = {}
l1f = {}
end
if ops % 8192 == 0 then
l2 = {}
end
if l2[c24] ~= nil then
return l2[c24]
end
if l1d[c24] ~= nil then
l1f[c24] = l1f[c24] + 1
if l1f[c24] >= 16 then
l2[c24] = l1d[c24]
l1d[c24] = nil
l1f[c24] = nil
return l2[c24]
end
return l1d[c24]
end
local closestKey = findClosest(colors, c24)
if not closestKey then return nil end
local value = colors[closestKey]
l1d[c24] = value
l1f[c24] = 1
return value
end
local EFI = {
getEpochMs = function() return apis.os.epoch("utc") end,
getUptime = function() return apis.os.clock() * 1000 end,
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
getMachineEvent = function()
if #eventQueue > 0 then
return table.unpack(table.remove(eventQueue, 1))
else
return nil
end
end,
getEEPROM = function() return getFile(eeprom) end,
setEEPROM = function(_, text)
local h = apis.fs.open(eeprom, "w")
h.write(text)
h.close()
end,
initfs=fs,
disks=initFs,
screenCtl={
print = function(_, text) write(text .. "\n") end,
printInline = function(_, text) write(text) end,
clear = function()
apis.term.clear()
apis.term.setCursorPos(1, 1)
end,
setCursorPos = function(_, x, y)
apis.term.setCursorPos(x, y)
end,
getCursorPos = function() return apis.term.getCursorPos() end,
getSize = function() return apis.term.getSize() end,
setBackgroundColor = function(_, color)
apis.term.setBackgroundColor(aprox(color))
end,
setTextColor = function(_, color)
apis.term.setTextColor(aprox(color))
end,
getBackgroundColor = function()
return bg
end,
getTextColor = function()
return fg
end,
enable=function() end,
disable=function() end
},
architecture="cct",
getNvram = function() return getFile("/nvram.dat") end,
setNvram = function(_, text)
local h = apis.fs.open("/nvram.dat", "w")
h.write(text)
h.close()
end,
firmware=apis,
reboot=false
}
apis.term.setBackgroundColor(0x8000)
apis.term.setTextColor(0x1000)
apis.term.clear()
apis.term.setCursorPos(1, 1)
local kernelCoro = coroutine.create(function()
---@diagnostic disable-next-line: param-type-mismatch
local ok, err = xpcall(Kernel, debug.traceback, EFI)
if not ok and not EFI.reboot then displaySuperBadError(err) end
if err then
apis.os.reboot()
else
apis.os.shutdown()
end
end)
function coroutine.resumeWithTimeout(co, timeout, ...)
local startTime = EFI.getEpochMs()
debug.sethook(co, function()
if EFI.getEpochMs() > startTime + timeout then
return coroutine.yield("timeout")
end
end, "", 1000)
local ret = {coroutine.resume(co, ...)}
if ret[1] and ret[2] == "timeout" then
return "timeout"
elseif ret[1] == false then
return "error", ret[2]
else
debug.sethook(co)
return "success", table.unpack(ret, 2)
end
end
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
while true do
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
apis.os.queueEvent("NoSleep")
local exit = false
while not exit do
local event = {coroutine.yield()}
if event[1] == "key" then
queueEvent("keyPressed", 1, event[2])
if acekeys[event[2]] then
queueEvent("keyTyped", 1, acekeys[event[2]])
end
elseif event[1] == "char" then
queueEvent("keyTyped", 1, event[2])
elseif event[1] == "key_up" then
queueEvent("keyReleased", 1, event[2])
elseif event[1] == "disk" then
queueEvent("componentAdded", "disk")
elseif event[1] == "disk_eject" then
queueEvent("componentRemoved", "disk")
elseif event[1] == "modem_message" then
queueEvent("modem_message", table.unpack(event, 2))
elseif event[1] == "rednet_message" then
queueEvent("rednet_message", table.unpack(event, 2))
elseif event[1] == "http_success" then
queueEvent("http_success", table.unpack(event, 2))
elseif event[1] == "http_failure" then
queueEvent("http_failure", table.unpack(event, 2))
elseif event[1] == "NoSleep" then
exit = true
end
end
if status == "error" or coroutine.status(kernelCoro) == "dead" then
if EFI.reboot then
apis.os.reboot()
end
displaySuperBadError("Kernel error: " .. tostring(err))
coroutine.yield("key")
end
initFs:refresh()
end
end, debug.traceback)
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
while true do coroutine.yield("key") end

View File

@@ -0,0 +1,119 @@
--:Minify:--
local BOOT_DRIVE_PATH=({...})[1] or "/$"
-- UnBIOS by JackMacWindows
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
-- To use, just place a `bios.lua` in the root of the drive, and run this program
-- Here's a list of things that are irreversibly changed:
-- * both `bit` and `bit32` are kept for compatibility
-- * string metatable blocking (on old versions of CC)
-- In addition, if `debug` is not available these things are also irreversibly changed:
-- * old Lua 5.1 `load` function (for loading from a function)
-- * `loadstring` prefixing (before CC:T 1.96.0)
-- * `http.request`
-- * `os.shutdown` and `os.reboot`
-- * `peripheral`
-- * `turtle.equip[Left|Right]`
-- Licensed under the MIT license
local args = {...}
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
local t = {}
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
for _,k in ipairs(t) do _G[k] = nil end
local native = _G.term.native()
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
_G.term = native
if _G.http then
_G.http.checkURL = _G.http.checkURLAsync
_G.http.websocket = _G.http.websocketAsync
end
if _G.commands then _G.commands = _G.commands.native end
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
-- Set up TLCO
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
-- this would cause `parallel` to throw an error, but we replace `error` with an
-- empty placeholder to let it continue and return without throwing. This results
-- in the `pcall` returning successfully, preventing the error-displaying code
-- from running - essentially making it so that `os.shutdown` is called immediately
-- after the new BIOS exits.
--
-- From there, the setup code is placed in `term.native` since it's the first
-- thing called after `parallel` exits. This loads the new BIOS and prepares it
-- for execution. Finally, it overwrites `os.shutdown` with the new function to
-- allow it to be the last function called in the original BIOS, and returns.
-- From there execution continues, calling the `term.redirect` dummy, skipping
-- over the error-handling code (since `pcall` returned ok), and calling
-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail
-- called, which effectively makes it run as the main chunk.
local olderror = error
_G.error = function() end
_G.term.redirect = function() end
function _G.term.native()
_G.term.native = nil
_G.term.redirect = nil
_G.error = olderror
term.setBackgroundColor(32768)
term.setTextColor(1)
term.setCursorPos(1, 1)
term.setCursorBlink(true)
term.clear()
local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
if file == nil then
term.setCursorBlink(false)
term.setTextColor(16384)
term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2)
term.write("Press any key to continue")
coroutine.yield("key")
os.shutdown()
end
local fn, err = loadstring(file.readAll(), "@bootloader")
file.close()
if fn == nil then
term.setCursorBlink(false)
term.setTextColor(16384)
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2)
term.write(err)
term.setCursorPos(1, 3)
term.write("Press any key to continue")
coroutine.yield("key")
os.shutdown()
end
setfenv(fn, _G)
local oldshutdown = os.shutdown
os.shutdown = function()
os.shutdown = oldshutdown
return fn(BOOT_DRIVE_PATH)
end
end
if debug then
-- Restore functions that were overwritten in the BIOS
-- Apparently this has to be done *after* redefining term.native
local function restoreValue(tab, idx, name, hint)
local i, key, value = 1, debug.getupvalue(tab[idx], hint)
while key ~= name and key ~= nil do
key, value = debug.getupvalue(tab[idx], i)
i=i+1
end
tab[idx] = value or tab[idx]
end
restoreValue(_G, "loadstring", "nativeloadstring", 1)
restoreValue(_G, "load", "nativeload", 5)
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
restoreValue(os, "shutdown", "nativeShutdown", 1)
restoreValue(os, "reboot", "nativeReboot", 1)
if turtle then
restoreValue(turtle, "equipLeft", "v", 1)
restoreValue(turtle, "equipRight", "v", 1)
end
do
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
while key ~= "native" and key ~= nil do
key, value = debug.getupvalue(peripheral.isPresent, i)
i=i+1
end
_G.peripheral = value or peripheral
end
end

View File

@@ -0,0 +1,272 @@
--:Minify:--
local apis = ({...})[1]
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH
local fs = apis.fs
local native = apis.peripheral
local peripheral = {}
local sides = {"top", "bottom", "left", "right", "front", "back"}
function peripheral.getNames()
local results = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(results, side)
if native.hasType(side, "peripheral_hub") then
local remote = native.call(side, "getNamesRemote")
for _, name in ipairs(remote) do
table.insert(results, name)
end
end
end
end
return results
end
function peripheral.isPresent(name)
if native.isPresent(name) then
return true
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return true
end
end
return false
end
function peripheral.getType(peripheral)
if type(peripheral) == "string" then
if native.isPresent(peripheral) then
return native.getType(peripheral)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "getTypeRemote", peripheral)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return table.unpack(mt.types)
end
end
function peripheral.hasType(peripheral, peripheral_type)
if type(peripheral) == "string" then
if native.isPresent(peripheral) then
return native.hasType(peripheral, peripheral_type)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.types[peripheral_type] ~= nil
end
end
function peripheral.getMethods(name)
if native.isPresent(name) then
return native.getMethods(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getMethodsRemote", name)
end
end
return nil
end
function peripheral.getName(peripheral)
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.name
end
function peripheral.call(name, method, ...)
if native.isPresent(name) then
return native.call(name, method, ...)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "callRemote", name, method, ...)
end
end
return nil
end
function peripheral.wrap(name)
local methods = peripheral.getMethods(name)
if not methods then
return nil
end
local types = { peripheral.getType(name) }
for i = 1, #types do types[types[i]] = true end
local result = setmetatable({}, {
__name = "peripheral",
name = name,
type = types[1],
types = types,
})
for _, method in ipairs(methods) do
result[method] = function(...)
return peripheral.call(name, method, ...)
end
end
return result
end
function peripheral.find(ty, filter)
local results = {}
for _, name in ipairs(peripheral.getNames()) do
if peripheral.hasType(name, ty) then
local wrapped = peripheral.wrap(name)
if filter == nil or filter(name, wrapped) then
table.insert(results, wrapped)
end
end
end
return table.unpack(results)
end
local disks = {}
local internal = {}
local function norm(path)
if not path or path == "" then return "/" end
return fs.combine("/", path)
end
local function createDisk(id, basePath, readonly, periph)
basePath = norm(basePath)
local disk = {address = id, isReadOnly = function() return readonly end}
function disk:spaceUsed()
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
end
function disk:spaceTotal() return fs.getCapacity(basePath) end
function disk:list(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) or not fs.isDir(p) then
return nil, "not directory"
end
return fs.list(p)
end
function disk:fileExists(path)
local p = fs.combine(basePath, path)
return fs.exists(p) and not fs.isDir(p)
end
function disk:directoryExists(path)
local p = fs.combine(basePath, path)
return fs.exists(p) and fs.isDir(p)
end
function disk:type(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) then
return nil
elseif fs.isDir(p) then
return "directory"
else
return "file"
end
end
function disk:makeDirectory(path)
local p = fs.combine(basePath, path)
fs.makeDir(p)
return true
end
function disk:remove(path)
local p = fs.combine(basePath, path)
if fs.exists(p) then fs.delete(p) end
return true
end
function disk:setLabel(label) periph.setLabel(label) end
function disk:getLabel(label) return periph.getLabel() end
function disk:attributes(path)
local p = fs.combine(basePath, path)
return fs.attributes(p)
end
function disk:open(path, mode)
local p = fs.combine(basePath, path)
return fs.open(p, mode)
end
return disk
end
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel = function(label)
local h = fs.open("/.label", "w")
h.write(label)
h.close()
end,
getLabel = function()
local h = fs.open("/.label", "r")
if not h then return "$" end
local label = h.readAll()
h.close()
return label
end
})
internal["rom"] = createDisk("rom", "/rom", true, {
setLabel = function(label)
error("Device is read-only")
end,
getLabel = function()
return "cctrom"
end
})
local function refresh()
disks={}
for _, disk in ipairs({peripheral.find("drive")}) do
if disk.isDiskPresent() then
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
end
end
end
local function iter()
refresh()
local combined = {}
for id, obj in pairs(internal) do combined[id] = obj end
for id, obj in pairs(disks) do combined[id] = obj end
return pairs(combined)
end
return {refresh = refresh, list = iter}

View File

@@ -0,0 +1,394 @@
--:Minify:--
local kernel = ...
local apis = kernel.apis
local native = apis.peripheral
local sides = {"top", "bottom", "left", "right", "front", "back"}
local peripheral={}
function peripheral.getNames()
local results = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(results, side)
if native.hasType(side, "peripheral_hub") then
local remote = native.call(side, "getNamesRemote")
for _, name in ipairs(remote) do
table.insert(results, name)
end
end
end
end
return results
end
function peripheral.isPresent(name)
if native.isPresent(name) then
return true
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return true
end
end
return false
end
function peripheral.getType(peripheral)
if type(peripheral) == "string" then
if native.isPresent(peripheral) then
return native.getType(peripheral)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "getTypeRemote", peripheral)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return table.unpack(mt.types)
end
end
function peripheral.hasType(peripheral, peripheral_type)
if type(peripheral) == "string" then
if native.isPresent(peripheral) then
return native.hasType(peripheral, peripheral_type)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.types[peripheral_type] ~= nil
end
end
function peripheral.getMethods(name)
if native.isPresent(name) then
return native.getMethods(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getMethodsRemote", name)
end
end
return nil
end
function peripheral.getName(peripheral)
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.name
end
function peripheral.call(name, method, ...)
if native.isPresent(name) then
return native.call(name, method, ...)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "callRemote", name, method, ...)
end
end
return nil
end
function peripheral.wrap(name)
local methods = peripheral.getMethods(name)
if not methods then
return nil
end
local types = { peripheral.getType(name) }
for i = 1, #types do types[types[i]] = true end
local result = setmetatable({}, {
__name = "peripheral",
name = name,
type = types[1],
types = types,
})
for _, method in ipairs(methods) do
result[method] = function(...)
return peripheral.call(name, method, ...)
end
end
return result
end
function peripheral.find(ty, filter)
local results = {}
for _, name in ipairs(peripheral.getNames()) do
if peripheral.hasType(name, ty) then
local wrapped = peripheral.wrap(name)
if filter == nil or filter(name, wrapped) then
table.insert(results, wrapped)
end
end
end
return table.unpack(results)
end
local icolors = {
[0x1] = 1, -- #000000
[0x2] = 2, -- #FFFFFF
[0x4] = 3, -- #FF0000
[0x8] = 4, -- #00FF00
[0x10] = 5, -- #0000FF
[0x20] = 6, -- #00FFFF
[0x40] = 7, -- #FF00FF
[0x80] = 8, -- #FFFF00
[0x100] = 9, -- #FF6D00
[0x200] = 10, -- #6DFF55
[0x400] = 11, -- #24FFFF
[0x800] = 12, -- #924900
[0x1000] = 13, -- #6D6D55
[0x2000] = 14, -- #DBDBAA
[0x4000] = 15, -- #6D00FF
[0x8000] = 16 -- #B6FF00
}
local colors = {
0x0001, -- #000000
0x0002, -- #FFFFFF
0x0004, -- #FF0000
0x0008, -- #00FF00
0x0010, -- #0000FF
0x0020, -- #00FFFF
0x0040, -- #FF00FF
0x0080, -- #FFFF00
0x0100, -- #FF6D00
0x0200, -- #6DFF55
0x0400, -- #24FFFF
0x0800, -- #924900
0x1000, -- #6D6D55
0x2000, -- #DBDBAA
0x4000, -- #6D00FF
0x8000 -- #B6FF00
}
local function write(text, term)
local x, y = term.getCursorPos()
local w, h = term.getSize()
for i = 1, #text do
local c = text:sub(i, i)
if c == "\n" then
y = y + 1
x = 1
elseif c == "\t" then
local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize)
term.write(string.rep(" ", spaces))
x = x + spaces
elseif c == "\b" then
if x > 1 then
x = x - 1
term.setCursorPos(x, y)
term.write(" ")
term.setCursorPos(x, y)
end
else
if x <= w and y <= h then
term.setCursorPos(x, y)
term.write(c)
x = x + 1
end
end
if x > w then
x = 1
y = y + 1
end
if y - 1 >= h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
kernel.devfs.data.tty={}
local ctrl,alt = false, false
local function serializeBool(bool)
if bool then
return "T"
else
return "F"
end
end
local function newtty(obj, id, ev)
kernel.devfs.data["tty"][id] = function(op, mode)
if op=="type" then
return "character device"
elseif op=="open" then
local h = {
read=function(amount)
local rv=""
for i=1, amount or 1 do
local event = {ev()}
if event[1] then
rv=rv..event[1]
end
end
if rv=="" then rv=nil end
return rv
end,
write=function(content)
write(content, obj)
end,
size=function()
local s={obj.getSize()}
return table.concat(s,";")
end,
clear=function()
obj.clear()
obj.setCursorPos(1,1)
end,
gpos=function()
local s={obj.getCursorPos()}
return table.concat(s,";")
end,
spos=function(x,y)
return obj.setCursorPos(x,y)
end,
sfgc=function(c)
return obj.setTextColor(colors[c])
end,
sbgc=function(c)
return obj.setBackgroundColor(colors[c])
end,
gfgc=function()
return icolors[obj.getTextColor()]
end,
gbgc=function()
return icolors[obj.getBackgroundColor()]
end,
gctrl=function()
return serializeBool(ctrl)..";"..serializeBool(alt)
end
}
if mode=="rw" then
return h
elseif mode=="r" then
h["write"]=nil
return h
elseif mode=="w" then
h["read"]=nil
return h
end
end
end
end
local fifo = kernel.newFifo()
kernel.processes.cctmond = function()
local timeout = false
while true do
local event = {kernel.EFI:getMachineEvent()}
if event[1] then
local eventType = event[1]
local charOrKey = event[3]
local ctrlKeyMap = {
[apis.keys.a]=1, [apis.keys.b]=2, [apis.keys.c]=3,
[apis.keys.d]=4, [apis.keys.e]=5, [apis.keys.f]=6,
[apis.keys.g]=7, [apis.keys.h]=8, [apis.keys.i]=9,
[apis.keys.j]=10, [apis.keys.k]=11, [apis.keys.l]=12,
[apis.keys.m]=13, [apis.keys.n]=14, [apis.keys.o]=15,
[apis.keys.p]=16, [apis.keys.q]=17, [apis.keys.r]=18,
[apis.keys.s]=19, [apis.keys.t]=20, [apis.keys.u]=21,
[apis.keys.v]=22, [apis.keys.w]=23, [apis.keys.x]=24,
[apis.keys.y]=25, [apis.keys.z]=26,
}
if eventType == "keyPressed" then
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
ctrl = true
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
alt = true
end
if ctrl then
local ctrlByte = ctrlKeyMap[charOrKey]
if ctrlByte then
if ctrlByte == 3 then
for _, task in ipairs(syscall.getTasks()) do
syscall.sigsend(task, 1)
end
else
fifo.push(string.char(ctrlByte))
end
end
else
local specialKeyMap = {
[apis.keys.up] = "",
[apis.keys.down] = "",
[apis.keys.right] = "",
[apis.keys.left] = "",
[apis.keys.home] = "",
[apis.keys["end"]] = "",
[apis.keys.pageUp] = "[5~",
[apis.keys.pageDown] = "[6~",
[apis.keys.delete] = "[3~",
}
local special = specialKeyMap[charOrKey]
if special then fifo.push(special) end
end
elseif eventType == "keyReleased" then
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
ctrl = false
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
alt = false
end
elseif eventType == "keyTyped" then
if charOrKey then fifo.push(charOrKey) end
end
timeout = false
else
timeout = true
end
if timeout then
sleep(0.05)
end
end
end
newtty(apis.term, "1", fifo.pop)
for i,v in ipairs({peripheral.find("monitor")}) do
v.setTextScale(.5)
v.write("Initializing...")
newtty(v,tostring(i+1),function () end)
end