feat: 初始提交 LeonOS 实现
添加 LeonOS 的基本实现,包括:
- 核心 API 模块(colors, disk, gps, keys, multishell, parallel, rednet, redstone, settings, vector)
- 命令行程序(about, alias, bg, clear, copy, delete, edit, fg, help, list, lua, mkdir, move, paint, peripherals, programs, reboot, set, shutdown, threads)
- 系统启动脚本和包管理
- 文档(README.md, LICENSE)
- 开发工具(devbin)和更新程序
实现功能:
- 完整的线程管理系统
- 兼容 ComputerCraft 的 API 设计
- 改进的 shell 和命令补全系统
- 多标签终端支持
- 设置管理系统
2025-08-31 16:54:18 +08:00
|
|
|
-- UnBIOS by JackMacWindows
|
2025-08-31 17:30:12 +08:00
|
|
|
-- Modified by Leonmmcoset to work with LeonOS
|
feat: 初始提交 LeonOS 实现
添加 LeonOS 的基本实现,包括:
- 核心 API 模块(colors, disk, gps, keys, multishell, parallel, rednet, redstone, settings, vector)
- 命令行程序(about, alias, bg, clear, copy, delete, edit, fg, help, list, lua, mkdir, move, paint, peripherals, programs, reboot, set, shutdown, threads)
- 系统启动脚本和包管理
- 文档(README.md, LICENSE)
- 开发工具(devbin)和更新程序
实现功能:
- 完整的线程管理系统
- 兼容 ComputerCraft 的 API 设计
- 改进的 shell 和命令补全系统
- 多标签终端支持
- 设置管理系统
2025-08-31 16:54:18 +08:00
|
|
|
-- 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
|
|
|
|
|
if _HOST:find("UnBIOS") then return end
|
|
|
|
|
local keptAPIs = {bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, io = 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, _RC_ROM_DIR = true}
|
|
|
|
|
_G._RC_ROM_DIR = settings.get("LeonOS.rom_dir") or error("LeonOS.rom_dir is not set!", 0)
|
|
|
|
|
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
|
|
|
|
|
_G.term = _G.term.native()
|
|
|
|
|
_G.http.checkURL = _G.http.checkURLAsync
|
|
|
|
|
_G.http.websocket = _G.http.websocketAsync
|
|
|
|
|
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 = {"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
|
|
|
|
|
_G._HOST = _G._HOST .. " (UnBIOS)"
|
|
|
|
|
-- 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("/bios.lua", "r")
|
|
|
|
|
if file == nil then
|
|
|
|
|
term.setCursorBlink(false)
|
|
|
|
|
term.setTextColor(16384)
|
|
|
|
|
term.write("Could not find /bios.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(), "@bios.lua")
|
|
|
|
|
file.close()
|
|
|
|
|
if fn == nil then
|
|
|
|
|
term.setCursorBlink(false)
|
|
|
|
|
term.setTextColor(16384)
|
|
|
|
|
term.write("Could not load /bios.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()
|
|
|
|
|
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)
|
|
|
|
|
restoreValue(http, "request", "nativeHTTPRequest", 3)
|
|
|
|
|
restoreValue(os, "shutdown", "nativeShutdown", 1)
|
|
|
|
|
restoreValue(os, "restart", "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
|
|
|
|
|
coroutine.yield()
|