MineOS/EFI/Full.lua
2022-05-17 14:59:00 +03:00

513 lines
9.1 KiB
Lua

local
stringsMineOSEFI,
stringsChangeLabel,
stringsKeyDown,
stringsComponentAdded,
stringsFilesystem,
stringsURLBoot,
componentProxy,
componentList,
pullSignal,
uptime,
tableInsert,
mathMax,
mathMin,
mathHuge,
mathFloor,
colorsTitle,
colorsBackground,
colorsText,
colorsSelectionBackground,
colorsSelectionText,
OSList,
bindGPUToScreen,
drawRectangle,
drawText,
newMenuElement,
runLoop,
drawCentrizedText,
drawTitle,
status,
executeString,
boot,
newMenuBackElement,
menu,
input,
internetExecute =
"MineOS EFI",
"Change label",
"key_down",
"component_added",
"filesystem",
"URL boot",
component.proxy,
component.list,
computer.pullSignal,
computer.uptime,
table.insert,
math.max,
math.min,
math.huge,
math.floor,
0x2D2D2D,
0xE1E1E1,
0x878787,
0x878787,
0xE1E1E1
local
eeprom,
gpu,
internetAddress =
componentProxy(componentList("eeprom")()),
componentProxy(componentList("gpu")()),
componentList("internet")()
local
gpuSet,
gpuSetBackground,
gpuFill,
eepromSetData,
eepromGetData,
screenWidth,
screenHeight =
gpu.set,
gpu.setBackground,
gpu.fill,
eeprom.setData,
eeprom.getData,
gpu.getResolution()
OSList,
bindGPUToScreen,
drawRectangle,
drawText,
newMenuElement,
runLoop,
drawCentrizedText,
drawTitle,
status,
executeString,
boot,
newMenuBackElement,
menu,
input,
internetExecute =
{
{
"/OS.lua"
},
{
"/init.lua",
function()
computer.getBootAddress, computer.setBootAddress = eepromGetData, eepromSetData
end
}
},
function()
local screenAddress = componentList("screen")()
if screenAddress then
gpu.bind(screenAddress, true)
end
end,
function(x, y, width, height, color)
gpuSetBackground(color)
gpuFill(x, y, width, height, " ")
end,
function(x, y, foreground, text)
gpu.setForeground(foreground)
gpuSet(x, y, text)
end,
function(text, callback, breakLoop)
return {
s = text,
c = callback,
b = breakLoop
}
end,
function(func, ...)
while func({ pullSignal(...) }) == nil do
end
end,
function(y, foreground, text)
drawText(mathFloor(screenWidth / 2 - #text / 2), y, foreground, text)
end,
function(y, title)
y = mathFloor(screenHeight / 2 - y / 2)
drawRectangle(1, 1, screenWidth, screenHeight, colorsBackground)
drawCentrizedText(y, colorsTitle, title)
return y + 2
end,
function(statusText, needWait)
local lines = {}
for line in statusText:gmatch("[^\r\n]+") do
lines[#lines + 1] = line:gsub("\t", " ")
end
local y = drawTitle(#lines, stringsMineOSEFI)
for i = 1, #lines do
drawCentrizedText(y, colorsText, lines[i])
y = y + 1
end
if needWait then
while pullSignal() ~= stringsKeyDown do
end
end
end,
function(...)
local result, reason = load(...)
if result then
result, reason = xpcall(result, debug.traceback)
if result then
return
end
end
status(reason, 1)
end,
function(proxy)
local OS
for i = 1, #OSList do
OS = OSList[i]
if proxy.exists(OS[1]) then
status("Booting from " .. (proxy.getLabel() or proxy.address))
-- Updating current EEPROM boot address if it's differs from given proxy address
if eepromGetData() ~= proxy.address then
eepromSetData(proxy.address)
end
-- Running OS pre-boot function
if OS[2] then
OS[2]()
end
-- Reading boot file
local handle, data, chunk, success, reason = proxy.open(OS[1], "rb"), ""
repeat
chunk = proxy.read(handle, mathHuge)
data = data .. (chunk or "")
until not chunk
proxy.close(handle)
-- Running boot file
executeString(data, "=" .. OS[1])
return 1
end
end
end,
function(f)
return newMenuElement("Back", f, 1)
end,
function(title, elements)
local selectedElement, maxLength = 1, 0
for i = 1, #elements do
maxLength = math.max(maxLength, #elements[i].s)
end
runLoop(function(e)
local y, x, text = drawTitle(#elements + 2, title)
for i = 1, #elements do
text = " " .. elements[i].s .. " "
x = mathFloor(screenWidth / 2 - #text / 2)
if i == selectedElement then
gpuSetBackground(colorsSelectionBackground)
drawText(x, y, colorsSelectionText, text)
gpuSetBackground(colorsBackground)
else
drawText(x, y, colorsText, text)
end
y = y + 1
end
if e[1] == stringsKeyDown then
if e[4] == 200 and selectedElement > 1 then
selectedElement = selectedElement - 1
elseif e[4] == 208 and selectedElement < #elements then
selectedElement = selectedElement + 1
elseif e[4] == 28 then
if elements[selectedElement].c then
elements[selectedElement].c()
end
if elements[selectedElement].b then
return 1
end
end
elseif e[1] == stringsComponentAdded and e[3] == "screen" then
bindGPUToScreen()
end
end)
end,
function(title, prefix)
local
y,
text,
state,
eblo,
char =
drawTitle(2, title),
"",
1
local function draw()
eblo = prefix .. text
gpuFill(1, y, screenWidth, 1, " ")
drawCentrizedText(y, colorsText, eblo .. (state and "_" or ""))
end
draw()
runLoop(
function(e)
if e[1] == stringsKeyDown then
if e[4] == 28 then
return 1
elseif e[4] == 14 then
text = text:sub(1, -2)
else
char = unicode.char(e[3])
if char:match("^[%w%d%p%s]+") then
text = text .. char
end
end
state = 1
elseif e[1] == "clipboard" then
text = text .. e[3]
elseif not e[1] then
state = not state
end
draw()
end,
0.5
)
return text
end,
function(url)
local
connection,
data,
result,
reason =
componentProxy(internetAddress).request(url),
""
if connection then
status("Downloading script")
while 1 do
result, reason = connection.read(mathHuge)
if result then
data = data .. result
else
connection.close()
if reason then
status(reason, 1)
else
executeString(data, "=url")
end
break
end
end
else
status("Invalid URL", 1)
end
end
bindGPUToScreen()
status("Hold Alt to show boot options")
-- Waiting 1 sec for user to press Alt key
local deadline, eventData = uptime() + 1
while uptime() < deadline do
eventData = { pullSignal(deadline - uptime()) }
if eventData[1] == stringsKeyDown and eventData[4] == 56 then
local utilities = {
newMenuElement("Disk utility", function()
local
restrict,
filesystems =
function(text, limit)
return (#text < limit and text .. string.rep(" ", limit - #text) or text:sub(1, limit)) .. " "
end,
{ newMenuBackElement() }
local function updateFilesystems()
for i = 2, #filesystems do
table.remove(filesystems, 1)
end
for address in componentList(stringsFilesystem) do
local proxy = componentProxy(address)
local
label,
isReadOnly =
proxy.getLabel() or "Unnamed",
proxy.isReadOnly()
tableInsert(filesystems, 1,
newMenuElement(
(address == eepromGetData() and "> " or " ") ..
restrict(label, 10) ..
restrict(proxy.spaceTotal() > 1048575 and "HDD" or proxy.spaceTotal() > 65535 and "FDD" or "SYS", 3) ..
restrict(isReadOnly and "R " or "R/W", 3) ..
restrict(math.ceil(proxy.spaceUsed() / proxy.spaceTotal() * 100) .. "%", 4) ..
address:sub(1, 8) .. "",
function()
local elements = {
newMenuElement(
"Set as bootable",
function()
eepromSetData(address)
updateFilesystems()
end,
1
),
newMenuBackElement()
}
if not isReadOnly then
tableInsert(elements, 2, newMenuElement(
stringsChangeLabel,
function()
pcall(proxy.setLabel, input(stringsChangeLabel, "New value: "))
updateFilesystems()
end,
1
))
tableInsert(elements, 3, newMenuElement(
"Erase",
function()
status("Erasing " .. address)
proxy.remove("")
updateFilesystems()
end,
1
))
end
menu(label .. " (" .. address .. ")", elements)
end
)
)
end
end
updateFilesystems()
menu("Select filesystem", filesystems)
end),
newMenuBackElement()
}
if internetAddress then
tableInsert(utilities, 2, newMenuElement("System recovery", function()
internetExecute("https://tinyurl.com/29urhz7z")
end))
tableInsert(utilities, 3, newMenuElement(stringsURLBoot, function()
internetExecute(input(stringsURLBoot, "Address: "))
end))
end
menu(stringsMineOSEFI, utilities)
end
end
-- Trying to boot from previously selected fs or from any available
local bootProxy = componentProxy(eepromGetData())
if not (bootProxy and boot(bootProxy)) then
local function tryBootFromAny()
for address in componentList(stringsFilesystem) do
bootProxy = componentProxy(address)
if boot(bootProxy) then
computer.shutdown()
else
bootProxy = nil
end
end
if not bootProxy then
status("Not boot sources found")
end
end
tryBootFromAny()
-- Waiting for any fs component available
runLoop(function(e)
if e[1] == stringsComponentAdded then
tryBootFromAny()
end
end)
end