From cbf25999f0abc49f85bc90dbe3827cd3b23f945e Mon Sep 17 00:00:00 2001 From: WahPlus Date: Sun, 17 Aug 2025 16:38:08 +0300 Subject: [PATCH] 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. --- .luarc.json | 104 +++++- halyde/apps/argentum.lua | 16 +- halyde/apps/boot.lua | 4 +- halyde/apps/cat.lua | 2 +- halyde/apps/cd.lua | 2 +- halyde/apps/cp.lua | 2 +- halyde/apps/download.lua | 4 +- halyde/apps/edit.lua | 8 +- halyde/apps/fetch.lua | 16 +- halyde/apps/help.lua | 2 +- halyde/apps/label.lua | 4 +- halyde/apps/ls.lua | 4 +- halyde/apps/lsdrv.lua | 8 +- halyde/apps/lua.lua | 4 +- halyde/apps/maindrv.lua | 2 +- halyde/apps/mkdir.lua | 2 +- halyde/apps/mv.lua | 2 +- halyde/apps/reboot.lua | 2 +- halyde/apps/resolution.lua | 0 halyde/apps/rm.lua | 2 +- halyde/apps/rtest.lua | 6 +- halyde/apps/rtest3d.lua | 8 +- halyde/apps/shutdown.lua | 2 +- halyde/config/shell.json | 2 +- halyde/config/startupapps.json | 2 +- halyde/core/boot.lua | 98 ------ halyde/core/cormgr.lua | 97 ------ halyde/core/drvload.lua | 46 --- halyde/core/fullkb.lua | 143 -------- halyde/core/termlib.lua | 453 ------------------------- halyde/kernel/boot.lua | 73 ++++ halyde/{core => kernel}/datatools.lua | 0 halyde/{core => kernel}/evmgr.lua | 32 +- halyde/kernel/modload.lua | 53 +++ halyde/kernel/modules/defenv.lua | 53 +++ halyde/kernel/modules/ipc.lua | 15 + halyde/kernel/modules/keyboard.lua | 157 +++++++++ halyde/kernel/modules/terminal.lua | 466 ++++++++++++++++++++++++++ halyde/kernel/tsched.lua | 149 ++++++++ halyde/{core => shell}/shell.lua | 26 +- halyde/system.log | 4 + home/test.lua | 7 + init.lua | 57 ++-- {halyde/lib => lib}/component.lua | 0 {halyde/lib => lib}/computer.lua | 0 {halyde/lib => lib}/event.lua | 2 +- {halyde/lib => lib}/filesystem.lua | 14 +- {halyde/lib => lib}/json.lua | 0 lib/log.lua | 30 ++ {halyde/lib => lib}/raster.lua | 2 +- {halyde/lib => lib}/serialize.lua | 0 {halyde/lib => lib}/unicode.lua | 0 52 files changed, 1232 insertions(+), 955 deletions(-) create mode 100644 halyde/apps/resolution.lua delete mode 100644 halyde/core/boot.lua delete mode 100644 halyde/core/cormgr.lua delete mode 100644 halyde/core/drvload.lua delete mode 100644 halyde/core/fullkb.lua delete mode 100644 halyde/core/termlib.lua create mode 100644 halyde/kernel/boot.lua rename halyde/{core => kernel}/datatools.lua (100%) rename halyde/{core => kernel}/evmgr.lua (57%) create mode 100644 halyde/kernel/modload.lua create mode 100644 halyde/kernel/modules/defenv.lua create mode 100644 halyde/kernel/modules/ipc.lua create mode 100644 halyde/kernel/modules/keyboard.lua create mode 100644 halyde/kernel/modules/terminal.lua create mode 100644 halyde/kernel/tsched.lua rename halyde/{core => shell}/shell.lua (83%) create mode 100644 halyde/system.log create mode 100644 home/test.lua rename {halyde/lib => lib}/component.lua (100%) rename {halyde/lib => lib}/computer.lua (100%) rename {halyde/lib => lib}/event.lua (97%) rename {halyde/lib => lib}/filesystem.lua (98%) rename {halyde/lib => lib}/json.lua (100%) create mode 100644 lib/log.lua rename {halyde/lib => lib}/raster.lua (99%) rename {halyde/lib => lib}/serialize.lua (100%) rename {halyde/lib => lib}/unicode.lua (100%) diff --git a/.luarc.json b/.luarc.json index 488c6fe..f472490 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,10 +1,100 @@ { - "diagnostics.globals": [ - "checkArg", - "computer", - "component" + "$schema": "https://raw.githubusercontent.com/LuaLS/lua-language-server/master/locale/en-us/setting.lua", + "runtime": { + "version": "Lua 5.3", + "special": {}, + "unicodeName": false, + "nonstandardSymbol": [] + }, + "workspace": { + "checkThirdParty": false, + "maxPreload": 5000, + "preloadFileSize": 500 + }, + "diagnostics": { + "disable": [ + "undefined-global", + "lowercase-global" ], - "diagnostics.disable": [ - "lowercase-global" + "globals": [ + "_G", + "_VERSION", + "assert", + "error", + "getmetatable", + "ipairs", + "load", + "next", + "pairs", + "pcall", + "rawequal", + "rawget", + "rawlen", + "rawset", + "select", + "setmetatable", + "tonumber", + "tostring", + "type", + "xpcall", + "checkArg", + "bit32", + "coroutine", + "debug", + "math", + "os", + "string", + "table", + "component", + "computer", + "unicode", + "utf8" ] -} \ No newline at end of file + }, + "completion": { + "enable": true, + "callSnippet": "Both", + "keywordSnippet": "Both", + "displayContext": 6 + }, + "hover": { + "enable": true, + "viewString": true, + "viewStringMax": 1000, + "viewNumber": true, + "fieldInfer": 3000, + "previewFields": 50, + "enumsLimit": 5 + }, + "semantic": { + "enable": true, + "variable": true, + "annotation": true, + "keyword": false + }, + "format": { + "enable": true, + "defaultConfig": { + "indent_style": "space", + "indent_size": "2", + "tab_width": "2" + } + }, + "spell": { + "dict": [] + }, + "telemetry": { + "enable": false + }, + "IntelliSense": { + "traceLocalSet": false, + "traceReturn": false, + "traceBeSetted": false, + "traceFieldInject": false + }, + "type": { + "castNumberToInteger": false, + "weakUnionCheck": false, + "weakNilCheck": false + } +} diff --git a/halyde/apps/argentum.lua b/halyde/apps/argentum.lua index 4edff50..a7367a7 100644 --- a/halyde/apps/argentum.lua +++ b/halyde/apps/argentum.lua @@ -1,9 +1,9 @@ local packages = {...} local command = packages[1] table.remove(packages, 1) -local fs = import("filesystem") -local component = import("component") -local agReg = import("/argentum/registry.cfg") +local fs = require("filesystem") +local component = require("component") +local agReg = require("/argentum/registry.cfg") if not command then shell.run("help argentum") return @@ -346,7 +346,7 @@ if command == "install" then else print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil")) end - agReg = import("/argentum/registry.cfg") + agReg = require("/argentum/registry.cfg") while true do if not doChecks(packages[i]) then table.insert(fails, packages[i]) @@ -497,7 +497,7 @@ elseif command == "update" then else print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil")) end - agReg = import("/argentum/registry.cfg") + agReg = require("/argentum/registry.cfg") if not packages[1] then local packagesInstalled = fs.list("/argentum/store/") for _, currentPackage in pairs(packagesInstalled) do @@ -632,7 +632,7 @@ elseif command == "info" then else print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil")) end - agReg = import("/argentum/registry.cfg") + agReg = require("/argentum/registry.cfg") if not agReg[packages[1]] and not source then print("\27[91mPackage " .. packages[1] .. " does not exist.") return @@ -656,7 +656,7 @@ elseif command == "search" then else print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil")) end - agReg = import("/argentum/registry.cfg") + agReg = require("/argentum/registry.cfg") local searchResults = {} for packageName, _ in pairs(agReg) do if packageName:find(packages[1], 1, true) then @@ -679,7 +679,7 @@ elseif command == "list" then else print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil")) end - agReg = import("/argentum/registry.cfg") + agReg = require("/argentum/registry.cfg") local sortedPackages = {} for packageName, _ in pairs(agReg) do table.insert(sortedPackages, packageName) diff --git a/halyde/apps/boot.lua b/halyde/apps/boot.lua index d08ef3d..80de81e 100644 --- a/halyde/apps/boot.lua +++ b/halyde/apps/boot.lua @@ -1,5 +1,5 @@ -local component = import("component") -local computer = import("computer") +local component = require("component") +local computer = require("computer") local args = {...} local force = false diff --git a/halyde/apps/cat.lua b/halyde/apps/cat.lua index 1c5dc93..2151914 100644 --- a/halyde/apps/cat.lua +++ b/halyde/apps/cat.lua @@ -1,5 +1,5 @@ local files = {...} -local fs = import("filesystem") +local fs = require("filesystem") if not files or not files[1] then shell.run("help cat") return diff --git a/halyde/apps/cd.lua b/halyde/apps/cd.lua index 72aee9e..5df313f 100644 --- a/halyde/apps/cd.lua +++ b/halyde/apps/cd.lua @@ -1,5 +1,5 @@ local directory = ... -local fs = import("filesystem") +local fs = require("filesystem") if not directory then return diff --git a/halyde/apps/cp.lua b/halyde/apps/cp.lua index ecd1316..9962779 100644 --- a/halyde/apps/cp.lua +++ b/halyde/apps/cp.lua @@ -1,5 +1,5 @@ local fromFile, toFile = ... -local fs = import("filesystem") +local fs = require("filesystem") if not fromFile or not toFile then shell.run("help cp") diff --git a/halyde/apps/download.lua b/halyde/apps/download.lua index 96fdd5b..5885055 100644 --- a/halyde/apps/download.lua +++ b/halyde/apps/download.lua @@ -1,7 +1,7 @@ local url = ... -local component = import("component") -local fs = import("filesystem") +local component = require("component") +local fs = require("filesystem") if not component.list("internet")() then print("\27[91mThis program requires an internet card to run.") diff --git a/halyde/apps/edit.lua b/halyde/apps/edit.lua index 467a5cf..1281f03 100644 --- a/halyde/apps/edit.lua +++ b/halyde/apps/edit.lua @@ -1,8 +1,8 @@ local file = ... -local fs = import("filesystem") -local event = import("event") -local component = import("component") -local unicode = import("unicode") +local fs = require("filesystem") +local event = require("event") +local component = require("component") +local unicode = require("unicode") local gpu = component.gpu local width, height = gpu.getResolution() local scrollPosX, scrollPosY = 1, 1 diff --git a/halyde/apps/fetch.lua b/halyde/apps/fetch.lua index add0a0d..eb71ae2 100644 --- a/halyde/apps/fetch.lua +++ b/halyde/apps/fetch.lua @@ -1,13 +1,13 @@ -local component = import("component") -local computer = import("computer") +local component = require("component") +local computer = require("computer") local function printstat(text) - termlib.cursorPosX = 35 - termlib.write(text .. "\n", false) + terminal.cursorPosX = 35 + terminal.write(text .. "\n", false) end -termlib.write(_OSLOGO, false) -termlib.cursorPosY = termlib.cursorPosY - 17 +terminal.write(_OSLOGO, false) +terminal.cursorPosY = terminal.cursorPosY - 17 printstat("\27[92mOS\27[0m: ".._OSVERSION) printstat("\27[92mArchitecture\27[0m: ".._VERSION) local componentCounter = 0 @@ -15,7 +15,7 @@ for _, _ in component.list() do componentCounter = componentCounter + 1 end printstat("\27[92mComponents\27[0m: "..tostring(componentCounter)) -printstat("\27[92mCoroutines\27[0m: "..tostring(#cormgr.corList)) +printstat("\27[92mCoroutines\27[0m: "..tostring(#tsched.getTasks())) printstat("\27[92mBattery\27[0m: "..tostring(math.floor(computer.energy() / computer.maxEnergy() * 1000 + 0.5) / 10).."%") local totalMemory = computer.totalMemory() local usedMemory = computer.totalMemory() - computer.freeMemory() @@ -67,4 +67,4 @@ local width, height = component.invoke(component.list("gpu")(), "getResolution") printstat("\27[92mResolution\27[0m: "..tostring(width).."x"..tostring(height).."\n") printstat("\27[40m \27[41m \27[42m \27[43m \27[44m \27[45m \27[46m \27[47m ") printstat("\27[100m \27[101m \27[102m \27[103m \27[104m \27[105m \27[106m \27[107m ") -termlib.cursorPosY = termlib.cursorPosY + 5 +terminal.cursorPosY = terminal.cursorPosY + 5 diff --git a/halyde/apps/help.lua b/halyde/apps/help.lua index 47cd216..0b27476 100644 --- a/halyde/apps/help.lua +++ b/halyde/apps/help.lua @@ -1,4 +1,4 @@ -local fs = import("filesystem") +local fs = require("filesystem") local args = {...} local command = args[1] args = nil diff --git a/halyde/apps/label.lua b/halyde/apps/label.lua index 0c12ee4..2ed358e 100644 --- a/halyde/apps/label.lua +++ b/halyde/apps/label.lua @@ -1,5 +1,5 @@ -local component = import("component") -local computer = import("computer") +local component = require("component") +local computer = require("computer") local args = {...} if not args then return print("\x1b[91mCannot get arguments.") end if not args[1] then diff --git a/halyde/apps/ls.lua b/halyde/apps/ls.lua index f7149b8..e7e7fe0 100644 --- a/halyde/apps/ls.lua +++ b/halyde/apps/ls.lua @@ -1,8 +1,8 @@ local args = {...} local target = args[1] args = nil -local fs = import("filesystem") -local unicode = import("unicode") +local fs = require("filesystem") +local unicode = require("unicode") local maxLength = 0 local margin = 2 -- minimum space between filename and size local dirTable = {} diff --git a/halyde/apps/lsdrv.lua b/halyde/apps/lsdrv.lua index 55133fb..a392c7f 100644 --- a/halyde/apps/lsdrv.lua +++ b/halyde/apps/lsdrv.lua @@ -1,7 +1,7 @@ -local serialize = import("serialize") -local component = import("component") -local computer = import("computer") -local unicode = import("unicode") +local serialize = require("serialize") +local component = require("component") +local computer = require("computer") +local unicode = require("unicode") local width,height = component.gpu.getResolution() diff --git a/halyde/apps/lua.lua b/halyde/apps/lua.lua index 03629f6..251f1ee 100644 --- a/halyde/apps/lua.lua +++ b/halyde/apps/lua.lua @@ -1,13 +1,13 @@ print("\27[44m".._VERSION.."\27[0m shell") print('Type "exit" to exit.') termlib.readHistory["lua"] = {""} -local fs = import("filesystem") +local fs = require("filesystem") local loadedLibraries = "" local libList = fs.list("halyde/lib") for _, lib in pairs(libList) do if lib:match("(.+)%.lua") then - loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = import("' .. lib:match("(.+)%.lua") .. '")\n' + loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = require("' .. lib:match("(.+)%.lua") .. '")\n' end end diff --git a/halyde/apps/maindrv.lua b/halyde/apps/maindrv.lua index 74aaf2a..561f213 100644 --- a/halyde/apps/maindrv.lua +++ b/halyde/apps/maindrv.lua @@ -1,4 +1,4 @@ -local computer = import("computer") +local computer = require("computer") if type(computer)~="table" then return print("\x1b[91mComputer library returned '"..type(computer).."' type\x1b[39m") diff --git a/halyde/apps/mkdir.lua b/halyde/apps/mkdir.lua index b1a8c1a..39eb0be 100644 --- a/halyde/apps/mkdir.lua +++ b/halyde/apps/mkdir.lua @@ -1,5 +1,5 @@ local directory = ... -local fs = import("filesystem") +local fs = require("filesystem") if not directory then shell.run("help mkdir") diff --git a/halyde/apps/mv.lua b/halyde/apps/mv.lua index 6ffd880..d974660 100644 --- a/halyde/apps/mv.lua +++ b/halyde/apps/mv.lua @@ -1,5 +1,5 @@ local fromFile, toFile = ... -local fs = import("filesystem") +local fs = require("filesystem") if not fromFile or not toFile then shell.run("help mv") diff --git a/halyde/apps/reboot.lua b/halyde/apps/reboot.lua index a11869a..af9b0cd 100644 --- a/halyde/apps/reboot.lua +++ b/halyde/apps/reboot.lua @@ -1 +1 @@ -import("computer").shutdown(true) +require("computer").shutdown(true) diff --git a/halyde/apps/resolution.lua b/halyde/apps/resolution.lua new file mode 100644 index 0000000..e69de29 diff --git a/halyde/apps/rm.lua b/halyde/apps/rm.lua index f83b695..d8fa1a9 100644 --- a/halyde/apps/rm.lua +++ b/halyde/apps/rm.lua @@ -1,5 +1,5 @@ local file = ... -local fs = import("filesystem") +local fs = require("filesystem") if not file then shell.run("help rm") diff --git a/halyde/apps/rtest.lua b/halyde/apps/rtest.lua index 825e54f..d5b202c 100644 --- a/halyde/apps/rtest.lua +++ b/halyde/apps/rtest.lua @@ -1,4 +1,4 @@ -local raster = import("raster") +local raster = require("raster") raster.init() @@ -15,7 +15,7 @@ end]] end end ]] -local event = import("event") +local event = require("event") local x=0 local y=0 local vx=1 @@ -88,4 +88,4 @@ end end ]] raster.free() -termlib.cursorPosY=1 \ No newline at end of file +termlib.cursorPosY=1 diff --git a/halyde/apps/rtest3d.lua b/halyde/apps/rtest3d.lua index 62c0c2c..b8a8702 100644 --- a/halyde/apps/rtest3d.lua +++ b/halyde/apps/rtest3d.lua @@ -1,7 +1,7 @@ -local component = import("component") -local computer = import("computer") -local raster = import("raster") -local event = import("event") +local component = require("component") +local computer = require("computer") +local raster = require("raster") +local event = require("event") -- Initialize the 3D renderer for a spinning cube -- Using the raster library for drawing diff --git a/halyde/apps/shutdown.lua b/halyde/apps/shutdown.lua index d2544dc..6c79ab6 100644 --- a/halyde/apps/shutdown.lua +++ b/halyde/apps/shutdown.lua @@ -1 +1 @@ -import("computer").shutdown() +require("computer").shutdown() diff --git a/halyde/config/shell.json b/halyde/config/shell.json index 4bed850..f1f250d 100644 --- a/halyde/config/shell.json +++ b/halyde/config/shell.json @@ -1 +1 @@ -{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls","ps":"lscor","poweroff":"shutdown","restart":"reboot","lsblk":"lsdrv"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ %s\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"} +{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls","ps":"lscor","poweroff":"shutdown","restart":"reboot","lsblk":"lsdrv"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!","Now i% more secure!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ %s\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"} diff --git a/halyde/config/startupapps.json b/halyde/config/startupapps.json index 5609ad6..3597354 100644 --- a/halyde/config/startupapps.json +++ b/halyde/config/startupapps.json @@ -1 +1 @@ -["/halyde/core/fullkb.lua","/halyde/core/evmgr.lua","/halyde/core/drvload.lua","/halyde/core/shell.lua"] +["/halyde/shell/shell.lua"] diff --git a/halyde/core/boot.lua b/halyde/core/boot.lua deleted file mode 100644 index 0405c25..0000000 --- a/halyde/core/boot.lua +++ /dev/null @@ -1,98 +0,0 @@ -local loadfile = ... -local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile) - -_G._OSVERSION = "Halyde 2.8.1" -_G._OSLOGO = "" -local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil -repeat - tmpdata = handle:read(math.huge) - _OSLOGO = _OSLOGO .. (tmpdata or "") -until not tmpdata - -_G.package = {["preloaded"] = {}} - -loadfile("/halyde/core/datatools.lua")() - -function _G.import(module, ...) - local args = table.pack(...) - if package.preloaded[module] then - return package.preloaded[module] - end - local modulepath - if filesystem.exists(module) then - modulepath = module - elseif filesystem.exists("/halyde/lib/"..module..".lua") then - modulepath = "/halyde/lib/"..module..".lua" - elseif shell and shell.workingDirectory and filesystem.exists(shell.workingDirectory..module) then - modulepath = shell.workingDirectory..module - end - assert(modulepath, "module not found\npossible locations:\n/halyde/lib/"..module..".lua") - local handle, data, tmpdata = filesystem.open(modulepath), "", nil - repeat - tmpdata = handle:read(math.huge or math.maxinteger) - data = data .. (tmpdata or "") - until not tmpdata - handle:close() - return(assert(load(data, "="..modulepath))(table.unpack(args))) -end - -local function preload(module) - local handle, data, tmpdata = assert(filesystem.open("/halyde/lib/" .. module .. ".lua", "r")), "", nil - repeat - tmpdata = handle:read(math.huge or math.maxinteger) - data = data .. (tmpdata or "") - until not tmpdata - package.preloaded[module] = assert(load(data, "="..module))() - _G[module] = nil -end - -preload("component") -preload("computer") -preload("filesystem") - -local component = import("component") -local gpu = component.gpu -local screenAddress = component.list("screen")() ---local screen = component.screen - -gpu.bind(screenAddress) ---local maxWidth, maxHeight = gpu.maxResolution() ---local aspectX, aspectY = screen.getAspectRatio() ---local screenRatio = aspectX * 2 / aspectY - --- Calculate potential dimensions ---local widthLimited = math.floor(maxHeight * screenRatio) ---local heightLimited = math.floor(maxWidth / screenRatio) - ---local targetWidth, targetHeight - ---if widthLimited <= maxWidth then - -- height is the limiting factor --- targetWidth = widthLimited --- targetHeight = maxHeight ---else - -- width is the limiting factor --- targetWidth = maxWidth --- targetHeight = heightLimited ---end - ---targetWidth = math.min(targetWidth, maxWidth) ---targetHeight = math.min(targetHeight, maxHeight) - ---gpu.setResolution(targetWidth, targetHeight) -gpu.setResolution(gpu.maxResolution()) - ---local handle = assert(filesystem.open("/bazinga.txt", "w")) ---assert(handle:write("Bazinga!")) ---handle:close() - -local fs = import("filesystem") -if not fs.exists("/halyde/config/shell.json") then -- Auto-generate configs - fs.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json") -end -if not fs.exists("/halyde/config/startupapps.json") then - fs.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json") -end -fs = nil - -import("/halyde/core/cormgr.lua") diff --git a/halyde/core/cormgr.lua b/halyde/core/cormgr.lua deleted file mode 100644 index 7049fa3..0000000 --- a/halyde/core/cormgr.lua +++ /dev/null @@ -1,97 +0,0 @@ -_G.cormgr = {} -_G.cormgr.corList = {} -_G.cormgr.labelList = {} - -local component = import("component") -local filesystem = import("filesystem") -local json = import("json") -local gpu = component.gpu ---local ocelot = component.ocelot - -function _G.cormgr.loadCoroutine(path,...) - local args = {...} - local function corFunction() - local result, errorMessage = xpcall(function(...) - import(...) - end, function(errorMessage) - return errorMessage .. "\n \n" .. debug.traceback() - end, path, table.unpack(args)) - if not result then - if print then - gpu.freeAllBuffers() - print("\n\27[91m" .. errorMessage) - else - error(errorMessage) - end - end - --import(path, table.unpack(args)) - end - cormgr.addCoroutine(corFunction, string.match(tostring(path), "([^/]+)%.lua$")) -end - -function _G.cormgr.addCoroutine(func, name) - local cor = coroutine.create(func) - table.insert(cormgr.corList, cor) - table.insert(cormgr.labelList, name) - return cor -end - -function _G.cormgr.removeCoroutine(name) - local index = table.find(cormgr.labelList, cor) - table.remove(cormgr.corList, index) - table.remove(cormgr.labelList, index) - --coroutine.close(cor) -end - -function handleError(errormsg) - if errormsg == nil then - error("unknown error") - else - error(tostring(errormsg).."\n \n"..debug.traceback()) - end -end - -local function runCoroutines() - for i = 1, #_G.cormgr.corList do - if cormgr.corList[i] then - local result, errorMessage = coroutine.resume(cormgr.corList[i]) - if cormgr.corList[i] then - if not result then - handleError(errorMessage) - end - if coroutine.status(cormgr.corList[i]) == "dead" then - table.remove(cormgr.corList, i) - table.remove(cormgr.labelList, i) - --ocelot.log("Removed coroutine") - i = i - 1 - end - --computer.pullSignal(0) - --coroutine.yield() - end - end - end -end - -local handle, data, tmpdata = filesystem.open("/halyde/config/startupapps.json", "r"), "", nil -repeat - tmpdata = handle:read(math.huge or math.maxinteger) - data = data .. (tmpdata or "") -until not tmpdata -handle:close() -for _, line in ipairs(json.decode(data)) do - if line ~= "" then - --[[ if _G.print then - print(line) - end ]] - _G.cormgr.loadCoroutine(line) - runCoroutines() - end -end --- _G.cormgr.loadCoroutine("/halyde/core/shell.lua") - -while true do - runCoroutines() - if #_G.cormgr.corList == 0 then - computer.shutdown() - end -end diff --git a/halyde/core/drvload.lua b/halyde/core/drvload.lua deleted file mode 100644 index 441b091..0000000 --- a/halyde/core/drvload.lua +++ /dev/null @@ -1,46 +0,0 @@ -local fs = import("filesystem") - -local driverPath = "/halyde/drivers" - -local drivers = fs.list(driverPath) -local driverTypes = {} - -local function loadDriver(drvName) - local driverData = import(fs.concat(driverPath, drvName)) - table.remove(drivers, table.find(drivers, drvName)) - if driverData.dependencies then - for _, dependency in pairs(driverData.dependencies) do - if table.find(drivers, dependency) then - loadDriver(dependency) - elseif table.find(drivers, dependency .. ".lua") then - loadDriver(dependency .. ".lua") - else - for typeLookupDrvName, typeLookupDrvType in pairs(driverTypes) do - if typeLookupDrvType == dependency then - loadDriver(typeLookupDrvName) - -- Don't break, because there can be multiple drivers of the correct type - end - end - end - end - end - --print(drvName) - if driverData.onStartup then -- I have no idea why would this not exist, but it's a failsafe - driverData.onStartup() - end - -- More functions to be implemented in the future -end - -for _, drvName in pairs(drivers) do -- Get all the driver types - local driverData = import(fs.concat(driverPath, drvName)) - if driverData.type then - --print(driverData.type) - driverTypes[drvName] = driverData.type -- Not the other way around because there can be multiple drivers of the same type, but there can't be multiple entries with the same key - end -end - -for _, drvName in pairs(drivers) do -- Load the drivers - if drvName:sub(-1, -1) ~= "/" then -- Check if it's not a directory. Otherwise it might be driver config - loadDriver(drvName) - end -end diff --git a/halyde/core/fullkb.lua b/halyde/core/fullkb.lua deleted file mode 100644 index e9c64de..0000000 --- a/halyde/core/fullkb.lua +++ /dev/null @@ -1,143 +0,0 @@ -_G.keyboard = {["keys"] = {}} - -keyboard.keys["1"] = 0x02 -keyboard.keys["2"] = 0x03 -keyboard.keys["3"] = 0x04 -keyboard.keys["4"] = 0x05 -keyboard.keys["5"] = 0x06 -keyboard.keys["6"] = 0x07 -keyboard.keys["7"] = 0x08 -keyboard.keys["8"] = 0x09 -keyboard.keys["9"] = 0x0A -keyboard.keys["0"] = 0x0B -keyboard.keys.a = 0x1E -keyboard.keys.b = 0x30 -keyboard.keys.c = 0x2E -keyboard.keys.d = 0x20 -keyboard.keys.e = 0x12 -keyboard.keys.f = 0x21 -keyboard.keys.g = 0x22 -keyboard.keys.h = 0x23 -keyboard.keys.i = 0x17 -keyboard.keys.j = 0x24 -keyboard.keys.k = 0x25 -keyboard.keys.l = 0x26 -keyboard.keys.m = 0x32 -keyboard.keys.n = 0x31 -keyboard.keys.o = 0x18 -keyboard.keys.p = 0x19 -keyboard.keys.q = 0x10 -keyboard.keys.r = 0x13 -keyboard.keys.s = 0x1F -keyboard.keys.t = 0x14 -keyboard.keys.u = 0x16 -keyboard.keys.v = 0x2F -keyboard.keys.w = 0x11 -keyboard.keys.x = 0x2D -keyboard.keys.y = 0x15 -keyboard.keys.z = 0x2C - -keyboard.keys.apostrophe = 0x28 -keyboard.keys.at = 0x91 -keyboard.keys.back = 0x0E -- backspace -keyboard.keys.backslash = 0x2B -keyboard.keys.capital = 0x3A -- capslock -keyboard.keys.colon = 0x92 -keyboard.keys.comma = 0x33 -keyboard.keys.enter = 0x1C -keyboard.keys.equals = 0x0D -keyboard.keys.grave = 0x29 -- accent grave -keyboard.keys.lbracket = 0x1A -keyboard.keys.lcontrol = 0x1D -keyboard.keys.lmenu = 0x38 -- left Alt -keyboard.keys.lshift = 0x2A -keyboard.keys.minus = 0x0C -keyboard.keys.numlock = 0x45 -keyboard.keys.pause = 0xC5 -keyboard.keys.period = 0x34 -keyboard.keys.rbracket = 0x1B -keyboard.keys.rcontrol = 0x9D -keyboard.keys.rmenu = 0xB8 -- right Alt -keyboard.keys.rshift = 0x36 -keyboard.keys.scroll = 0x46 -- Scroll Lock -keyboard.keys.semicolon = 0x27 -keyboard.keys.slash = 0x35 -- / on main keyboard -keyboard.keys.space = 0x39 -keyboard.keys.stop = 0x95 -keyboard.keys.tab = 0x0F -keyboard.keys.underline = 0x93 - --- Keypad (and numpad with numlock off) -keyboard.keys.up = 0xC8 -keyboard.keys.down = 0xD0 -keyboard.keys.left = 0xCB -keyboard.keys.right = 0xCD -keyboard.keys.home = 0xC7 -keyboard.keys["end"] = 0xCF -keyboard.keys.pageUp = 0xC9 -keyboard.keys.pageDown = 0xD1 -keyboard.keys.insert = 0xD2 -keyboard.keys.delete = 0xD3 - --- Function keys -keyboard.keys.f1 = 0x3B -keyboard.keys.f2 = 0x3C -keyboard.keys.f3 = 0x3D -keyboard.keys.f4 = 0x3E -keyboard.keys.f5 = 0x3F -keyboard.keys.f6 = 0x40 -keyboard.keys.f7 = 0x41 -keyboard.keys.f8 = 0x42 -keyboard.keys.f9 = 0x43 -keyboard.keys.f10 = 0x44 -keyboard.keys.f11 = 0x57 -keyboard.keys.f12 = 0x58 -keyboard.keys.f13 = 0x64 -keyboard.keys.f14 = 0x65 -keyboard.keys.f15 = 0x66 -keyboard.keys.f16 = 0x67 -keyboard.keys.f17 = 0x68 -keyboard.keys.f18 = 0x69 -keyboard.keys.f19 = 0x71 - --- Japanese keyboards -keyboard.keys.kana = 0x70 -keyboard.keys.kanji = 0x94 -keyboard.keys.convert = 0x79 -keyboard.keys.noconvert = 0x7B -keyboard.keys.yen = 0x7D -keyboard.keys.circumflex = 0x90 -keyboard.keys.ax = 0x96 - --- Numpad -keyboard.keys.numpad0 = 0x52 -keyboard.keys.numpad1 = 0x4F -keyboard.keys.numpad2 = 0x50 -keyboard.keys.numpad3 = 0x51 -keyboard.keys.numpad4 = 0x4B -keyboard.keys.numpad5 = 0x4C -keyboard.keys.numpad6 = 0x4D -keyboard.keys.numpad7 = 0x47 -keyboard.keys.numpad8 = 0x48 -keyboard.keys.numpad9 = 0x49 -keyboard.keys.numpadmul = 0x37 -keyboard.keys.numpaddiv = 0xB5 -keyboard.keys.numpadsub = 0x4A -keyboard.keys.numpadadd = 0x4E -keyboard.keys.numpaddecimal = 0x53 -keyboard.keys.numpadcomma = 0xB3 -keyboard.keys.numpadenter = 0x9C -keyboard.keys.numpadequals = 0x8D - --- Create inverse mapping for name lookup. -setmetatable(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 -}) diff --git a/halyde/core/termlib.lua b/halyde/core/termlib.lua deleted file mode 100644 index 1d1e74b..0000000 --- a/halyde/core/termlib.lua +++ /dev/null @@ -1,453 +0,0 @@ -local serialize = import("serialize") -local unicode = import("unicode") -local event = import("event") ---local keyboard = import("keyboard") - ---local ocelot = component.proxy(component.list("ocelot")()) -local component = import("component") -local computer = import("computer") -local gpu = component.gpu -_G.termlib = {} -termlib.cursorPosX = 1 -termlib.cursorPosY = 1 -termlib.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) - termlib.cursorPosY=height - end -end - -local function newLine() - termlib.cursorPosX=1 - termlib.cursorPosY = termlib.cursorPosY + 1 - if termlib.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 termlib.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(termlib.cursorPosX,termlib.cursorPosY,section) - if unicode.wlen(section) > width - termlib.cursorPosX + 1 and textWrap then - section = section:sub(width - termlib.cursorPosX + 2) - newLine() - else - termlib.cursorPosX = termlib.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() - termlib.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(termlib.cursorPosX,termlib.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 - termlib.write(table.concat(stringArgs, " ") .. "\n") -end - -function _G.clear() - width, height = gpu.getResolution() - gpu.setForeground(defaultForegroundColor) - gpu.setBackground(defaultBackgroundColor) - gpu.fill(1,1,width,height," ") - termlib.cursorPosX, termlib.cursorPosY = 1, 1 -end - -function _G.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 termlib.readHistory[readHistoryType] then - termlib.readHistory[readHistoryType] = {text} - elseif termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType] ] ~= "" then - table.insert(termlib.readHistory[readHistoryType], text) - end - historyIdx = #termlib.readHistory[readHistoryType] - end - - local function updateHistory() - if not readHistoryType then return end - termlib.readHistory[readHistoryType][historyIdx]=text - end - - local cur = unicode.len(text)+1 - if prefix then termlib.write(prefix) end - local startX, startY = termlib.cursorPosX, termlib.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 maxChars1 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 termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType]]=="" then - table.remove(termlib.readHistory[readHistoryType],#termlib.readHistory[readHistoryType]) - end - if historyIdx<#termlib.readHistory[readHistoryType] then - table.remove(termlib.readHistory[readHistoryType],historyIdx) - table.insert(termlib.readHistory[readHistoryType],text) - end - while #termlib.readHistory[readHistoryType] > 50 do - table.remove(termlib.readHistory[readHistoryType], 1) - end - end - - termlib.cursorPosX=1 - termlib.cursorPosY=termlib.cursorPosY+math.ceil((unicode.wlen(text)+startX-1)/width) - if termlib.cursorPosY>height then scrollDown() end - - return text -end diff --git a/halyde/kernel/boot.lua b/halyde/kernel/boot.lua new file mode 100644 index 0000000..27c5c41 --- /dev/null +++ b/halyde/kernel/boot.lua @@ -0,0 +1,73 @@ +local loadfile = ... +local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile)) +_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file +_G._OSLOGO = "" +_G._PUBLIC = {} +local ocelot = component.proxy(component.list("ocelot")()) + +local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil +repeat + tmpdata = handle:read(math.huge) + _OSLOGO = _OSLOGO .. (tmpdata or "") +until not tmpdata + +_G.package = {["preloaded"] = {}} + +loadfile("/halyde/kernel/modules/datatools.lua")() + +function _G.require(module, ...) + ocelot.log("Requiring " .. module) + local args = table.pack(...) + if package.preloaded[module] then + return package.preloaded[module] + end + local modulepath + if filesystem.exists(module) then + modulepath = module + elseif filesystem.exists("/lib/" .. module .. ".lua") then + modulepath = "/lib/" .. module .. ".lua" + elseif shell and shell.workingDirectory and filesystem.exists(filesystem.concat(shell.workingDirectory, module .. ".lua")) then + modulepath = shell.workingDirectory .. module .. ".lua" + end + assert(modulepath, "Module not found\nPossible locations:\n/lib/" .. module .. ".lua") + local handle, data, tmpdata = filesystem.open(modulepath), "", nil + repeat + tmpdata = handle:read(math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + handle:close() + return(assert(load(data, "="..modulepath))(table.unpack(args))) +end + +function _G.package.preload(module) + local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil + repeat + tmpdata = handle:read(math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + handle:close() + package.preloaded[module] = assert(load(data, "="..module))() + _G[module] = nil +end + +require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. +require("/halyde/kernel/modload.lua") + +package.preload("component") +package.preload("computer") + +local component = require("component") +local gpu = component.gpu +local screenAddress = component.list("screen")() + +gpu.bind(screenAddress) +gpu.setResolution(gpu.maxResolution()) + +if not filesystem.exists("/halyde/config/shell.json") then -- Auto-generate configs + filesystem.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json") +end +if not filesystem.exists("/halyde/config/startupapps.json") then + filesystem.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json") +end + +require("/halyde/kernel/tsched.lua") diff --git a/halyde/core/datatools.lua b/halyde/kernel/datatools.lua similarity index 100% rename from halyde/core/datatools.lua rename to halyde/kernel/datatools.lua diff --git a/halyde/core/evmgr.lua b/halyde/kernel/evmgr.lua similarity index 57% rename from halyde/core/evmgr.lua rename to halyde/kernel/evmgr.lua index 7fb252f..861cfa1 100644 --- a/halyde/core/evmgr.lua +++ b/halyde/kernel/evmgr.lua @@ -2,11 +2,11 @@ _G.evmgr = {} _G.evmgr.eventQueue = {} local maxEventQueueLength = 10 -- increase if events start getting dropped -local computer = import("computer") +local computer = require("computer") -keyboard.ctrlDown = false -keyboard.altDown = false -keyboard.shiftDown = false +_G._PUBLIC.keyboard.ctrlDown = false +_G._PUBLIC.keyboard.altDown = false +_G._PUBLIC.keyboard.shiftDown = false --local ocelot = component.proxy(component.list("ocelot")()) @@ -16,31 +16,31 @@ while true do args = {computer.uptime(), computer.pullSignal(0)} if args and args[2] then table.insert(evmgr.eventQueue, args) - if keyboard then + if _PUBLIC.keyboard then if args[2] == "key_down" then local keycode = args[5] - local key = keyboard.keys[keycode] + local key = _PUBLIC.keyboard.keys[keycode] if key == "lcontrol" then - keyboard.ctrlDown = true + _PUBLIC.keyboard.ctrlDown = true elseif key == "lmenu" then - keyboard.altDown = true + _PUBLIC.keyboard.altDown = true elseif key == "lshift" then - keyboard.shiftDown = true - elseif key == "c" and keyboard.ctrlDown and keyboard.altDown then + _PUBLIC.keyboard.shiftDown = true + elseif key == "c" and _PUBLIC.keyboard.ctrlDown and _PUBLIC.keyboard.altDown then if print then - print("\n\27[91mCoroutine "..tostring(#cormgr.corList).." killed.") + print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.") end - cormgr.corList[#cormgr.corList] = nil + tsched.tasks[#tsched.tasks] = nil end elseif args[2] == "key_up" then local keycode = args[5] - local key = keyboard.keys[keycode] + local key = _PUBLIC.keyboard.keys[keycode] if key == "lcontrol" then - keyboard.ctrlDown = false + _PUBLIC.keyboard.ctrlDown = false elseif key == "lmenu" then - keyboard.altDown = false + _PUBLIC.keyboard.altDown = false elseif key == "lshift" then - keyboard.shiftDown = true + _PUBLIC.keyboard.shiftDown = true end end end diff --git a/halyde/kernel/modload.lua b/halyde/kernel/modload.lua new file mode 100644 index 0000000..6aa7dfa --- /dev/null +++ b/halyde/kernel/modload.lua @@ -0,0 +1,53 @@ +local fs = require("filesystem") +local ocelot = require("component").ocelot + +local modulePath = "/halyde/kernel/modules" + +local modules = fs.list(modulePath) +local moduleTypes = {} + +local function loadModule(modName) + ocelot.log("Checking module " .. modName) + local moduleData = require(fs.concat(modulePath, modName)) + table.remove(modules, table.find(modules, modName)) + if not moduleData.check() then + return + end + ocelot.log("Loading module " .. modName) + if moduleData.dependencies then + for _, dependency in pairs(moduleData.dependencies) do + if table.find(modules, dependency) then + loadModule(dependency) + elseif table.find(modules, dependency .. ".lua") then + loadModule(dependency .. ".lua") + else + for typeLookupDrvName, typeLookupDrvType in pairs(moduleTypes) do + if typeLookupDrvType == dependency then + loadModule(typeLookupDrvName) + -- Don't break, because there can be multiple modules of the correct type + end + end + end + end + end + --print(modName) + if moduleData.init then -- I have no idea why this would not exist, but it's a failsafe + moduleData.init() + end +end + +for _, modName in pairs(modules) do -- Get all the module types + local moduleData = require(fs.concat(modulePath, modName)) + if moduleData.type then + --print(moduleData.type) + moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key + end +end + +while modules[1] do + if modules[1]:sub(-1, -1) ~= "/" then -- Check if it's not a directory. If it is, it might be module config + loadModule(modules[1]) + end +end + +ocelot.log("Finished loading modules!") diff --git a/halyde/kernel/modules/defenv.lua b/halyde/kernel/modules/defenv.lua new file mode 100644 index 0000000..a3ab3a5 --- /dev/null +++ b/halyde/kernel/modules/defenv.lua @@ -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 diff --git a/halyde/kernel/modules/ipc.lua b/halyde/kernel/modules/ipc.lua new file mode 100644 index 0000000..fbdbec7 --- /dev/null +++ b/halyde/kernel/modules/ipc.lua @@ -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 diff --git a/halyde/kernel/modules/keyboard.lua b/halyde/kernel/modules/keyboard.lua new file mode 100644 index 0000000..d20850d --- /dev/null +++ b/halyde/kernel/modules/keyboard.lua @@ -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 diff --git a/halyde/kernel/modules/terminal.lua b/halyde/kernel/modules/terminal.lua new file mode 100644 index 0000000..2d8fc94 --- /dev/null +++ b/halyde/kernel/modules/terminal.lua @@ -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 maxChars1 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 diff --git a/halyde/kernel/tsched.lua b/halyde/kernel/tsched.lua new file mode 100644 index 0000000..865a1eb --- /dev/null +++ b/halyde/kernel/tsched.lua @@ -0,0 +1,149 @@ +_G._PUBLIC.tsched = {} +_G.tsched = {} +_G.tsched.tasks = {} + +local currentTask + +local component = require("component") +local computer = require("computer") +local filesystem = require("filesystem") +local json = require("json") +local gpu = component.gpu +local ocelot = component.ocelot + +function _G._PUBLIC.tsched.runAsTask(path,...) + local args = {...} + local function taskFunction() + local result, errorMessage = xpcall(function(...) + local args = table.pack(...) + if not filesystem.exists(path) then + error("No such file: " .. path) + end + local handle, data, tmpdata = filesystem.open(path), "", nil + repeat + tmpdata = handle:read(math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + handle:close() + + -- Userland environment definition + local userland = table.copy(_PUBLIC) + userland._G = userland + + assert(load(data, "="..path, "t", userland))(table.unpack(args)) + end, function(errorMessage) + return errorMessage .. "\n \n" .. debug.traceback() + end, path, table.unpack(args)) + if not result then + if print then + gpu.freeAllBuffers() + print("\n\27[91m" .. errorMessage) + else + error(errorMessage) + end + end + --require(path, table.unpack(args)) + end + _PUBLIC.tsched.addTask(taskFunction, string.match(tostring(path), "([^/]+)%.lua$")) +end + +function _G._PUBLIC.tsched.addTask(func, name) + ocelot.log("Added task " .. name) + local task = coroutine.create(func) + table.insert(tsched.tasks, {["task"] = task, ["name"] = name}) + return task +end + +function _G._PUBLIC.tsched.removeTask(id) + -- TODO: Check for user permissions before running + table.remove(_G.tsched.tasks, id) +end + +function handleError(errormsg) + if errormsg == nil then -- TODO: Replace with proper error handling (if this isn't considered proper..?) + print("\27[91munknown error" .. "\n \n" .. debug.traceback()) + else + print("\27[91m" .. tostring(errormsg) .. "\n \n" .. debug.traceback()) + end +end + +local function runTasks() + for i = 1, #_G.tsched.tasks do + if tsched.tasks[i] then + currentTask = tsched.tasks[i] + local result, errorMessage = coroutine.resume(tsched.tasks[i].task) + if not result then + handleError(errorMessage) + end + if coroutine.status(tsched.tasks[i].task) == "dead" then + _PUBLIC.tsched.removeTask(i) + --ocelot.log("Removed coroutine") + i = i - 1 + end + --computer.pullSignal(0) + --coroutine.yield() + end + end +end + +function _G._PUBLIC.tsched.getCurrentTask() + return table.copy(currentTask) +end + +function _G._PUBLIC.tsched.getTasks() + return table.copy(tsched.tasks) +end + +local function taskFunction() + local result, errorMessage = xpcall(function() + if not filesystem.exists("/halyde/kernel/evmgr.lua") then + error("No such file: /halyde/kernel/evmgr.lua") + end + local handle, data, tmpdata = filesystem.open("/halyde/kernel/evmgr.lua"), "", nil + repeat + tmpdata = handle:read(math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + handle:close() + assert(load(data, "=/halyde/kernel/evmgr.lua"))() + end, function(errorMessage) + return errorMessage .. "\n \n" .. debug.traceback() + end, "/halyde/kernel/evmgr.lua") + if not result then + if print then + gpu.freeAllBuffers() + print("\n\27[91m" .. errorMessage) + else + error(errorMessage) + end + end +end +_PUBLIC.tsched.addTask(taskFunction, "evmgr") +package.preload("event") + +local handle, data, tmpdata = filesystem.open("/halyde/config/startupapps.json", "r"), "", nil +repeat + tmpdata = handle:read(math.huge or math.maxinteger) + data = data .. (tmpdata or "") +until not tmpdata +handle:close() +for _, line in ipairs(json.decode(data)) do + if line ~= "" then + --[[ if _G.print then + print(line) + end ]] + _G._PUBLIC.tsched.runAsTask(line) + runTasks() + end +end +-- _G.cormgr.loadCoroutine("/halyde/core/shell.lua") + +while true do + runTasks() + if #_G.tsched.tasks == 0 then + computer.beep(1000, 0.5) + while true do + computer.pullSignal() + end + end +end diff --git a/halyde/core/shell.lua b/halyde/shell/shell.lua similarity index 83% rename from halyde/core/shell.lua rename to halyde/shell/shell.lua index f75b189..efc5937 100644 --- a/halyde/core/shell.lua +++ b/halyde/shell/shell.lua @@ -1,5 +1,5 @@ -local fs = import("filesystem") -local json = import("json") +local fs = require("filesystem") +local json = require("json") local handle, data, tmpdata = fs.open("/halyde/config/shell.json", "r"), "", nil repeat tmpdata = handle:read(math.huge) @@ -7,23 +7,21 @@ repeat until not tmpdata handle:close() local shellcfg = json.decode(data) -import("/halyde/core/termlib.lua") -local event = import("event") -local component = import("component") +local component = require("component") local gpu = component.gpu _G.shell = {} _G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"] _G.shell.aliases = shellcfg["aliases"] -local function runAsCoroutine(path, ...) +local function runAsTask(path, ...) --ocelot.log("running " .. path .. " as coroutine") - cormgr.loadCoroutine(path, ...) - local corIndex = #cormgr.corList - local cor = cormgr.corList[#cormgr.corList] + tsched.runAsTask(path, ...) + local corIndex = #tsched.getTasks() + local task = tsched.getTasks()[#tsched.getTasks()] repeat coroutine.yield() - until cormgr.corList[corIndex] ~= cor + until tsched.getTasks()[corIndex] ~= task end function _G.shell.run(command) @@ -66,14 +64,14 @@ function _G.shell.run(command) if fs.exists(args[1]) and not fs.isDirectory(args[1]) then local path = args[1] table.remove(args, 1) - runAsCoroutine(path, table.unpack(args)) + runAsTask(path, table.unpack(args)) return end for _, item in pairs(PATH) do if fs.exists(item..args[1]) and not fs.isDirectory(item .. args[1]) then local path = fs.concat(item, args[1]) table.remove(args, 1) - runAsCoroutine(path, table.unpack(args)) + runAsTask(path, table.unpack(args)) return else -- try to look for it without the file extension local files = fs.list(item) or {} @@ -81,7 +79,7 @@ function _G.shell.run(command) -- previous pattern: (.+)%.[^%.]+$ if args[1] == file:match("(.+)%.[^%.]+$") and not fs.isDirectory(item .. file) then table.remove(args, 1) - runAsCoroutine(item .. file, table.unpack(args)) + runAsTask(item .. file, table.unpack(args)) return end end @@ -100,7 +98,7 @@ while true do if shell.workingDirectory:sub(-1, -1) ~= "/" then shell.workingDirectory = shell.workingDirectory .. "/" end - local shellCommand = read("shell", shellcfg.prompt:format(shell.workingDirectory)) + local shellCommand = terminal.read("shell", shellcfg.prompt:format(shell.workingDirectory)) shell.run(shellCommand) gpu.freeAllBuffers() end diff --git a/halyde/system.log b/halyde/system.log new file mode 100644 index 0000000..5e48223 --- /dev/null +++ b/halyde/system.log @@ -0,0 +1,4 @@ +[00:00:04:12] Debug! +[00:00:04:19] Info! +[00:00:04:25] Warning! +[00:00:04:32] Error! diff --git a/home/test.lua b/home/test.lua new file mode 100644 index 0000000..c6f637f --- /dev/null +++ b/home/test.lua @@ -0,0 +1,7 @@ +local cor = coroutine.create(function() + print("Hello World!") +end) + +print(coroutine.status(cor)) +coroutine.resume(cor) +print(coroutine.status(cor)) diff --git a/init.lua b/init.lua index 56c7dcd..463f850 100644 --- a/init.lua +++ b/init.lua @@ -1,5 +1,24 @@ local gpu = component.proxy(component.list("gpu")()) -local resx, resy = gpu.getResolution() +local resX, resY = gpu.getResolution() + +-- Architecture check +local foundArchitecture = false +for _, arch in pairs(computer.getArchitectures()) do + if arch == "Lua 5.3" then + foundArchitecture = true + break + end +end + +if foundArchitecture then + computer.setArchitecture("Lua 5.3") +else + gpu.set(1, 1, "Required architecture (Lua 5.3) is not supported.") + gpu.set(1, 2, "Halting.") + while true do + computer.pullSignal() + end +end local function loadfile(file) checkArg(1, file, "string") @@ -17,36 +36,36 @@ local function handleError(errorMessage) return(errorMessage.."\n \n"..debug.traceback()) end -function loadthething() - loadfile("/halyde/core/boot.lua")(loadfile) +function loadBoot() + loadfile("/halyde/kernel/boot.lua")(loadfile) end gpu.setBackground(0x000000) -gpu.fill(1, 1, resx, resy, " ") -local result, reason = xpcall(loadthething, handleError) +gpu.fill(1, 1, resX, resY, " ") + +-- Copying low-level functions in case of post-preload failure +local pullSignal = computer.pullSignal +local shutdown = computer.shutdown + +local result, reason = xpcall(loadBoot, handleError) if not result then - if import then - local computer = import("computer") - end gpu.setBackground(0x000000) - gpu.fill(1, 1, resx, resy, " ") + gpu.fill(1, 1, resX, resY, " ") gpu.setBackground(0x800000) gpu.setForeground(0xFFFFFF) gpu.set(2,2,"A critical error has occurred.") local i = 4 - reason = reason:gsub("\t", " ") - for line in string.gmatch((reason ~= nil and tostring(reason)) or "unknown error", "([^\n]*)\n?") do + reason = tostring(reason):gsub("\t", " ") + for line in string.gmatch(reason or "unknown error", "([^\n]*)\n?") do gpu.set(2,i,line) i = i + 1 end - if computer~=nil then - gpu.set(2,i+1, "Press any key to restart.") - local evname - repeat - evname = computer.pullSignal() - until evname == "key_down" - computer.shutdown(true) - end + gpu.set(2,i+1, "Press any key to restart.") + local evname + repeat + evname = pullSignal() + until evname == "key_down" + shutdown(true) while true do coroutine.yield() end diff --git a/halyde/lib/component.lua b/lib/component.lua similarity index 100% rename from halyde/lib/component.lua rename to lib/component.lua diff --git a/halyde/lib/computer.lua b/lib/computer.lua similarity index 100% rename from halyde/lib/computer.lua rename to lib/computer.lua diff --git a/halyde/lib/event.lua b/lib/event.lua similarity index 97% rename from halyde/lib/event.lua rename to lib/event.lua index 64547fa..eada457 100644 --- a/halyde/lib/event.lua +++ b/lib/event.lua @@ -1,4 +1,4 @@ -local computer = import("computer") +local computer = require("computer") local event = {} local bufferTime = 0.1 -- A little bit of buffer time so events won't be skipped by accident. diff --git a/halyde/lib/filesystem.lua b/lib/filesystem.lua similarity index 98% rename from halyde/lib/filesystem.lua rename to lib/filesystem.lua index cbdd325..570e3c5 100644 --- a/halyde/lib/filesystem.lua +++ b/lib/filesystem.lua @@ -1,14 +1,14 @@ local loadfile = ... -- raw loadfile from boot.lua -local component, computer +local unicode, component, computer if loadfile then - unicode = loadfile("/halyde/lib/unicode.lua")(loadfile) - component = loadfile("/halyde/lib/component.lua")(loadfile) + unicode = loadfile("/lib/unicode.lua")(loadfile) + component = loadfile("/lib/component.lua")(loadfile) computer = _G.computer -elseif import then - unicode = import("unicode") - component = import("component") - computer = import("computer") +elseif require then + unicode = require("unicode") + component = require("component") + computer = require("computer") end local filesystem = {} diff --git a/halyde/lib/json.lua b/lib/json.lua similarity index 100% rename from halyde/lib/json.lua rename to lib/json.lua diff --git a/lib/log.lua b/lib/log.lua new file mode 100644 index 0000000..fe8fb35 --- /dev/null +++ b/lib/log.lua @@ -0,0 +1,30 @@ +local fs = require("filesystem") +local computer = require("computer") + +local log = {} + +function log.add(text, logType) + checkArg(1, text, "string") + checkArg(2, logType, "string", "nil") + if logType ~= "debug" and logType ~= "info" and logType ~= "warning" and logType ~= "error" and logType then + error("Log type must either be debug, info, warning or error.") + end + if not logType then + logType = "debug" + end + local handle = fs.open("/halyde/system.log", "a") + local time = computer.uptime() + local logText = string.format("[%02d:%02d:%02d:%02d] " .. text, math.floor(time / 86400), math.floor(time / 3600 % 24), math.floor(time / 60 % 60), math.floor(time % 60)) .. "\n" + if logType == "debug" then + handle:write("\27[37m" .. logText) + elseif logType == "info" then + handle:write("\27[97m" .. logText) + elseif logType == "warning" then + handle:write("\27[93m" .. logText) + else + handle:write("\27[91m" .. logText) + end + handle:close() +end + +return log diff --git a/halyde/lib/raster.lua b/lib/raster.lua similarity index 99% rename from halyde/lib/raster.lua rename to lib/raster.lua index 2709b75..cff96a8 100644 --- a/halyde/lib/raster.lua +++ b/lib/raster.lua @@ -9,7 +9,7 @@ local raster = { ["backgroundColor"]=0xFFFFFF } -local component = import("component") +local component = require("component") -- local ocelot = component.proxy(component.list("ocelot")()) local gpu = component.gpu diff --git a/halyde/lib/serialize.lua b/lib/serialize.lua similarity index 100% rename from halyde/lib/serialize.lua rename to lib/serialize.lua diff --git a/halyde/lib/unicode.lua b/lib/unicode.lua similarity index 100% rename from halyde/lib/unicode.lua rename to lib/unicode.lua