neonucleus/data/OpenOS/lib/core/lua_shell.lua
IonutParau 687cfebd00 testing version of LuaBIOS and OpenOS
people were having issues getting them to work so now we promote consistency
2025-06-28 20:41:49 +02:00

130 lines
3.6 KiB
Lua

local package = require("package")
local term = require("term")
local function optrequire(...)
local success, module = pcall(require, ...)
if success then
return module
end
end
local env -- forward declare for binding in metamethod
env = setmetatable({}, {
__index = function(_, k)
_ENV[k] = _ENV[k] or optrequire(k)
return _ENV[k]
end,
__pairs = function(t)
return function(_, key)
local k, v = next(t, key)
if not k and t == env then
t = _ENV
k, v = next(t)
end
if not k and t == _ENV then
t = package.loaded
k, v = next(t)
end
return k, v
end
end,
})
env._PROMPT = tostring(env._PROMPT or "\27[32mlua> \27[37m")
local function findTable(t, path)
if type(t) ~= "table" then return nil end
if not path or #path == 0 then return t end
local name = string.match(path, "[^.]+")
for k, v in pairs(t) do
if k == name then
return findTable(v, string.sub(path, #name + 2))
end
end
local mt = getmetatable(t)
if t == env then mt = {__index=_ENV} end
if mt then
return findTable(mt.__index, path)
end
return nil
end
local function findKeys(t, r, prefix, name)
if type(t) ~= "table" then return end
for k, v in pairs(t) do
if type(k) == "string" and string.match(k, "^"..name) then
local postfix = ""
if type(v) == "function" then postfix = "()"
elseif type(v) == "table" and getmetatable(v) and getmetatable(v).__call then postfix = "()"
elseif type(v) == "table" then postfix = "."
end
r[prefix..k..postfix] = true
end
end
local mt = getmetatable(t)
if t == env then mt = {__index=_ENV} end
if mt then
return findKeys(mt.__index, r, prefix, name)
end
end
local read_handler = {hint = function(line, index)
line = (line or "")
local tail = line:sub(index)
line = line:sub(1, index - 1)
local path = string.match(line, "[a-zA-Z_][a-zA-Z0-9_.]*$")
if not path then return nil end
local suffix = string.match(path, "[^.]+$") or ""
local prefix = string.sub(path, 1, #path - #suffix)
local tbl = findTable(env, prefix)
if not tbl then return nil end
local keys = {}
local hints = {}
findKeys(tbl, keys, string.sub(line, 1, #line - #suffix), suffix)
for key in pairs(keys) do
table.insert(hints, key .. tail)
end
return hints
end}
io.write("\27[37m".._VERSION .. " Copyright (C) 1994-2022 Lua.org, PUC-Rio\n")
io.write("\27[33mEnter a statement and hit enter to evaluate it.\n")
io.write("Prefix an expression with '=' to show its value.\n")
io.write("Press Ctrl+D to exit the interpreter.\n\27[37m")
while term.isAvailable() do
io.write(env._PROMPT)
local command = term.read(read_handler)
if not command then -- eof
return
end
local code, reason
if string.sub(command, 1, 1) == "=" then
code, reason = load("return " .. string.sub(command, 2), "=stdin", "t", env)
else
code, reason = load("return " .. command, "=stdin", "t", env)
if not code then
code, reason = load(command, "=stdin", "t", env)
end
end
if code then
local result = table.pack(xpcall(code, debug.traceback))
if not result[1] then
if type(result[2]) == "table" and result[2].reason == "terminated" then
os.exit(result[2].code)
end
io.stderr:write(tostring(result[2]) .. "\n")
else
local ok, why = pcall(function()
for i = 2, result.n do
io.write(require("serialization").serialize(result[i], true), i < result.n and "\t" or "\n")
end
end)
if not ok then
io.stderr:write("crashed serializing result: ", tostring(why))
end
end
else
io.stderr:write(tostring(reason) .. "\n")
end
end