I forgot you have to give it write permissions (minified)

This commit is contained in:
github-actions[bot]
2026-04-30 12:32:52 +00:00
parent 2a2b27a827
commit b08d7b3f98
44 changed files with 102 additions and 4919 deletions
+1 -691
View File
@@ -1,691 +1 @@
local packages = {...}
local command = packages[1]
table.remove(packages, 1)
local fs = import("filesystem")
local component = import("component")
local agReg = import("/argentum/registry.cfg")
if not command then
shell.run("help argentum")
return
end
if not component.list("internet")() then
print("\27[91mThis program requires an internet card to run.")
return
end
local internet = component.internet
local source
if table.find(packages, "-s") then
source = table.remove(packages, table.find(packages, "-s") + 1)
table.remove(packages, table.find(packages, "-s"))
print("Using " .. source .. " as package source")
elseif table.find(packages, "--source") then
source = table.remove(packages, table.find(packages, "--source") + 1)
table.remove(packages, table.find(packages, "--source"))
print("Using " .. source .. " as package source")
else
print("Using main registry as package source")
end
if source and source:sub(1, 1) == "/" and source:sub(-1, -1) ~= "/" then
source = source .. "/"
end
local packageList = table.copy(packages)
local function getFile(path)
if path:sub(1,1) == "/" then
if not fs.exists(path) then
return false, "file does not exist"
end
local handle, data, tmpdata = fs.open(path, "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
return data
else
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(path)
request:finishConnect()
end)
if not status then
return false, errorMessage
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
return false, responseCode
end
repeat
tmpdata = request.read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
return data
end
end
local i = 1
local function getAgConfig(package, source)
source = source or agReg[package]
local data, errorMessage = getFile(source .. "argentum.cfg")
if not data or data == "" then
print("\27[91mCould not fetch Ag config: " .. (errorMessage or "returned nil data"))
return false
end
local func, errorMessage = load(data, "=argentum.cfg", "bt", {})
if not func then
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
return false
end
local agcfg
local status, errorMessage = pcall(function()
agcfg = func()
end)
if not status then
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
return false
end
if not agcfg[package] or not agcfg[package].maindir or not agcfg[package].directories or not agcfg[package].files or not agcfg[package].version then
local response = ("\27[91mAg config of " .. package .. " is improperly configured.\nPlease contact the package owner.")
end
return agcfg
end
local function doChecks(package)
if not agReg[package] and not source then
print("\27[91mPackage " .. package .. " does not exist.")
return false
end
if fs.exists("/argentum/store/" .. package) then
print("\27[91mPackage " .. package .. " is already installed.")
return false
end
agcfg = getAgConfig(package, source)
if not agcfg then
return false
end
if agcfg[package].dependencies then
for _, dependency in ipairs(agcfg[package].dependencies) do
if not agReg[dependency] and not agcfg[dependency] then
local response = read(nil, "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]")
if response:lower() ~= "s" then
fs.remove("/argentum/store/" .. package)
return false
end
end
end
for _, dependency in pairs(agcfg[package].dependencies) do
print(package .. " depends on " .. dependency)
if not table.find(packages, dependency) and doChecks(dependency) then
table.insert(packages, table.find(packages, package), dependency)
table.insert(packageList, dependency)
i = i + 1
end
end
end
return true
end
local function lpad(str, len, char)
str=tostring(str)
if char == nil then char = ' ' end
return string.rep(char, len - #str) .. str
end
local gpu = component.gpu
local width,height = gpu.getResolution()
local function progress(package,progress)
local info = string.format("%s %s%%",package,lpad(math.floor(progress*100),2))
info=info..string.rep(" ",width-#info)
local progX = math.floor(progress*width)
gpu.setBackground(0x00FF00)
gpu.setForeground(0x000000)
gpu.set(1,height,info:sub(1,progX))
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.set(progX+1,height,info:sub(progX+1))
end
local function clearProgress()
gpu.setBackground(0x000000)
gpu.fill(1,height,width,1," ")
end
local function installPackage(package, overwriteFlag)
if not overwriteFlag then
overwriteFlag = false
end
if not overwriteFlag then print("Installing " .. package .. "...") end
local agcfg = getAgConfig(package, source)
if not agcfg then
return false
end
local source = source or agReg[package]
local packageStore = "V" .. agcfg[package].version
if agcfg[package].dependencies then
for _, dependency in ipairs(agcfg[package].dependencies) do
if not agReg[dependency] and not agcfg[dependency] then
local response = read(nil, "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]")
if response:lower() ~= "s" then
fs.remove("/argentum/store/" .. package)
return false
end
end
end
for _, dependency in pairs(agcfg[package].dependencies) do
if agReg[dependency] or agcfg[dependency] then
--installPackage(dependency)
packageStore = packageStore .. "\nD" .. dependency
end
end
end
if agcfg[package].directories then
for _, directory in pairs(agcfg[package].directories) do
if directory:sub(-1, -1) ~= "/" then
directory = directory .. "/"
end
packageStore = "A" .. directory .. "\n" .. packageStore
if not fs.exists(directory) then
fs.makeDirectory(directory)
end
end
end
for idx, file in ipairs(agcfg[package].files) do
clearProgress()
::retry::
print(" Downloading " .. file .. "...")
progress(package,idx/#agcfg[package].files)
local data, errorMessage = getFile(source .. agcfg[package].maindir .. file)
if not data then
clearProgress()
local response = read(nil, "\27[91mCould not fetch " .. file .. ": " .. errorMessage .. "\n\27[0m[a - Abort/R - Retry/s - Skip]")
if response:lower() == "a" then
fs.remove("/argentum/store/" .. package)
return false
elseif response:lower() == "s" then
goto skip
else
goto retry
end
end
if fs.exists(file) and not overwriteFlag then
if not fs.exists("/argentum/store/" .. package .. "/files/" .. file:match("(.*/)")) then
fs.makeDirectory("/argentum/store/" .. package .. "/files/" .. file:match("(.*/)"))
end
fs.copy(file, "/argentum/store/" .. package .. "/files/" .. file)
packageStore = packageStore .. "\nM" .. file
else
packageStore = packageStore .. "\nA" .. file
end
local handle = fs.open(file, "w")
handle:write(data)
handle:close()
::skip::
end
clearProgress()
fs.makeDirectory("/argentum/store/" .. package)
local handle = fs.open("/argentum/store/" .. package .. "/package.cfg", "w")
handle:write(packageStore)
handle:close()
return true
end
local function removePackage(package)
print("Removing " .. package .. "...")
if not fs.exists("/argentum/store/" .. package .. "/package.cfg") then
print("\27[91mLocal Ag config of " .. package .. " does not exist.")
return false
end
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
data = data .. "\n"
local idx = 0
for line in data:gmatch("(.-)\n") do
idx=idx+1
if line:sub(1, 1) == "A" then
clearProgress()
::retry::
print(" Removing " .. line:sub(2) .. "...")
if line:sub(-1, -1) == "/" and fs.list(line:sub(2))[1] then
print(" There are still files in " .. line:sub(2) .. ". Skipping.")
else
progress(package,idx/select(2,data:gsub("\n","\n")))
local result, errorMessage = fs.remove(line:sub(2))
if not result then
clearProgress()
local response = read(nil, "\27[91mFailed to remove " .. line:sub(2) .. ": " .. errorMessage .. "\n\27[0m[a - Abort/r - Retry/S - Skip]")
if response:lower() == "a" then
return false
elseif response:lower() == "r" then
goto retry
end
end
end
elseif line:sub(1, 1) == "M" then
clearProgress()
::retry::
print(" Reverting " .. line:sub(2) .. "...")
progress(package,idx/select(2,data:gsub("\n","\n")))
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/files/" .. line:sub(2), "r"), "", nil
if not handle then
clearProgress()
local response = read(nil, "\27[91mFailed to revert " .. line:sub(2) .. ": " .. data .. "\n\27[0m[a - Abort/R - Retry/s - Skip]") -- this is pretty stupid but i think the error message would get pushed to data
if response:lower() == "a" then
return false
elseif response:lower() == "s" then
goto skip
else
goto retry
end
end
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local handle = fs.open(line:sub(2), "w")
handle:write(data)
handle:close()
::skip::
end
end
clearProgress()
fs.remove("/argentum/store/" .. package .. "/")
return true
end
local function updatePackage(package)
print("Updating " .. package .. "...")
local agcfg = getAgConfig(package, source)
if not agcfg then
return false
end
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local oldFiles = {}
for line in (data .. "\n"):gmatch("(.-)\n") do
if line:sub(1, 1) == "A" or line:sub(1, 1) == "M" then
if agcfg[package].directories then
if not table.find(agcfg[package].files, line:sub(2)) and not table.find(agcfg[package].directories, line:sub(2, -2)) then
table.insert(oldFiles, line:sub(2))
end
else
if not table.find(agcfg[package].files, line:sub(2)) then
table.insert(oldFiles, line:sub(2))
end
end
end
end
for _, oldFile in pairs(oldFiles) do
print(" Removing " .. oldFile .. "...")
end
return installPackage(package, true)
end
local fails = {}
if command == "install" then
if not packages or not packages[1] then
print("Please specify packages to install.")
return
end
print("Fetching Ag registry...")
local newRegistry, errorMessage = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum/registry.cfg")
if newRegistry then
local handle = fs.open("/argentum/registry.cfg", "w")
handle:write(newRegistry)
handle:close()
else
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
end
agReg = import("/argentum/registry.cfg")
while true do
if not doChecks(packages[i]) then
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
end
i = i + 1
if i > #packages then
break
end
end
local answer
if #fails == 0 then
print("Packages that will be installed: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
return
end
elseif #packageList == 0 then
print("None of the packages can be installed.")
return
else
print("Some packages cannot be installed.")
print("Packages that will be installed: " .. table.concat(packageList, ", "))
print("Packages that cannot be installed: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
return
end
end
for _, failedPackage in pairs(fails) do
table.remove(packages, table.find(packages, failedPackage))
end
fails = {}
for _, package in ipairs(packages) do
if not installPackage(package) then
table.insert(fails, package)
table.remove(packageList, table.find(packageList, package))
end
end
if #fails == 0 then
print("Installation completed successfully.")
print("Packages installed: " .. table.concat(packageList, ", "))
elseif #packageList == 0 then
print("All packages failed to install.")
print("Packages that could not be installed: " .. table.concat(fails, ", "))
else
print("Some packages failed to install.")
print("Packages installed: " .. table.concat(packageList, ", "))
print("Packages that could not be installed: " .. table.concat(fails, ", "))
end
elseif command == "remove" then
if not packages or not packages[1] then
print("Please specify packages to remove.")
return
end
while true do
if not fs.exists("/argentum/store/" .. packages[i]) then
print("\27[91mPackage " .. packages[i] .. " is not installed.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
elseif packages[i] == "halyde" then -- yes, this stuff is hard-coded.
print("\27[91mFor obvious reasons, you can't uninstall Halyde.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
elseif packages[i] == "argentum" then
print("\27[91mFor obvious reasons, you can't uninstall Argentum.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
end
i = i + 1
if i > #packages then
break
end
end
-- do dependency checks
local packagesInstalled = fs.list("/argentum/store")
for _, currentPackage in pairs(packagesInstalled) do
if currentPackage:sub(-1, -1) == "/" and fs.exists("/argentum/store/" .. currentPackage .. "package.cfg") then
local handle, data, tmpdata = fs.open("/argentum/store/" .. currentPackage .. "package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
for line in (data.."\n"):gmatch("(.-)\n") do
for i = 1, #packages do
if line == "D" .. packages[i] then
print(packages[i] .. " depends on " .. currentPackage:sub(1, -2))
if not table.find(packages, currentPackage:sub(1, -2)) then
table.insert(packages, table.find(packages, packages[i]), currentPackage:sub(1, -2))
table.insert(packageList, currentPackage:sub(1, -2))
i = i + 1
end
end
end
end
end
end
local answer
if #fails == 0 then
print("Packages that will be removed: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
return
end
elseif #packageList == 0 then
print("None of the packages can be removed.")
return
else
print("Some packages cannot be removed.")
print("Packages that will be removed: " .. table.concat(packageList, ", "))
print("Packages that cannot be removed: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
return
end
end
for _, failedPackage in pairs(fails) do
table.remove(packages, table.find(packages, failedPackage))
end
fails = {}
for _, package in ipairs(packages) do
if not removePackage(package) then
table.insert(fails, package)
table.remove(packageList, table.find(packageList, package))
end
end
if #fails == 0 then
print("Removal completed successfully.")
print("Packages removed: " .. table.concat(packageList, ", "))
elseif #packageList == 0 then
print("All packages failed to be removed.")
print("Packages that could not be removed: " .. table.concat(fails, ", "))
else
print("Some packages failed to be removed.")
print("Packages removed: " .. table.concat(packageList, ", "))
print("Packages that could not be removed: " .. table.concat(fails, ", "))
end
elseif command == "update" then
print("Fetching Ag registry...")
local newRegistry, errorMessage = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum/registry.cfg")
if newRegistry then
local handle = fs.open("/argentum/registry.cfg", "w")
handle:write(newRegistry)
handle:close()
else
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
end
agReg = import("/argentum/registry.cfg")
if not packages[1] then
local packagesInstalled = fs.list("/argentum/store/")
for _, currentPackage in pairs(packagesInstalled) do
if currentPackage:sub(-1, -1) == "/" and fs.exists("/argentum/store/" .. currentPackage .. "package.cfg") then
table.insert(packages, currentPackage:sub(1, -2))
table.insert(packageList, currentPackage:sub(1, -2))
end
end
end
while true do
local nonexistent = false -- I couldn't figure out a better way to do this, so I have to use a flag if the package doesn't exist
if not fs.exists("/argentum/store/" .. packages[i]) then
print("\27[91mPackage " .. packages[i] .. " is not installed.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
nonexistent = true
end
if not nonexistent then
-- Check if up to date
local agcfg = getAgConfig(packages[i], source)
if not agcfg then
return false
end
local handle, data, tmpdata = fs.open("/argentum/store/" .. packages[i] .. "/package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local version = "0.0.0"
for line in (data.."\n"):gmatch("(.-)\n") do
if line:sub(1, 1) == "V" then
version = line:sub(2)
break
end
end
if agcfg[packages[i]].version == version then
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
else
print(packages[i].." is out of date [\x1b[93m"..version.."\x1b[39m < \x1b[92m"..agcfg[packages[i]].version.."\x1b[39m]")
end
end
i = i + 1
if i > #packages then
break
end
end
local answer
if #packageList == 0 then
if #fails == 0 then
print("All packages are up to date.")
return
else
print("None of the packages can be updated.")
return
end
elseif #fails == 0 then
print("Packages that will be updated: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
return
end
else
print("Some packages cannot be updated.")
print("Packages that will be updated: " .. table.concat(packageList, ", "))
print("Packages that cannot be updated: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
return
end
end
for _, failedPackage in pairs(fails) do
table.remove(packages, table.find(packages, failedPackage))
end
fails = {}
for _, package in pairs(packages) do
-- Previous up-to-date check
--local agcfg = getAgConfig(package, source)
--if not agcfg then
-- return false
--end
--local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
--repeat
-- tmpdata = handle:read(math.huge)
-- data = data .. (tmpdata or "")
--until not tmpdata
--handle:close()
--local version = "0.0.0"
--for line in (data.."\n"):gmatch("(.-)\n") do
-- if line:sub(1, 1) == "V" then
-- version = line:sub(2)
-- break
-- end
--end
--if agcfg[package].version == version then
-- print(package .. " is up to date")
-- goto skip
--end
if not updatePackage(package) then
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
goto skip
end
::skip::
end
if #fails == 0 then
print("Update completed successfully.")
print("Packages updated: " .. table.concat(packageList, ", "))
elseif #packageList == 0 then
print("All packages failed to update.")
print("Packages that could not update: " .. table.concat(fails, ", "))
else
print("Some packages failed to update.")
print("Packages updated: " .. table.concat(packageList, ", "))
print("Packages that could not update: " .. table.concat(fails, ", "))
end
elseif command == "info" then
if not packages[1] then
print("Please specify a package to show information about.")
return
end
print("Fetching Ag registry...")
local newRegistry, errorMessage = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum/registry.cfg")
if newRegistry then
local handle = fs.open("/argentum/registry.cfg", "w")
handle:write(newRegistry)
handle:close()
else
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
end
agReg = import("/argentum/registry.cfg")
if not agReg[packages[1]] and not source then
print("\27[91mPackage " .. packages[1] .. " does not exist.")
return
end
local agcfg = getAgConfig(packages[1], source)
if not agcfg then
return false
end
print("\27[93m" .. packages[1] .. "\27[0m v" .. agcfg[packages[1]].version .. "\n " .. (agcfg[packages[1]].description or "No description."):gsub("\n", " \n"))
elseif command == "search" then
if not packages[1] then
print("Please specify a search term.")
return
end
print("Fetching Ag registry...")
local newRegistry, errorMessage = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum/registry.cfg")
if newRegistry then
local handle = fs.open("/argentum/registry.cfg", "w")
handle:write(newRegistry)
handle:close()
else
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
end
agReg = import("/argentum/registry.cfg")
local searchResults = {}
for packageName, _ in pairs(agReg) do
if packageName:find(packages[1], 1, true) then
table.insert(searchResults, packageName)
end
end
if not searchResults[1] then
print("No search results found for " .. packages[1] .. ".")
return
end
table.sort(searchResults)
print("Search results: \n " .. table.concat(searchResults, "\n "))
elseif command == "list" then
print("Fetching Ag registry...")
local newRegistry, errorMessage = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum/registry.cfg")
if newRegistry then
local handle = fs.open("/argentum/registry.cfg", "w")
handle:write(newRegistry)
handle:close()
else
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
end
agReg = import("/argentum/registry.cfg")
local sortedPackages = {}
for packageName, _ in pairs(agReg) do
table.insert(sortedPackages, packageName)
end
table.sort(sortedPackages)
print("List of available Ag packages: \n " .. table.concat(sortedPackages, "\n "))
else
shell.run("help ag")
end
Error: no such file. (``)
+1 -60
View File
@@ -1,60 +1 @@
local component = import("component")
local computer = import("computer")
local args = {...}
local force = false
local forceArgIdx = table.find(args,"-f") or table.find(args,"--force")
if forceArgIdx then
table.remove(args,forceArgIdx)
force = true
end
local function getComponentID(str)
local function fromSlot(slot)
for i,v in component.list() do
if component.slot(i)==slot then
return i
end
end
end
if str=="hdd1" or str=="#1" then return fromSlot(5) end
if str=="hdd2" or str=="#2" then return fromSlot(6) end
if str=="floppy" or str=="#3" then return fromSlot(7) end
if #str<3 then return nil,"Abbreviated ID must atleast have 3 characters" end
return component.get(str)
end
local function fileExists(compID,file)
return component.invoke(compID,"exists",file) and not component.invoke(compID,"isDirectory",file)
end
if type(args[1])=="string" then
local compID,err = getComponentID(args[1])
if not compID then
print("\x1b[91mCould not get component ID from '"..args[1].."'.")
if type(err)=="string" then print("\x1b[91m"..err) end
return
end
if not force then
if componentlib.additions[compID] then
return print("\x1b[91mThis component is virtual and cannot be booted from directly.\nID: "..compID)
end
local type = component.type(compID)
if type~="filesystem" and type~="drive" then
return print("\x1b[91mThis component is not a storage medium.\nID: "..compID)
end
if type=="filesystem" and not fileExists(compID,"/init.lua") then
return print("\x1b[91mThis storage medium doesn't have an \"init.lua\" file.\nID: "..compID)
end
end
computer.setBootAddress(compID)
if computer.getBootAddress()~=compID then
return print("\x1b[91mFailed to set the boot address.")
end
computer.shutdown(true)
else
shell.run("help boot")
end
Error: no such file. (``)
+1 -20
View File
@@ -1,20 +1 @@
local files = {...}
local fs = import("filesystem")
if not files or not files[1] then
shell.run("help cat")
return
end
for _, file in ipairs(files) do
if file:sub(1, 1) ~= "/" then
file = fs.concat(shell.workingDirectory, file)
end
if not fs.exists(file) then
print("\27[91mFile does not exist.")
end
local handle = fs.open(file, "r")
local data
repeat
data = handle:read(math.huge or math.maxinteger)
termlib.write(data)
until not data
end
Error: no such file. (``)
+1 -14
View File
@@ -1,14 +1 @@
local directory = ...
local fs = import("filesystem")
if not directory then
return
end
if directory:sub(1, 1) ~= "/" then
directory = fs.concat(shell.workingDirectory, directory)
end
if fs.exists(directory) and fs.isDirectory(directory) then
shell.workingDirectory = fs.canonical(directory)
else
print("\27[91mNo such directory.")
end
Error: no such file. (``)
+1 -2
View File
@@ -1,2 +1 @@
clear()
-- truly so much going on here
Error: no such file. (``)
+1 -26
View File
@@ -1,26 +1 @@
local fromFile, toFile = ...
local fs = import("filesystem")
if not fromFile or not toFile then
shell.run("help cp")
return
end
if fromFile:sub(1, 1) ~= "/" then
fromFile = fs.concat(shell.workingDirectory, fromFile)
end
if toFile:sub(1, 1) ~= "/" then
toFile = fs.concat(shell.workingDirectory, toFile)
end
if fromFile == toFile then
print("\27[91mSource and destination are the same.")
return
end
if not fs.exists(fromFile) then
print("\27[91mSource file does not exist.")
return
end
if fs.exists(toFile) and not (table.find({...}, "-o") or table.find({...}, "--overwrite")) then
print("\27[91mDestination file already exists. Run this command again with -o to overwrite it.")
return
end
fs.copy(fromFile, toFile)
Error: no such file. (``)
+1 -57
View File
@@ -1,57 +1 @@
local url = ...
local component = import("component")
local fs = import("filesystem")
if not component.list("internet")() then
print("\27[91mThis program requires an internet card to run.")
return
end
if not url then
print("Please enter a URL to download from.")
shell.run("help download")
return
end
if url:sub(-1, -1) == "/" then
url = url:sub(1, -2)
end
local internet = component.internet
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(url)
request:finishConnect()
end)
if not status then
print("\27[91mDownload failed: " .. errorMessage)
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
print("\27[91mDownload failed: " .. tostring(responseCode))
end
repeat
tmpdata = request.read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
local saveLocation
local saveLocationOK = false
repeat
saveLocation = read(nil, "File save location: ", fs.concat(shell.workingDirectory, url:match("/([^/]+)$")))
if fs.isDirectory(saveLocation) then
print("\27[91mThe specified location is a directory.")
elseif fs.exists(saveLocation) then
local answer = read(nil, "\27[91mThere is already a file at the specified directory. Overwrite it? [Y/n]")
if answer:lower() ~= "n" then
saveLocationOK = true
end
else
saveLocationOK = true
end
until saveLocationOK
local handle = fs.open(saveLocation, "w")
handle:write(data)
handle:close()
print("File downloaded successfully.")
Error: no such file. (``)
+1 -7
View File
@@ -1,7 +1 @@
local args = {...}
local concatText = args[1]
table.remove(args, 1)
for _, item in pairs(args) do
concatText = concatText .. " " .. item
end
print(concatText)
Error: no such file. (``)
+1 -351
View File
@@ -1,351 +1 @@
local file = ...
local fs = import("filesystem")
local event = import("event")
local component = import("component")
local unicode = import("unicode")
local gpu = component.gpu
local width, height = gpu.getResolution()
local scrollPosX, scrollPosY = 1, 1
local cursorPosX, cursorPosY = 1, 1
local cursorWhite = true
local changesMade = false
local renderBuffer = gpu.allocateBuffer()
local scrollSpeed = 5
local tab = " "
--local ocelot = component.ocelot
local function rawset(x, y, text)
termlib.cursorPosX = x
termlib.cursorPosY = y
termlib.write(text, false)
end
local filestring, filepath, handle, data, tmpdata
if file then
if file:sub(1, 1) == "/" then
filepath = file
else
filepath = shell.workingDirectory .. file
end
handle, data, tmpdata = fs.open(filepath, "r"), "", nil
if fs.exists(filepath) then
filestring = filepath
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = {}
if data:gmatch("(.-)\n")() then
for line in data:gmatch("(.-)\n") do
local newLine = line:gsub("\r", "") -- this took me SO LONG TO FIGURE OUT AAAAAAAA I HATE CRLF I HATE CRLF I HATE CRLF
table.insert(tmpdata, newLine)
end
else
tmpdata = {data}
end
else
filepath = shell.workingDirectory .. file
filestring = "[NEW FILE]"
tmpdata = {""}
end
else
filepath = ""
filestring = "[NEW FILE]"
tmpdata = {""}
end
local function render()
gpu.setActiveBuffer(renderBuffer)
clear()
--ocelot.log(tostring(scrollPosY))
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
if realCursorX < 1 then
scrollPosX = scrollPosX + realCursorX - 1
cursorPosX = 1
realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
end
for i = scrollPosY, height + scrollPosY - 3 do
gpu.set(1, i - scrollPosY + 1, (tmpdata[i] or ""):sub(scrollPosX))
end
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
rawset(1, height, "\27[107m\27[30m^X\27[0m Exit \27[107m\27[30m^S\27[0m Save" .. string.rep(" ", width))
local char = gpu.get(realCursorX, cursorPosY)
if cursorWhite then
gpu.setForeground(0)
gpu.setBackground(0xFFFFFF)
end
gpu.set(realCursorX, cursorPosY, char)
gpu.bitblt()
gpu.setActiveBuffer(0)
end
local renderFlag, cursorRenderFlag = false, false
local function scrollUp()
cursorPosY = cursorPosY - 1
cursorRenderFlag = true
cursorWhite = true
if cursorPosY < 1 then
renderFlag = true
scrollPosY = scrollPosY - 1
cursorPosY = 1
end
if scrollPosY < 1 then
renderFlag = false
scrollPosY = 1
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollDown()
cursorPosY = cursorPosY + 1
cursorRenderFlag = true
cursorWhite = true
if cursorPosY + scrollPosY - 1 > #tmpdata then
renderFlag = false
cursorPosY = #tmpdata - scrollPosY + 1
end
if cursorPosY > height - 2 then
renderFlag = true
scrollPosY = scrollPosY + 1
cursorPosY = height - 2
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollLeft()
cursorRenderFlag = true
cursorWhite = true
if cursorPosX > 1 then
if cursorPosX <= unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2 then
cursorPosX = cursorPosX - 1
elseif unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 1 > 1 then
cursorPosX = unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 1
end
elseif scrollPosX > 1 then
scrollPosX = scrollPosX - 1
renderFlag = true
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollRight()
cursorRenderFlag = true
cursorWhite = true
if cursorPosX <= unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 1 then
cursorPosX = cursorPosX + 1
end
if cursorPosX > width then
cursorPosX = width
scrollPosX = scrollPosX + 1
renderFlag = true
end
end
local function processEvent(args)
renderFlag, cursorRenderFlag = false, false
if args[1] == "key_down" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if keyboard.ctrlDown then
return false, false, key
end
if key == "down" and cursorPosY < #tmpdata then
scrollDown()
end
if key == "up" then
scrollUp()
end
if key == "left" then
scrollLeft()
end
if key == "right" then
scrollRight()
end
if key == "enter" then
changesMade = true
renderFlag = true
cursorWhite = true
table.insert(tmpdata, cursorPosY + 1, tmpdata[cursorPosY + scrollPosY - 1]:sub(cursorPosX))
tmpdata[cursorPosY + scrollPosY - 1] = tmpdata[cursorPosY + scrollPosY - 1]:sub(1, cursorPosX - 1)
cursorPosX = 1
cursorPosY = cursorPosY + 1
scrollPosX = 1
if cursorPosY > height - 2 then
scrollPosY = scrollPosY + 1
cursorPosY = height - 2
end
end
if key == "back" then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
if cursorPosX == 1 and cursorPosY + scrollPosY - 1 > 1 then
cursorPosY = cursorPosY - 1
if cursorPosY < 1 then
scrollPosY = scrollPosY - 1
cursorPosY = 1
end
if scrollPosY < 1 then
scrollPosY = 1
end
cursorPosX = unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2
if cursorPosX > width then
scrollPosX = cursorPosX - width + 1
cursorPosX = width
end
tmpdata[cursorPosY + scrollPosY - 1] = tmpdata[cursorPosY + scrollPosY - 1] .. tmpdata[cursorPosY + 1]
table.remove(tmpdata, cursorPosY + 1)
renderFlag = true
else
tmpdata[cursorPosY + scrollPosY - 1] = tmpdata[cursorPosY + scrollPosY - 1]:sub(1, cursorPosX + scrollPosX - 3) .. tmpdata[cursorPosY + scrollPosY - 1]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = math.min(cursorPosX - 1, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) + 1)
if cursorPosX < 1 then
cursorPosX = 1
scrollPosX = scrollPosX - 1
renderFlag = true
else
gpu.set(1, cursorPosY, tmpdata[cursorPosY + scrollPosY - 1]:sub(scrollPosX) .. " ")
end
end
end
if key == "tab" then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
tmpdata[cursorPosY + scrollPosY - 1] = tmpdata[cursorPosY + scrollPosY - 1]:sub(1, cursorPosX + scrollPosX - 2) .. tab .. tmpdata[cursorPosY + scrollPosY - 1]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = cursorPosX + unicode.wlen(tab)
if cursorPosX > width then
scrollPosX = scrollPosX + cursorPosX - width
cursorPosX = width
renderFlag = true
else
gpu.set(1, cursorPosY, tmpdata[cursorPosY + scrollPosY - 1]:sub(scrollPosX))
end
end
if args[3] >= 32 and args[3] <= 126 then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
tmpdata[cursorPosY + scrollPosY - 1] = tmpdata[cursorPosY + scrollPosY - 1]:sub(1, cursorPosX + scrollPosX - 2) .. unicode.char(args[3]) .. tmpdata[cursorPosY + scrollPosY - 1]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1])) + 1
--ocelot.log(tostring(cursorPosX))
if cursorPosX > width then
cursorPosX = width
scrollPosX = scrollPosX + 1
renderFlag = true
else
gpu.set(1, cursorPosY, tmpdata[cursorPosY + scrollPosY - 1]:sub(scrollPosX))
end
end
elseif args[1] == "scroll" then
if args[5] == 1 then
for i = 1, scrollSpeed do
scrollUp()
end
elseif args[5] == -1 and cursorPosY < #tmpdata then
for i = 1, scrollSpeed do
scrollDown()
end
end
end
return renderFlag, cursorRenderFlag
end
local function save()
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
gpu.set(1, height - 1, string.rep(" ", width))
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local savepath = read(nil, "\27[107m\27[30mSave location: ", filepath)
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
if fs.exists(savepath) then
gpu.set(1, height - 1, string.rep(" ", width))
local answer = read(nil, "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] ")
if answer:lower() == "n" then
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
gpu.set(1, height - 1, filestring .. string.rep(" ", width))
return
end
end
local handle, errorMessage = fs.open(savepath, "w")
if handle then
if table.concat(tmpdata, "\n"):sub(-1, -1) == "\n" then
handle:write(table.concat(tmpdata, "\n"))
else
handle:write(table.concat(tmpdata, "\n") .. "\n") -- add a newline at the end to follow POSIX standards
end
handle:close()
gpu.set(1, height - 1, filestring .. string.rep(" ", width))
else
gpu.set(1, height - 1, "ERROR: " .. errorMessage:gsub("\n", "") .. string.rep(" ", width))
end
changesMade = false
end
render()
while true do
local args = {event.pull(0.5)}
local renderFlag, cursorRenderFlag, specialKey = false, false, nil
local previousCursorX, previousCursorY = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2), cursorPosY
if args and args[1] then
cursorWhite = true
renderFlag, cursorRenderFlag, specialKey = processEvent(args)
if specialKey == "x" then
if changesMade then
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local response = read(nil, "\27[107m\27[30mWould you like to save changes? [Y/n] ")
if response:lower() ~= "n" then
save()
end
end
gpu.freeAllBuffers()
clear()
return
end
if specialKey == "s" then
save()
end
repeat
args = {event.pull("key_down", 0)}
if args and args[1] then
processEvent(args)
end
until not args or not args[1]
else
cursorWhite = not cursorWhite
cursorRenderFlag = true
end
if cursorRenderFlag then
local char = gpu.get(previousCursorX, previousCursorY)
gpu.set(previousCursorX, previousCursorY, char)
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
if realCursorX < 1 then
scrollPosX = scrollPosX + realCursorX - 1
cursorPosX = 1
realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
end
local char = gpu.get(realCursorX, cursorPosY)
if cursorWhite then
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
end
gpu.set(realCursorX, cursorPosY, char)
if cursorWhite then
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0)
end
end
if renderFlag then
render()
end
end
Error: no such file. (``)
+1 -70
View File
@@ -1,70 +1 @@
local component = import("component")
local computer = import("computer")
local function printstat(text)
termlib.cursorPosX = 35
termlib.write(text .. "\n", false)
end
termlib.write(_OSLOGO, false)
termlib.cursorPosY = termlib.cursorPosY - 17
printstat("\27[92mOS\27[0m: ".._OSVERSION)
printstat("\27[92mArchitecture\27[0m: ".._VERSION)
local componentCounter = 0
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[92mBattery\27[0m: "..tostring(math.floor(computer.energy() / computer.maxEnergy() * 1000 + 0.5) / 10).."%")
local totalMemory = computer.totalMemory()
local usedMemory = computer.totalMemory() - computer.freeMemory()
local totalMemoryString
if convert(totalMemory, "B", "GiB") >= 1 then
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(totalMemory, "B", "MiB") >= 1 then
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(totalMemory, "B", "KiB") >= 1 then
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
totalMemoryString = tostring(totalMemory) .. " B"
end
local usedMemoryString
if convert(usedMemory, "B", "GiB") >= 1 then
usedMemoryString = tostring(math.floor(convert(usedMemory, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(usedMemory, "B", "MiB") >= 1 then
usedMemoryString = tostring(math.floor(convert(usedMemory, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(usedMemory, "B", "KiB") >= 1 then
usedMemoryString = tostring(math.floor(convert(usedMemory, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
usedMemoryString = tostring(usedMemory) .. " B"
end
printstat("\27[92mMemory\27[0m: "..usedMemoryString.." / "..totalMemoryString)
local totalDisk = component.invoke(computer.getBootAddress(), "spaceTotal")
local usedDisk = component.invoke(computer.getBootAddress(), "spaceUsed")
local totalDiskString
if convert(totalDisk, "B", "GiB") >= 1 then
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(totalDisk, "B", "MiB") >= 1 then
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(totalDisk, "B", "KiB") >= 1 then
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
totalDiskString = tostring(totalDisk) .. " B"
end
local usedDiskString
if convert(usedDisk, "B", "GiB") >= 1 then
usedDiskString = tostring(math.floor(convert(usedDisk, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(usedDisk, "B", "MiB") >= 1 then
usedDiskString = tostring(math.floor(convert(usedDisk, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(usedDisk, "B", "KiB") >= 1 then
usedDiskString = tostring(math.floor(convert(usedDisk, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
usedDiskString = tostring(usedDisk) .. " B"
end
printstat("\27[92mDisk\27[0m: "..usedDiskString.." / "..totalDiskString)
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
Error: no such file. (``)
+1 -38
View File
@@ -1,38 +1 @@
local fs = import("filesystem")
local args = {...}
local command = args[1]
args = nil
if not command then
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/default.txt", "r"), "", nil
repeat
tmpdata = handle:read(math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
print(data)
return
end
if shell.aliases[command] then
command = shell.aliases[command]
end
if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/" .. command .. ".txt", "r"), "", nil
repeat
tmpdata = handle:read(math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
print(data)
local aliases = table.copy(shell.aliases)
if table.find(aliases, command) then
local aliasIndex = table.find(aliases, command)
local aliasString = "Aliases:\n " .. aliasIndex
aliases[aliasIndex] = nil
while table.find(aliases, command) do
aliasIndex = table.find(aliases, command)
aliasString = aliasString .. ", " .. aliasIndex
aliases[aliasIndex] = nil
end
print(aliasString)
end
else
print("Could not find help file for: " .. command .. ".")
end
Error: no such file. (``)
+1 -92
View File
@@ -1,92 +1 @@
local component = import("component")
local computer = import("computer")
local args = {...}
if not args then return print("\x1b[91mCannot get arguments.") end
if not args[1] then
return shell.run("help label")
end
local inputID = args[1]
local comp
local function componentFromSlot(slotNum)
if slotNum>=5 and slotNum<=8 then slotNum=slotNum-1 end
for i,v in component.list() do
if component.slot(i)==slotNum then
comp=component.proxy(i)
end
end
end
if inputID=="eeprom" then
comp = component.eeprom
elseif inputID=="halyde" then
comp = component.proxy(computer.getBootAddress())
elseif inputID:sub(1,4)=="slot" and tonumber(inputID:sub(5)) then
local slotNum = tonumber(inputID:sub(5))-1
componentFromSlot(slotNum)
elseif inputID:sub(1,1)=="#" and tonumber(inputID:sub(2)) then
local slotNum = tonumber(inputID:sub(2))+5
componentFromSlot(slotNum)
elseif #inputID>=3 then
local fullID = component.get(inputID)
if not fullID then return print("\x1b[91mCould not find entire component ID from \""..inputID.."\".") end
comp = component.proxy(fullID)
else
print("\x1b[91mAddress must have atleast 3 characters")
return shell.run("help label")
end
if not comp then
return print("\x1b[91mCould not find component from \""..inputID.."\".")
end
local compID = comp.address
local function formatID(id)
return id:sub(1,8).."\x1b[37m"..id:sub(9).."\x1b[39m"
end
local function unsupported(act)
print("This \x1b[92m"..(comp.type or "unknown").."\x1b[39m component doesn't support "..act.." labels.\nID: "..formatID(compID))
end
local function compError(act,reason)
print("\x1b[91mAn error occured while "..act.." the label of this component.\nComponent: "..(compID or "unknown id").." ("..((comp or {}).type or "unknown type")..")\n\n"..reason)
end
local function formatLabel(label)
local res = "No label defined"
if label then res="\""..label.."\"" end
return res
end
if type(args[2])~="string" then
if not comp.getLabel then
return unsupported("getting")
end
local label
local success,reason = pcall(function()
label = comp.getLabel()
end)
if success then
print("Label of "..formatID(compID)..((comp.type and comp.type~="filesystem") and " ("..comp.type..")" or "")..":\n \x1b[92m"..formatLabel(label).."\x1b[39m")
else
compError("getting",reason)
end
else
if not comp.setLabel then
return unsupported("setting")
end
local newLabel = ""
for i=2,#args do
newLabel=newLabel..tostring(args[i])
if i<#args then newLabel=newLabel.." " end
end
local label
local success,reason = pcall(function()
label = comp.setLabel(newLabel)
end)
if success then
print("Successfully set label of "..formatID(compID)..(comp.type and " ("..comp.type..")" or "").." to:\n \x1b[92m"..formatLabel(label).."\x1b[39m")
else
compError("setting",reason)
end
end
Error: no such file. (``)
+1 -70
View File
@@ -1,70 +1 @@
local args = {...}
local target = args[1]
args = nil
local fs = import("filesystem")
local unicode = import("unicode")
local maxLength = 0
local margin = 2 -- minimum space between filename and size
local dirTable = {}
local fileTable = {}
if target then
if target:sub(1, 1) ~= "/" then
target = fs.concat(shell.workingDirectory, target)
end
else
target = shell.workingDirectory
end
local files = fs.list(target)
if files then
for _, file in pairs(files) do
if file:sub(-1, -1) == "/" then
table.insert(dirTable, file)
file = file:sub(1, -2)
else
table.insert(fileTable, file)
end
if unicode.wlen(file) > maxLength then
maxLength = unicode.wlen(file)
end
end
table.sort(dirTable)
table.sort(fileTable)
files = {}
for _, v in ipairs(dirTable) do
table.insert(files, v)
end
for _, v in ipairs(fileTable) do
table.insert(files, v)
end
dirTable, fileTable = nil, nil
for _, file in ipairs(files) do
local dir = false
local filetext
if file:sub(-1, -1) == "/" then
dir = true
filetext = "\27[93m"..file:sub(1, -2)
elseif file:find(".") and file:match("[^.]+$") == "lua" then
filetext = "\27[92m"..file
end
filetext = (filetext or file)..string.rep(" ", maxLength - unicode.wlen(file) + margin)
if dir then
print(filetext.." \27[0m[DIR]")
else
local size = fs.size(fs.concat(target, file))
local sizeString
if convert(size, "B", "GiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "GiB") * 100 + 0.5) / 100).." GiB"
elseif convert(size, "B", "MiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "MiB") * 100 + 0.5) / 100).." MiB"
elseif convert(size, "B", "KiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "KiB") * 100 + 0.5) / 100).." KiB"
else
sizeString = tostring(size).." B"
end
print(filetext.."\27[0m"..sizeString)
end
end
end
Error: no such file. (``)
+1 -9
View File
@@ -1,9 +1 @@
print("\27[93m"..tostring(#cormgr.corList).."\27[0m coroutines active")
for i=1, #cormgr.corList do
if i==#cormgr.corList then
print("\27[93m└ "..i.."\27[0m - "..cormgr.labelList[i].." \27[0m")
else
print("\27[93m├ "..i.."\27[0m - "..cormgr.labelList[i].." \27[0m")
end
end
Error: no such file. (``)
+1 -320
View File
@@ -1,320 +1 @@
local serialize = import("serialize")
local component = import("component")
local computer = import("computer")
local unicode = import("unicode")
local width,height = component.gpu.getResolution()
local args = {...}
local showAll = not not (table.find(args,"-a") or table.find(args,"--all"))
local tablePos = {}
local tableOut = {}
local headers = {
["slot"]="SLOT",
["capacity"]="CAPACITY",
["managed"]="MANAGED",
["readOnly"]="READ-ONLY",
["id"]="FULL COMPONENT ID",
["mount"]="MOUNT",
["bootable"]="BOOTABLE",
["label"]="LABEL"
}
local headerAlign = {
["slot"]=false,
["capacity"]=true,
["managed"]=false,
["readOnly"]=false,
["id"]=false,
["mount"]=false,
["bootable"]=false,
["label"]=false
}
local function addHeader(id)
table.insert(tableOut,{headerAlign[id],headers[id]})
tablePos[id]=#tableOut
end
for i,v in pairs(tablePos) do print(i,v) end
local function everyHeader()
addHeader("slot")
addHeader("capacity")
addHeader("managed")
addHeader("readOnly")
addHeader("id")
addHeader("mount")
addHeader("bootable")
addHeader("label")
end
local function defaultHeaders()
if width>100 then addHeader("slot") end
addHeader("capacity")
if width>80 then addHeader("id") end
addHeader("mount")
addHeader("label")
end
local function invalidArgSyntax(err)
print(err)
return shell.run("help lsdrv")
end
local outArgIdx = table.find(args,"-o") or table.find(args,"--output")
if showAll then
everyHeader()
elseif outArgIdx then
table.remove(args,outArgIdx)
local arg = table.remove(args,outArgIdx)
if not arg then return invalidArgSyntax("Argument -o must have a value") end
if arg=="all" then
everyHeader()
else
if arg:sub(1,1)=="+" then
defaultHeaders()
end
for word in string.gmatch(arg:sub(2),"([^,]+)") do
if headers[word] then
addHeader(word)
else
print("\x1b[93mCategory \""..word.."\" doesn't exist\x1b[39m")
end
end
end
else
defaultHeaders()
end
local function headerUsed(id)
return not not tablePos[id]
end
local bibytes = not (table.find(args,"-H") or table.find(args,"--si"))
local function formatSize(mem)
local units = bibytes and {"B","KiB","MiB","GiB"} or {"B","KB","MB","GB"}
local unit = 1
local unitStep = bibytes and 1024 or 1000
while mem > unitStep and units[unit] do
unit = unit + 1
mem = mem/unitStep
end
local memStr = tostring(mem):sub(1,5)
if unicode.sub(memStr,-2)==".0" then
memStr=unicode.sub(memStr,1,-3)
end
return memStr.." "..units[unit]
end
local function fileExists(proxy,path)
return proxy.exists(path) and not proxy.isDirectory(path)
end
local function getBootCode(proxy)
local sector1 = proxy.readSector(1)
for i = 1,#sector1 do
if sector1:sub(i,i)=="\0" then
sector1 = sector1:sub(1,i-1)
break
end
end
return sector1
end
local function isBootable(proxy,type)
if type=="drive" then
return not not load(getBootCode(proxy))
elseif type=="filesystem" then
return not not (fileExists(proxy,"/init.lua") or fileExists(proxy,"/OS.lua"))
end
end
local function formatBoolean(bool)
return ({[true]="Yes",[false]="No"})[bool]
end
local function handleComponent(id,type)
if not id then return end
local proxy = component.proxy(id)
if not proxy then return end
-- local out = {}
-- for i=1,#tableOut do table.insert(out,"unknown") end
local slot,capacity,managed,readOnly,mount,bootable,label
local cslot = component.slot(id)
if cslot==-1 then
slot="Virtual"
elseif cslot==9 then
slot="EEPROM"
else
slot="#"..(cslot+2)
end
managed="Yes"
readOnly="No"
if type=="drive" then
managed="No"
capacity=formatSize(proxy.getCapacity())
mount="/special/drive/"..id:sub(1,3)
elseif type=="filesystem" then
capacity=formatSize(proxy.spaceTotal())
if proxy.isReadOnly() then
readOnly="Yes"
end
mount="/mnt/"..id:sub(1,3)
if computer.getBootAddress()==id then mount="/" end
if computer.tmpAddress()==id then
mount="/tmp"
slot="Temporary"
end
elseif type=="eeprom" then
capacity=formatSize(proxy.getSize()+proxy.getDataSize())
mount="/special/eeprom/"
end
if headerUsed("bootable") then
bootable = formatBoolean(isBootable(proxy,type))
end
if proxy.getLabel then
local clabel = proxy.getLabel()
label=clabel and serialize.string(clabel) or "None"
else
label="Unsupported"
end
local function insertElement(i,v)
if not tablePos[i] then return end
table.insert(tableOut[tablePos[i]],v or "unknown")
end
insertElement("slot",slot)
insertElement("capacity",capacity)
insertElement("managed",managed)
insertElement("readOnly",readOnly)
insertElement("id",id)
insertElement("mount",mount)
insertElement("bootable",bootable)
insertElement("label",label)
end
local function filter(tbl,test)
local i=1
while i<=#tbl do
if not test(tbl[i]) then
table.remove(tbl,i)
i=i-1
end
i=i+1
end
end
local function luaExpr(arg)
local func,err = load("local component,computer,type,id,readonly,capacity=... local managed,eeprom,halyde,tmp,proxy,slot,all=type==\"drive\",type==\"eeprom\",id==\""..computer.getBootAddress().."\",id==\""..computer.tmpAddress().."\",component.proxy(id),component.slot(id)+2,true return "..arg)
if func then
return function(comp)
local readOnly,capacity=false,nil
if comp[2]=="filesystem" then
readOnly=component.invoke(comp[1],"isReadOnly")
capacity=component.invoke(comp[1],"spaceTotal")
elseif comp[2]=="drive" then
capacity=component.invoke(comp[1],"getCapacity")
elseif comp[2]=="eeprom" then
capacity=component.invoke(comp[1],"getSize")+component.invoke(comp[1],"getDataSize")
end
return func(component,computer,comp[2],comp[1],readOnly,capacity)
end
else
return nil,err
end
end
local function boolToNum(val)
if type(val)=="boolean" then
if val then
return 1
else
return 0
end
end
return val
end
local comps = {}
for i,v in component.list("filesystem") do table.insert(comps,{i,v}) end
for i,v in component.list("drive") do table.insert(comps,{i,v}) end
for i,v in component.list("eeprom") do table.insert(comps,{i,v}) end
if not showAll then
local showArgIdx = table.find(args,"-s") or table.find(args,"--show")
if showArgIdx then
table.remove(args,showArgIdx)
local arg = table.remove(args,showArgIdx)
if not arg then return invalidArgSyntax("Argument -s must have a value") end
local func,err = luaExpr(arg)
if func then
filter(comps,func)
else
return print("\x1b[91mInvalid component filter:\n\n"..tostring(err).."\x1b[39m")
end
else
filter(comps,function(comp)
return comp[2]~="eeprom" and comp[1]~=computer.tmpAddress()
end)
end
end
local sortArgIdx = table.find(args,"-S") or table.find(args,"--sort")
if sortArgIdx then
table.remove(args,sortArgIdx)
local arg = table.remove(args,sortArgIdx)
if not arg then return invalidArgSyntax("Argument -S must have a value") end
local func,err = luaExpr(arg)
if func then
table.sort(comps,function(a,b)
return (boolToNum(func(a)) or 0)<(boolToNum(func(b)) or 0)
end)
else
return print("\x1b[91mInvalid sort expression:\n\n"..tostring(err).."\x1b[39m")
end
else
table.sort(comps,function(a,b)
return a[1]<b[1]
end)
end
if #comps>0 then
for i,v in ipairs(comps) do handleComponent(v[1],v[2]) end
else
return print("Could not find storage components for this filter.")
end
local function renderTableOutput()
local lines = {}
for i=1,#tableOut[1]-1 do
table.insert(lines,"")
end
for i=1,#tableOut do
local length = 1
for j=1,#lines do
tableOut[i][j+1]=tableOut[i][j+1] or "[nil]"
length = math.max(length,unicode.wlen(tableOut[i][j+1]))
end
for j=1,#lines do
if tableOut[i][1] then
lines[j]=lines[j]..string.rep(" ",length-unicode.wlen(tableOut[i][j+1]))..tableOut[i][j+1]
elseif i<#tableOut then
lines[j]=lines[j]..tableOut[i][j+1]..string.rep(" ",length-unicode.wlen(tableOut[i][j+1]))
else
lines[j]=lines[j]..tableOut[i][j+1]
end
if i<#tableOut then lines[j]=lines[j].." " end
end
end
print(lines[1].."\n")
for i=2,#lines do
print(lines[i])
end
end
renderTableOutput()
Error: no such file. (``)
+1 -31
View File
@@ -1,31 +1 @@
print("\27[44m".._VERSION.."\27[0m shell")
print('Type "exit" to exit.')
termlib.readHistory["lua"] = {""}
local fs = import("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'
end
end
while true do
local command = read("lua", "\27[44mlua>\27[0m ")
if command == "exit" then
return
else
local function runCommand()
local func = load(loadedLibraries.."return "..command,"=stdin") or load(loadedLibraries..command,"=stdin")
local res = {assert(func)()}
if res and (type(res[1])~="nil" or type(res[2])~="nil") then print(table.unpack(res)) end
end
local result, reason = xpcall(runCommand, function(errMsg)
return errMsg .. "\n\n" .. debug.traceback()
end)
if not result then
print("\27[91m" .. reason)
end
end
end
Error: no such file. (``)
+1 -8
View File
@@ -1,8 +1 @@
local computer = import("computer")
if type(computer)~="table" then
return print("\x1b[91mComputer library returned '"..type(computer).."' type\x1b[39m")
end
local address = computer.getBootAddress()
print(address)
Error: no such file. (``)
+1 -14
View File
@@ -1,14 +1 @@
local directory = ...
local fs = import("filesystem")
if not directory then
shell.run("help mkdir")
return
end
if directory:sub(1, 1) ~= "/" then
directory = fs.concat(shell.workingDirectory, directory)
end
if fs.exists(directory) then
print("\27[91mAn object already exists at the specified path.")
end
fs.makeDirectory(directory)
Error: no such file. (``)
+1 -24
View File
@@ -1,24 +1 @@
local fromFile, toFile = ...
local fs = import("filesystem")
if not fromFile or not toFile then
shell.run("help mv")
return
end
if fromFile:sub(1, 1) ~= "/" then
fromFile = fs.concat(shell.workingDirectory, fromFile)
end
if toFile:sub(1, 1) ~= "/" then
toFile = fs.concat(shell.workingDirectory, toFile)
end
if fromFile == toFile then
print("\27[91mSource and destination are the same.")
end
if not fs.exists(fromFile) then
print("\27[91mSource file does not exist.")
end
if fs.exists(toFile) and not (table.find({...}, "-o") or table.find({...}, "--overwrite")) then
print("\27[91mDestination file already exists. Run this command again with -o to overwrite it.")
return
end
fs.rename(fromFile, toFile)
Error: no such file. (``)
+1 -1
View File
@@ -1 +1 @@
import("computer").shutdown(true)
Error: no such file. (``)
+1 -15
View File
@@ -1,15 +1 @@
local file = ...
local fs = import("filesystem")
if not file then
shell.run("help rm")
return
end
if file:sub(1, 1) ~= "/" then
file = fs.concat(shell.workingDirectory, file)
end
if not fs.exists(file) then
print("\27[91mFile does not exist.")
return
end
fs.remove(file)
Error: no such file. (``)
+1 -91
View File
@@ -1,91 +1 @@
local raster = import("raster")
raster.init()
--[[for i=4,20 do
raster.set(i,i)
raster.set(i,i+4,0xFF00FF)
end]]
--[[ for x=4,20 do
for y=4,20 do
if (x+y)%2==0 then
raster.set(x,y,0xFF00FF)
end
end
end ]]
local event = import("event")
local x=0
local y=0
local vx=1
local vy=1
local col = 0x808080
local i=0
while event.pull("key_down",0)==nil do
i = i + 1
raster.set(x,y,col)
x = x + vx
y = y + vy
if x>raster.displayWidth then
x=raster.displayWidth
vx = -math.abs(vx)
col = math.random(0,0xFFFFFF)
end
if x<1 then
x=1
vx = math.abs(vx)
col = math.random(0,0xFFFFFF)
end
if y>raster.displayHeight-6 then
y=raster.displayHeight-6
vy = -math.abs(vy)
col = math.random(0,0xFFFFFF)
end
if y<1 then
y=1
vy = math.abs(vy)
col = math.random(0,0xFFFFFF)
end
if i>10 and i%15>0 then
while true do
local tries=0
local dx,dy=math.random(1,raster.displayWidth),math.random(1,raster.displayHeight-6)
if raster.get(dx,dy)~=0 then
raster.set(dx,dy,0)
break
end
tries = tries + 1
if tries>20 then
break
end
end
end
if i%10==0 then
raster.update()
coroutine.yield()
end
end
--[[ for i=0,360,4 do
local angle = i/180*math.pi
if false then
local x1,y1,x2,y2=raster.displayWidth/2,raster.displayHeight/2,raster.displayWidth/2+math.sin(angle)*80,raster.displayHeight/2+math.cos(angle)*80
raster.fillEllipse(x1,y1,x2,y2,0xFF00FF)
raster.update()
raster.fillEllipse(x1,y1,x2,y2,0x000000)
else
local x,y,c=raster.displayWidth/2,raster.displayHeight/2,math.abs(math.sin(angle)*100)
raster.drawCircle(x,y,c,0xFF00FF)
raster.update()
raster.drawCircle(x,y,c,0x000000)
end
end ]]
raster.free()
termlib.cursorPosY=1
Error: no such file. (``)
+1 -141
View File
@@ -1,141 +1 @@
local component = import("component")
local computer = import("computer")
local raster = import("raster")
local event = import("event")
-- Initialize the 3D renderer for a spinning cube
-- Using the raster library for drawing
-- Screen dimensions
local SCREEN_WIDTH, SCREEN_HEIGHT = component.invoke(component.list("gpu")(), "getResolution")
SCREEN_WIDTH, SCREEN_HEIGHT = SCREEN_WIDTH * 2, SCREEN_HEIGHT * 4
local CENTER_X = SCREEN_WIDTH / 2
local CENTER_Y = SCREEN_HEIGHT / 2
-- Cube properties
local CUBE_SIZE = 10
local increment = 0
local WHITE = 0xFFFFFF
local ROTATION_SPEED = 0.1
-- 3D cube vertices (centered at origin)
local vertices = {
{-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 0: left bottom back
{CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 1: right bottom back
{CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 2: right top back
{-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 3: left top back
{-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 4: left bottom front
{CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 5: right bottom front
{CUBE_SIZE, CUBE_SIZE, CUBE_SIZE}, -- 6: right top front
{-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE} -- 7: left top front
}
-- Cube edges defined by vertex indices
local edges = {
{0, 1}, {1, 2}, {2, 3}, {3, 0}, -- back face
{4, 5}, {5, 6}, {6, 7}, {7, 4}, -- front face
{0, 4}, {1, 5}, {2, 6}, {3, 7} -- connecting edges
}
-- Projection parameters
local FOV = 256 -- Field of view (distance from camera to screen)
local Z_OFFSET = 300 -- Distance from camera to cube center
-- Initialize rotation angles
local angleX, angleY, angleZ = 0, 0, 0
-- Matrix multiplication function (apply rotation to a 3D point)
local function rotatePoint(x, y, z)
-- Rotation around X axis
local cosX, sinX = math.cos(angleX), math.sin(angleX)
local y1 = y * cosX - z * sinX
local z1 = y * sinX + z * cosX
-- Rotation around Y axis
local cosY, sinY = math.cos(angleY), math.sin(angleY)
local x1 = x * cosY + z1 * sinY
local z2 = -x * sinY + z1 * cosY
-- Rotation around Z axis
local cosZ, sinZ = math.cos(angleZ), math.sin(angleZ)
local x2 = x1 * cosZ - y1 * sinZ
local y2 = x1 * sinZ + y1 * cosZ
return x2, y2, z2
end
-- Perspective projection function (3D to 2D)
local function projectPoint(x, y, z)
-- Apply perspective projection
local scale = FOV / (z + Z_OFFSET)
local x2d = x * scale + CENTER_X
local y2d = y * scale + CENTER_Y
return x2d, y2d
end
-- Render a single frame
local function renderFrame()
local time = computer.uptime()*20
increment = time*0.05 -- increment + 0.05
CUBE_SIZE = (math.sin(increment) + 1) * 25
vertices = {
{-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 0: left bottom back
{CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 1: right bottom back
{CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 2: right top back
{-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 3: left top back
{-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 4: left bottom front
{CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 5: right bottom front
{CUBE_SIZE, CUBE_SIZE, CUBE_SIZE}, -- 6: right top front
{-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE} -- 7: left top front
}
-- Update rotation angles
raster.clear()
angleX = time * ROTATION_SPEED -- angleX
angleY = time * ROTATION_SPEED * 0.7 -- angleY
angleZ = time * ROTATION_SPEED * 0.5 -- angleZ
-- Project all vertices
local projectedPoints = {}
for i, vertex in ipairs(vertices) do
-- Rotate the point
local x, y, z = rotatePoint(vertex[1], vertex[2], vertex[3])
-- Project the point to 2D
local x2d, y2d = projectPoint(x, y, z)
projectedPoints[i] = {x2d, y2d}
end
-- Draw all edges
for _, edge in ipairs(edges) do
local p1 = projectedPoints[edge[1] + 1] -- +1 because Lua indices start at 1
local p2 = projectedPoints[edge[2] + 1]
-- Draw the line
raster.drawLine(p1[1], p1[2], p2[1], p2[2], WHITE)
end
-- Render the frame
raster.update()
end
-- Main program
function main()
-- Initialize raster engine
raster.init()
-- Main loop (assume this is called repeatedly by the host environment)
while true do
renderFrame()
coroutine.yield()
if event.pull("key_down", 0) then
raster.free()
break
end
end
-- Return a reference to renderFrame so it can be called for animation
return renderFrame
end
-- Start the program
return main()
Error: no such file. (``)
+1 -1
View File
@@ -1 +1 @@
import("computer").shutdown()
Error: no such file. (``)
+1 -98
View File
@@ -1,98 +1 @@
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")
Error: no such file. (``)
+1 -97
View File
@@ -1,97 +1 @@
_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
Error: no such file. (``)
+1 -45
View File
@@ -1,45 +1 @@
local conversionTables = {
["bytes"] = {
["B"] = 1,
["KB"] = 1000,
["MB"] = 1000000,
["GB"] = 1000000000
}, ["bibytes"] = {
["B"] = 1,
["KiB"] = 1024,
["MiB"] = 1048576,
["GiB"] = 1073741824
}
}
function table.find(tab, item)
for k, v in pairs(tab) do
if v == item then
return k
end
end
end
function table.copy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[table.copy(orig_key)] = table.copy(orig_value)
end
setmetatable(copy, table.copy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
function convert(amount, fromUnit, toUnit)
for _, convTable in pairs(conversionTables) do
if convTable[toUnit] then
return amount / convTable[toUnit] * convTable[fromUnit]
end
end
return false, "unit does not exist"
end
Error: no such file. (``)
+1 -46
View File
@@ -1,46 +1 @@
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
Error: no such file. (``)
+1 -55
View File
@@ -1,55 +1 @@
_G.evmgr = {}
_G.evmgr.eventQueue = {}
local maxEventQueueLength = 10 -- increase if events start getting dropped
local computer = import("computer")
keyboard.ctrlDown = false
keyboard.altDown = false
keyboard.shiftDown = false
--local ocelot = component.proxy(component.list("ocelot")())
while true do
local args
repeat
args = {computer.uptime(), computer.pullSignal(0)}
if args and args[2] then
table.insert(evmgr.eventQueue, args)
if keyboard then
if args[2] == "key_down" then
local keycode = args[5]
local key = keyboard.keys[keycode]
if key == "lcontrol" then
keyboard.ctrlDown = true
elseif key == "lmenu" then
keyboard.altDown = true
elseif key == "lshift" then
keyboard.shiftDown = true
elseif key == "c" and keyboard.ctrlDown and keyboard.altDown then
if print then
print("\n\27[91mCoroutine "..tostring(#cormgr.corList).." killed.")
end
cormgr.corList[#cormgr.corList] = nil
end
elseif args[2] == "key_up" then
local keycode = args[5]
local key = keyboard.keys[keycode]
if key == "lcontrol" then
keyboard.ctrlDown = false
elseif key == "lmenu" then
keyboard.altDown = false
elseif key == "lshift" then
keyboard.shiftDown = true
end
end
end
while #evmgr.eventQueue > maxEventQueueLength do
--ocelot.log("Queue length breach, removing first signal")
table.remove(evmgr.eventQueue, 1)
end
end
until not args or not args[1]
--ocelot.log("done")
coroutine.yield()
end
Error: no such file. (``)
+1 -143
View File
@@ -1,143 +1 @@
_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
})
Error: no such file. (``)
+1 -106
View File
@@ -1,106 +1 @@
local fs = import("filesystem")
local json = import("json")
local handle, data, tmpdata = fs.open("/halyde/config/shell.json", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local shellcfg = json.decode(data)
import("/halyde/core/termlib.lua")
local event = import("event")
local component = import("component")
local gpu = component.gpu
_G.shell = {}
_G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"]
_G.shell.aliases = shellcfg["aliases"]
local function runAsCoroutine(path, ...)
--ocelot.log("running " .. path .. " as coroutine")
cormgr.loadCoroutine(path, ...)
local corIndex = #cormgr.corList
local cor = cormgr.corList[#cormgr.corList]
repeat
coroutine.yield()
until cormgr.corList[corIndex] ~= cor
end
function _G.shell.run(command)
checkArg(1, command, "string")
if shell.aliases[command:match("[^ ]+")] then
local _, cmdend = command:find("[^ ]+")
command = shell.aliases[command:match("[^ ]+")] .. command:sub(cmdend + 1)
end
local gm, result, args, trimmedCommand = command:gmatch("[^ ]+"), nil, {}, command
while true do
result = gm()
if not result then
break
end
if result:find('"') then
local location = trimmedCommand:find('"')
local argBefore = result:sub(1, result:find('"') - 1) -- edge case where there is no space before the quote, get the argument there
if argBefore and argBefore ~= "" then
table.insert(args, argBefore)
end
trimmedCommand = trimmedCommand:sub(location + 1)
if trimmedCommand:find('"') then
table.insert(args, trimmedCommand:sub(1, trimmedCommand:find('"') - 1))
trimmedCommand = trimmedCommand:sub(trimmedCommand:find('"') + 1)
gm = trimmedCommand:gmatch('[^ ]+')
else
print("\27[91mmalformed shell command")
return
end
else
table.insert(args, result)
end
end
-- execute the program
local PATH = table.copy(shellcfg.path)
table.insert(PATH, shell.workingDirectory)
if not args[1] then
return
end
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))
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))
return
else -- try to look for it without the file extension
local files = fs.list(item) or {}
for _, file in pairs(files) do
-- previous pattern: (.+)%.[^%.]+$
if args[1] == file:match("(.+)%.[^%.]+$") and not fs.isDirectory(item .. file) then
table.remove(args, 1)
runAsCoroutine(item .. file, table.unpack(args))
return
end
end
end
end
print("No such file or command: "..args[1])
end
print(shellcfg["startupMessage"]:format(_OSVERSION, shellcfg.splashMessages[math.random(1, #shellcfg.splashMessages)]))
while true do
coroutine.yield()
-- print(shell.workingDirectory .. " >")
--print(shellcfg["prompt"]:format(shell.workingDirectory),false)
-- termlib.cursorPosX = #(shell.workingDirectory .. " > ")
-- termlib.cursorPosY = termlib.cursorPosY - 1
if shell.workingDirectory:sub(-1, -1) ~= "/" then
shell.workingDirectory = shell.workingDirectory .. "/"
end
local shellCommand = read("shell", shellcfg.prompt:format(shell.workingDirectory))
shell.run(shellCommand)
gpu.freeAllBuffers()
end
Error: no such file. (``)
+1 -453
View File
@@ -1,453 +1 @@
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 maxChars<math.huge then
chr=unicode.sub(chr,1,maxChars-unicode.len(text))
end
text=unicode.sub(text,1,cur-1)..chr..unicode.sub(text,cur)
set(curPos(cur),chr,false)
cur=math.min(cur+unicode.len(chr),maxChars+1)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
set(curPos(cur+1),unicode.sub(text,cur+1),false)
end
local function moveCur(dir)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
cur=math.max(math.min(cur+dir,unicode.len(text)+1),1)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
end
local function isLetter(chr)
return not string.find("\x09 :@-./_~?&=%+#",chr,1,true)
end
local function nextCur(dir,chr,icur)
if icur==nil then icur=cur end
local next = math.max(math.min(icur+dir,unicode.len(text)+1),1)
if chr then return unicode.sub(text,next,next) end
return next
end
local function curAfterWord(dir)
local ncur = cur
while nextCur(dir,false,ncur)~=ncur and isLetter(nextCur(dir,true,ncur))==(dir==1) do
ncur=nextCur(dir,false,ncur)
end
while nextCur(dir,false,ncur)~=ncur and isLetter(nextCur(dir,true,ncur))==(dir==-1) do
ncur=nextCur(dir,false,ncur)
end
return ncur
end
local function moveWord(dir)
if nextCur(dir)==cur then return end
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
cur=curAfterWord(dir)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
cursorBlink = true
end
local function deleteWord(dir)
local after = curAfterWord(dir)
local lenb = unicode.wlen(text)
if dir==1 then
text=unicode.sub(text,1,cur-1)..unicode.sub(text,after)
set(curPos(cur+1),unicode.sub(text,cur+1)..string.rep(" ",lenb-unicode.wlen(text)+1),false)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
else
text = unicode.sub(text,1,after-1)..unicode.sub(text,cur)
cur=after
set(curPos(cur+1),unicode.sub(text,cur+1)..string.rep(" ",lenb-unicode.wlen(text)+1),false)
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
end
updateHistory()
cursorBlink = true
end
local function isLine(chr)
return chr=="\n" or chr=="\r"
end
--[[ gpu.set(startX,startY,unicode.sub(text,1,width-startX))
for i=1,(#text+startX)//width-1 do
gpu.set(startX,startY+i,unicode.sub(text,1+i*width,width-startX+i*width))
end ]]
set(1,text,false)
set(curPos(cur)," ",true)
local function reprint(new)
set(1,new..string.rep(" ",unicode.wlen(text)-unicode.wlen(new)+1),false)
cur=unicode.len(new)+1
text=new
set(curPos(cur)," ",true)
end
while true do
local args = {event.pull("key_down", "clipboard", 0.5)}
if args and args[1] == "key_down" and args[4] then
local key = keyboard.keys[args[4]]
if key=="up" and readHistoryType then
historyIdx=math.max(historyIdx-1,1)
reprint(termlib.readHistory[readHistoryType][historyIdx])
elseif key=="down" and readHistoryType then
historyIdx=math.min(historyIdx+1,#termlib.readHistory[readHistoryType])
reprint(termlib.readHistory[readHistoryType][historyIdx])
elseif key=="left" and keyboard.ctrlDown then
moveWord(-1)
elseif key=="right" and keyboard.ctrlDown then
moveWord(1)
elseif key=="left" then
moveCur(-1)
elseif key=="right" then
moveCur(1)
elseif key=="home" then
moveCur(-math.huge)
elseif key=="end" then
moveCur(math.huge)
elseif key=="back" and keyboard.ctrlDown then
deleteWord(-1)
elseif key=="delete" and keyboard.ctrlDown then
deleteWord(1)
elseif key=="back" and cur>1 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
Error: no such file. (``)
+1 -97
View File
@@ -1,97 +1 @@
local compLib
local LLcomponent
if table.copy then
compLib = table.copy(component)
LLcomponent = table.copy(component)
else
compLib = {}
LLcomponent = component
end
--local ocelot = LLcomponent.proxy(LLcomponent.list("ocelot")())
--ocelot.log("loaded")
_G.componentlib = {["additions"] = {}, ["removals"] = {}}
compLib.virtual = {}
function compLib.virtual.add(address, componentType, proxy)
checkArg(1, address, "string")
checkArg(2, componentType, "string")
checkArg(3, proxy, "table")
proxy["address"] = address
componentlib.additions[address] = {["componentType"] = componentType, ["proxy"] = proxy}
if componentlib.removals[address] then
componentlib.removals[address] = nil
end
end
function compLib.virtual.remove(address)
checkArg(1, address, "string")
if componentlib.additions[address] then
componentlib.additions[address] = nil
else
table.insert(componentlib.removals, address)
end
end
function compLib.list(componentType)
checkArg(1, componentType, "string", "nil")
local componentList = table.copy(LLcomponent.list(componentType))
for address, dataTable in pairs(componentlib.additions) do
if dataTable.componentType == componentType or not componentType then
componentList[address] = dataTable.componentType
end
end
for _, address in pairs(componentlib.removals) do
componentList[address] = nil
end
local i, value
setmetatable(componentList, {__call = function(self)
i, value = next(self, i)
return i, value
end})
return componentList
end
function compLib.proxy(address)
if componentlib.additions[address] then
--ocelot.log("vcomponent")
return componentlib.additions[address].proxy
else
return LLcomponent.proxy(address)
end
end
function compLib.invoke(address, funcName, ...)
--ocelot.log("Invoking " .. funcName .. " from " .. address)
if componentlib.additions[address] then
--ocelot.log("vcomponent")
return componentlib.additions[address].proxy[funcName](...)
else
return LLcomponent.invoke(address, funcName, ...)
end
end
function compLib.get(address)
checkArg(1, address, "string")
if #address < 3 then
return nil, "abbreviated address must be at least 3 characters long"
end
for currentAddress, name in compLib.list() do
if currentAddress:find("^" .. address) then
return(currentAddress)
end
end
return nil, "full address not found"
end
-- Add main component proxies to the library
setmetatable(compLib, {["__index"] = function(_, item)
if compLib.list(item)() then
return compLib.proxy(compLib.list(item)())
else
return compLib[item]
end
end})
return compLib
Error: no such file. (``)
+1 -14
View File
@@ -1,14 +1 @@
local computerlib = table.copy(computer)
local LLcomputer = table.copy(computer)
function computerlib.pullSignal(timeout)
local startTime = LLcomputer.uptime()
local result
repeat
result = {LLcomputer.pullSignal(0)}
coroutine.yield()
until result or timeout and LLcomputer.uptime() >= startTime + timeout
return table.unpack(result)
end
return computerlib
Error: no such file. (``)
+1 -55
View File
@@ -1,55 +1 @@
local computer = import("computer")
local event = {}
local bufferTime = 0.1 -- A little bit of buffer time so events won't be skipped by accident.
--local ocelot = component.proxy(component.list("ocelot")())
function event.pull(...)
local args = {...}
local evtypes, timeout = {}, nil
for _, arg in pairs(args) do
if type(arg) == "number" and not timeout then -- It's a timeout
timeout = arg
else -- It's an event type
table.insert(evtypes, tostring(arg))
end
end
local startTime = computer.uptime()
while true do
-- Check event queue for matching event
for i = 1, #evmgr.eventQueue do
local foundevent = false
if evtypes[1] then -- event type(s) specified
for _, evtype in pairs(evtypes) do
if evmgr.eventQueue[i][2] == evtype and evmgr.eventQueue[i][1] >= startTime - bufferTime then
foundevent = true
end
end
else
if evmgr.eventQueue[i][1] >= startTime - bufferTime then
foundevent = true
end
end
if foundevent then
-- Found matching event (or any event if no type specified)
local result = table.copy(evmgr.eventQueue[i])
table.remove(evmgr.eventQueue, i)
table.remove(result, 1) -- remove the time of event argument
return table.unpack(result)
end
end
-- Check if we've timed out
if timeout and computer.uptime() >= startTime + timeout then
return nil -- Timed out, return nil
end
-- Yield to allow other processes to run and more events to be added
coroutine.yield()
end
end
return event
Error: no such file. (``)
+1 -506
View File
@@ -1,506 +1 @@
local loadfile = ... -- raw loadfile from boot.lua
local component, computer
if loadfile then
unicode = loadfile("/halyde/lib/unicode.lua")(loadfile)
component = loadfile("/halyde/lib/component.lua")(loadfile)
computer = _G.computer
elseif import then
unicode = import("unicode")
component = import("component")
computer = import("computer")
end
local filesystem = {}
function filesystem.canonical(path)
checkArg(1, path, "string")
local segList = {}
if path:sub(1, 1) ~= "/" then
path = "/" .. path
end
path = path:gsub("/+", "/")
for segment in path:gmatch("[^/]+") do
if segment == ".." and segList[1] then
table.remove(segList, #segList)
elseif segment ~= "." then
table.insert(segList, segment)
end
end
return "/" .. table.concat(segList, "/")
end
function filesystem.concat(...)
local paths = {...}
for i, path in ipairs(paths) do
checkArg(i, path, "string")
end
local currentPath = paths[1]:match("(.+)/?$")
for i = 2, #paths do
currentPath = currentPath .. "/" .. paths[i]:match("^/?(.+)/?$")
end
return currentPath
end
function filesystem.absolutePath(path) -- returns the address and absolute path of an object
checkArg(1, path, "string")
path = filesystem.canonical(path)
local address = nil
if path:find("^/tmp") then
address = computer.tmpAddress()
path = path:sub(5)
elseif path:find("^/mnt/...") then
address = component.get(path:sub(6,8))
if not address then
address = computer.getBootAddress()
else
path = path:sub(9)
end
else
address = computer.getBootAddress()
end
if not address then
return nil, "no such component"
end
return address, path
end
function filesystem.exists(path) -- check if path exists
checkArg(1, path, "string")
local address, absPath = filesystem.absolutePath(path)
if not address then
return false
end
if absPath:find("^/special/drive/...") then
return not not (computer.getBootAddress() and component.get(absPath:sub(16,18)))
end
if absPath:find("^/special/eeprom/") then
return table.find({"init.lua","data.bin","label.txt"},absPath:sub(17))
end
return component.invoke(address, "exists", absPath)
end
local function readBytes(self,n)
n = n or 1
if n==1 then
local byte = self:read(1)
if byte==nil then return nil end
return string.byte(byte)
end
local bytes, res = {string.byte(self:read(n),1,n)}, 0
if self.littleEndian then
for i=#bytes,1,-1 do
res = (res<<8)&0xFFFFFFFF | bytes[i]
end
else
for i=1,#bytes do
res = (res<<8)&0xFFFFFFFF | bytes[i]
end
end
return res
end
local function readUnicodeChar(self)
return unicode.readChar(function()
return self:readBytes(1)
end)
end
local function iterateBytes(self)
return function()
local byte = readBytes(self,1)
if byte==nil then self:close() end
return byte
end
end
local function iterateUnicodeChars(self)
return unicode.iterate(iterateBytes(self))
end
function filesystem.makeReadStream(content)
local properHandle = {}
local readcursor = 1
function properHandle.read(self, amount)
checkArg(2, amount, "number")
local limit = string.len(content)+1
local out = nil
if readcursor<limit then
if amount==math.huge then
out = string.sub(content,math.min(readcursor,limit))
else
out = string.sub(content,math.min(readcursor,limit),math.min(readcursor+amount-1,limit))
end
end
readcursor=readcursor+amount
if out=="" then
return nil
end
return out
end
properHandle.readBytes = readBytes
properHandle.readUnicodeChar = readUnicodeChar
properHandle.iterateBytes = iterateBytes
properHandle.iterateUnicodeChars = iterateUnicodeChars
function properHandle.write()
return nil
end
function properHandle.close()
content=nil
end
return properHandle
end
function filesystem.open(path, mode, buffered) -- opens a file and returns its handle
checkArg(1, path, "string")
checkArg(2, mode, "string", "nil")
checkArg(3, buffered, "boolean", "nil")
if not mode then
mode = "r"
end
if buffered == nil then
buffered = true
end
if not (mode == "r" or mode == "w" or mode == "rb" or mode == "wb" or mode == "a" or mode == "ab") then
return nil, "invalid handle type"
end
if path:find("^/special") and not filesystem.exists(path) then
return nil, "/special does not allow creating files"
end
local address, absPath = filesystem.absolutePath(path)
local unmanagedDrive = address==computer.getBootAddress() and absPath:find("^/special/drive")
local unmanagedProxy, sectorSize, sectorCount, handle
if unmanagedDrive then
unmanagedProxy = component.proxy(component.get(absPath:sub(16,18)))
sectorSize = unmanagedProxy.getSectorSize()
sectorCount = math.ceil(unmanagedProxy.getCapacity()/sectorSize)
elseif not (address==computer.getBootAddress() and absPath:find("^/special/")) then
local handleArgs = {component.invoke(address, "open", absPath, mode)}
handle = handleArgs[1]
if not handle then
return table.unpack(handleArgs)
end
handleArgs = nil
end
local properHandle = {}
properHandle.handle = handle
properHandle.address = address
local content = nil
local readcursor = 1
if buffered and mode:sub(1,1)=="r" then
content=""
repeat
tmpdata = component.invoke(address, "read", handle, math.huge or math.maxinteger)
content = content .. (tmpdata or "")
until not tmpdata
component.invoke(address, "close", handle)
end
function properHandle.read(self, amount)
checkArg(2, amount, "number")
if unmanagedDrive then
local sectorIdx = ((readcursor-1)//sectorSize)+1
if sectorIdx>sectorCount then return nil end
local sector = unmanagedProxy.readSector(sectorIdx)
local data = sector:sub(((readcursor-1)%sectorSize)+1,((readcursor+math.min(amount,sectorSize)-2)%sectorSize)+1)
readcursor=readcursor+#data
if data=="" then return nil end
return data
else
if buffered then
local limit = string.len(content)+1
local out = nil
if readcursor<limit then
if amount==math.huge then
out = string.sub(content,math.min(readcursor,limit))
else
out = string.sub(content,math.min(readcursor,limit),math.min(readcursor+amount-1,limit))
end
end
readcursor=readcursor+amount
if out=="" then
return nil
end
return out
else
return component.invoke(self.address, "read", self.handle, amount)
end
end
end
properHandle.readBytes = readBytes
properHandle.readUnicodeChar = readUnicodeChar
properHandle.iterateBytes = iterateBytes
properHandle.iterateUnicodeChars = iterateUnicodeChars
function properHandle.write(self, data)
checkArg(2, data, "string")
if unmanagedDrive then
local startSector = ((readcursor-1)//sectorSize)+1
if startSector>sectorCount then return nil, "not enough space" end
local startSByte = ((readcursor-1)%sectorSize)+1
local sect = unmanagedProxy.readSector(startSector)
unmanagedProxy.writeSector(startSector,sect:sub(1,startSByte-1)..data:sub(1,sectorSize-startSByte+1))
for i=2,(#data+startSByte)//sectorSize do
if startSector+i-1>sectorCount then return nil, "not enough space" end
unmanagedProxy.writeSector(startSector+i-1,data:sub(startSByte+sectorSize*(i-1),startSByte+sectorSize*i-1))
end
readcursor=readcursor+#data
return true
else
return component.invoke(self.address, "write", self.handle, data)
end
end
function properHandle.close(self)
if buffered then
content = nil
else
return component.invoke(self.address, "close", self.handle)
end
end
if address==computer.getBootAddress() then
local eeprom
pcall(function()
eeprom = component.eeprom
end)
if eeprom then
local getFunc, setFunc
if absPath=="/special/eeprom/init.lua" then
getFunc,setFunc = "get","set"
elseif absPath=="/special/eeprom/data.bin" then
getFunc,setFunc = "getData","setData"
elseif absPath=="/special/eeprom/label.txt" then
getFunc,setFunc = "getLabel","setLabel"
end
if mode:sub(1,1)=="r" and getFunc then
local stream = filesystem.makeReadStream(eeprom[getFunc]() or "")
properHandle.read = stream.read
properHandle.close = stream.close
elseif mode:sub(1,1)=="w" and setFunc then
local content = ""
function properHandle.write(self, data)
checkArg(2, data, "string")
content=content..data
end
function properHandle.close(self)
return eeprom[setFunc](content)
end
end
end
end
return properHandle
end
function filesystem.list(path)
checkArg(1, path, "string")
path = filesystem.canonical(path)
if path == "/mnt" then
-- list drives
local returnTable = {}
local tmpAddress = computer.tmpAddress()
for address, _ in component.list("filesystem") do
if address~=tmpAddress then
table.insert(returnTable, address:sub(1, 3) .. "/")
end
end
return returnTable
elseif path == "/special/drive" then
local returnTable = {}
local tmpAddress = computer.tmpAddress()
for address, type in component.list("drive") do
if address~=tmpAddress and type=="drive" then
table.insert(returnTable, address:sub(1, 3))
end
end
return returnTable
elseif path=="/special/eeprom" then
return {"init.lua","data.bin","label.txt"}
else
local address, absPath = filesystem.absolutePath(path)
if not address then
return false
end
return component.invoke(address, "list", absPath)
end
end
function filesystem.size(path)
checkArg(1, path, "string")
local address, absPath = filesystem.absolutePath(path)
if not address then
return false
end
if address==computer.getBootAddress() then
if absPath:find("^/special/drive") then
local drive = component.get(absPath:sub(16,18))
if not drive then return false end
return component.invoke(drive,"getCapacity")
elseif absPath:find("^/special/eeprom") then
local eeprom
pcall(function()
eeprom = component.eeprom
end)
if eeprom then
local getFunc
if absPath=="/special/eeprom/init.lua" then
getFunc = "get"
elseif absPath=="/special/eeprom/data.bin" then
getFunc = "getData"
elseif absPath=="/special/eeprom/label.txt" then
getFunc = "getLabel"
end
return #(eeprom[getFunc]())
end
end
end
return component.invoke(address, "size", absPath)
end
local function getRecursiveList(address,absPath)
local list = component.invoke(address,"list",absPath)
local dirList = {}
local listChanged = true
while listChanged do
listChanged = false
for i=1,#list do
if component.invoke(address, "isDirectory", absPath.."/"..list[i]) then
listChanged = true
local dir = list[i]
if dir:sub(-1)=="/" then dir=dir:sub(1,-2) end
table.insert(dirList,dir)
table.remove(list,i)
local subDir = component.invoke(address,"list",absPath.."/"..dir)
for j=1,#subDir do table.insert(list,dir.."/"..subDir[j]) end
end
end
end
return list,dirList
end
local function copyContent(fromHandle,toHandle)
if not (fromHandle and toHandle) then return end
local memory = math.floor(computer.freeMemory()*0.8)
local tmpdata
while true do
tmpdata = fromHandle:read(memory)
if not tmpdata then break end
local status,reason = toHandle:write(tmpdata)
if status~=true then break end
end
fromHandle:close()
toHandle:close()
end
local function copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath)
-- TODO: make this use copyContent
if fromAbsPath:sub(-1)=="/" then fromAbsPath=fromAbsPath:sub(1,-2) end
if toAbsPath:sub(-1)=="/" then toAbsPath=toAbsPath:sub(1,-2) end
component.invoke(toAddress,"makeDirectory",toAbsPath)
local fileList,dirList = getRecursiveList(fromAddress,fromAbsPath)
for i=1,#dirList do
component.invoke(toAddress,"makeDirectory",toAbsPath.."/"..dirList[i])
end
for i=1,#fileList do
local fromFile, toFile = fromAbsPath.."/"..fileList[i], toAbsPath.."/"..fileList[i]
--[[ local handle = component.invoke(fromAddress, "open", fromFile, "r")
local data, tmpdata = "", nil
repeat
tmpdata = component.invoke(fromAddress, "read", handle, math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = component.invoke(fromAddress, "close", handle)
local handle = component.invoke(toAddress, "open", toFile, "w")
component.invoke(toAddress, "write", handle, data)
component.invoke(toAddress, "close", handle) ]]
local fromHandle = component.invoke(fromAddress, "open", fromFile, "r")
local toHandle = component.invoke(toAddress, "open", toFile, "w")
copyContent({
["read"]=function(...) return component.invoke(fromAddress, "read", handle, ...) end,
["close"]=function(...) return component.invoke(fromAddress, "close", handle, ...) end
},{
["write"]=function(...) return component.invoke(fromAddress, "write", handle, ...) end,
["close"]=function(...) return component.invoke(fromAddress, "close", handle, ...) end
})
end
end
function filesystem.isDirectory(path)
checkArg(1, path, "string")
local address, absPath = filesystem.absolutePath(path)
if not address then
return false
end
return component.invoke(address, "isDirectory", absPath)
end
function filesystem.rename(fromPath, toPath)
checkArg(1, fromPath, "string")
checkArg(2, toPath, "string")
local fromAddress, fromAbsPath = filesystem.absolutePath(fromPath)
local toAddress, toAbsPath = filesystem.absolutePath(toPath)
if not fromAddress or not toAddress then
return false
end
if fromAddress == toAddress then
return component.invoke(fromAddress, "rename", fromAbsPath, toAbsPath)
elseif filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath) then
copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath)
filesystem.remove(fromPath) -- component.invoke(fromAddress,"remove", fromAbsPath)
else
local handle, data, tmpdata = filesystem.open(fromPath), "", nil -- component.invoke(fromAddress, "open", fromAbsPath, "r"), "", nil
repeat
tmpdata = handle:read(math.huge or math.maxinteger) -- component.invoke(fromAddress, "read", handle, math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = handle:close() -- component.invoke(fromAddress, "close", handle)
local handle = filesystem.open(toPath) -- component.invoke(toAddress, "open", toAbsPath, "w")
handle:write(data) -- component.invoke(toAddress, "write", handle, data)
handle:close() -- component.invoke(toAddress, "close", handle)
filesystem.remove(fromPath) -- component.invoke(fromAddress, "remove", fromAbsPath)
end
end
function filesystem.copy(fromPath, toPath)
checkArg(1, fromPath, "string")
checkArg(2, toPath, "string")
local fromAddress, fromAbsPath = filesystem.absolutePath(fromPath)
local toAddress, toAbsPath = filesystem.absolutePath(toPath)
if not fromAddress or not toAddress then
return false
end
if filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath)
copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath)
else
--[[ local handle = filesystem.open(fromPath,"r")
local data, tmpdata = "", nil
repeat
tmpdata = handle:read(math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = handle:close()
local handle = filesystem.open(toPath,"w")
handle:write(data)
handle:close() ]]
copyContent(filesystem.open(fromPath,"r"),filesystem.open(toPath,"w"))
end
end
function filesystem.remove(path)
checkArg(1, path, "string")
local address, absPath = filesystem.absolutePath(path)
if not address then
return false
end
if absPath:find("^/special") then return false end
if absPath:find("^/tmp") then return false end
if absPath:find("^/mnt") then return false end
return component.invoke(address, "remove", absPath)
end
function filesystem.makeDirectory(path)
checkArg(1, path, "string")
local address, absPath = filesystem.absolutePath(path)
if not address then
return false
end
return component.invoke(address, "makeDirectory", absPath)
end
return(filesystem)
Error: no such file. (``)
+1 -4
View File
@@ -1,4 +1 @@
-- json.lua by rxi
-- Minified with luamin
-- Original: https://github.com/rxi/json.lua
local a={_version="0.1.2"}local b;local c={["\\"]="\\",["\""]="\"",["\b"]="b",["\f"]="f",["\n"]="n",["\r"]="r",["\t"]="t"}local d={["/"]="/"}for e,f in pairs(c)do d[f]=e end;local function g(h)return"\\"..(c[h]or string.format("u%04x",h:byte()))end;local function i(j)return"null"end;local function k(j,l)local m={}l=l or{}if l[j]then error("circular reference")end;l[j]=true;if rawget(j,1)~=nil or next(j)==nil then local n=0;for e in pairs(j)do if type(e)~="number"then error("invalid table: mixed or invalid key types")end;n=n+1 end;if n~=#j then error("invalid table: sparse array")end;for o,f in ipairs(j)do table.insert(m,b(f,l))end;l[j]=nil;return"["..table.concat(m,",").."]"else for e,f in pairs(j)do if type(e)~="string"then error("invalid table: mixed or invalid key types")end;table.insert(m,b(e,l)..":"..b(f,l))end;l[j]=nil;return"{"..table.concat(m,",").."}"end end;local function p(j)return'"'..j:gsub('[%z\1-\31\\"]',g)..'"'end;local function q(j)if j~=j or j<=-math.huge or j>=math.huge then error("unexpected number value '"..tostring(j).."'")end;return string.format("%.14g",j)end;local r={["nil"]=i,["table"]=k,["string"]=p,["number"]=q,["boolean"]=tostring}b=function(j,l)local s=type(j)local t=r[s]if t then return t(j,l)end;error("unexpected type '"..s.."'")end;function a.encode(j)return b(j)end;local u;local function v(...)local m={}for o=1,select("#",...)do m[select(o,...)]=true end;return m end;local w=v(" ","\t","\r","\n")local x=v(" ","\t","\r","\n","]","}",",")local y=v("\\","/",'"',"b","f","n","r","t","u")local z=v("true","false","null")local A={["true"]=true,["false"]=false,["null"]=nil}local function B(C,D,E,F)for o=D,#C do if E[C:sub(o,o)]~=F then return o end end;return#C+1 end;local function G(C,D,H)local I=1;local J=1;for o=1,D-1 do J=J+1;if C:sub(o,o)=="\n"then I=I+1;J=1 end end;error(string.format("%s at line %d col %d",H,I,J))end;local function K(n)local t=math.floor;if n<=0x7f then return string.char(n)elseif n<=0x7ff then return string.char(t(n/64)+192,n%64+128)elseif n<=0xffff then return string.char(t(n/4096)+224,t(n%4096/64)+128,n%64+128)elseif n<=0x10ffff then return string.char(t(n/262144)+240,t(n%262144/4096)+128,t(n%4096/64)+128,n%64+128)end;error(string.format("invalid unicode codepoint '%x'",n))end;local function L(M)local N=tonumber(M:sub(1,4),16)local O=tonumber(M:sub(7,10),16)if O then return K((N-0xd800)*0x400+O-0xdc00+0x10000)else return K(N)end end;local function P(C,o)local m=""local Q=o+1;local e=Q;while Q<=#C do local R=C:byte(Q)if R<32 then G(C,Q,"control character in string")elseif R==92 then m=m..C:sub(e,Q-1)Q=Q+1;local h=C:sub(Q,Q)if h=="u"then local S=C:match("^[dD][89aAbB]%x%x\\u%x%x%x%x",Q+1)or C:match("^%x%x%x%x",Q+1)or G(C,Q-1,"invalid unicode escape in string")m=m..L(S)Q=Q+#S else if not y[h]then G(C,Q-1,"invalid escape char '"..h.."' in string")end;m=m..d[h]end;e=Q+1 elseif R==34 then m=m..C:sub(e,Q-1)return m,Q+1 end;Q=Q+1 end;G(C,o,"expected closing quote for string")end;local function T(C,o)local R=B(C,o,x)local M=C:sub(o,R-1)local n=tonumber(M)if not n then G(C,o,"invalid number '"..M.."'")end;return n,R end;local function U(C,o)local R=B(C,o,x)local V=C:sub(o,R-1)if not z[V]then G(C,o,"invalid literal '"..V.."'")end;return A[V],R end;local function W(C,o)local m={}local n=1;o=o+1;while 1 do local R;o=B(C,o,w,true)if C:sub(o,o)=="]"then o=o+1;break end;R,o=u(C,o)m[n]=R;n=n+1;o=B(C,o,w,true)local X=C:sub(o,o)o=o+1;if X=="]"then break end;if X~=","then G(C,o,"expected ']' or ','")end end;return m,o end;local function Y(C,o)local m={}o=o+1;while 1 do local Z,j;o=B(C,o,w,true)if C:sub(o,o)=="}"then o=o+1;break end;if C:sub(o,o)~='"'then G(C,o,"expected string for key")end;Z,o=u(C,o)o=B(C,o,w,true)if C:sub(o,o)~=":"then G(C,o,"expected ':' after key")end;o=B(C,o+1,w,true)j,o=u(C,o)m[Z]=j;o=B(C,o,w,true)local X=C:sub(o,o)o=o+1;if X=="}"then break end;if X~=","then G(C,o,"expected '}' or ','")end end;return m,o end;local _={['"']=P,["0"]=T,["1"]=T,["2"]=T,["3"]=T,["4"]=T,["5"]=T,["6"]=T,["7"]=T,["8"]=T,["9"]=T,["-"]=T,["t"]=U,["f"]=U,["n"]=U,["["]=W,["{"]=Y}u=function(C,D)local X=C:sub(D,D)local t=_[X]if t then return t(C,D)end;G(C,D,"unexpected character '"..X.."'")end;function a.decode(C)if type(C)~="string"then error("expected argument of type string, got "..type(C))end;local m,D=u(C,B(C,1,w,true))D=B(C,D,w,true)if D<=#C then G(C,D,"trailing garbage")end;return m end;return a
Error: no such file. (``)
+1 -27
View File
File diff suppressed because one or more lines are too long
+1 -432
View File
@@ -1,432 +1 @@
local raster = {
["units"]={},
["defaultBackgroundColor"]=0x000000,
["defaultForegroundColor"]=0xFFFFFF,
["displayWidth"]=0,
["displayHeight"]=0,
["charWidth"]=0,
["charHeight"]=0,
["backgroundColor"]=0xFFFFFF
}
local component = import("component")
-- local ocelot = component.proxy(component.list("ocelot")())
local gpu = component.gpu
local display = {}
local chunksAffected = {}
local renderBuffer = nil
-- braille rendering
function raster.units.charToBraille(x,y)
return x*2,y*4
end
function raster.units.brailleToChar(x,y)
return math.ceil(x/2),math.ceil(y/4)
end
function raster.init(width, height, bgcolor)
-- NOTE: Width and height are in characters, not pixels in braille.
-- If the width and height are nil, the entire screen will be used.
if width==nil and height==nil then
width, height = gpu.getResolution()
end
raster.charWidth = width
raster.charHeight = height
width, height = raster.units.charToBraille(width, height)
bgcolor = bgcolor or raster.defaultBackgroundColor
if bgcolor~=0 then
for i=1,width*height do
display[i]=bgcolor
end
end
raster.displayWidth = width
raster.displayHeight = height
raster.backgroundColor = bgcolor
pcall(function()
renderBuffer = gpu.allocateBuffer()
end)
raster.clear()
end
function raster.set(x, y, color)
if x<1 or x>raster.displayWidth or y<1 or y>raster.displayHeight then
return false
end
color = color or raster.defaultForegroundColor
local i = x+y*raster.displayWidth
display[i] = color
local ci = math.floor((x-1)/2)+math.floor((y-1)/4)*raster.charWidth+1
-- ocelot.log(x..","..y..":"..ci)
chunksAffected[ci] = true
return true
end
function raster.get(x, y)
local i = x+y*raster.displayWidth
return display[i] or raster.backgroundColor
end
local function stats(arr)
local out = {}
for i=1,#arr do
local v = arr[i]
if out[v]==nil then
out[v]=1
else
out[v] = out[v] + 1
end
end
return out
end
local function getKeys(t)
local keys = {}
for k,v in pairs(t) do
table.insert(keys,{k,v})
end
table.sort(keys,function(a,b)
return a[2]>b[2]
end)
for i=1,#keys do
keys[i] = keys[i][1]
end
return keys
end
local function colorDifference(a,b)
return ((a>>16)&255)-((b>>16)&255)+((a>>8)&255)-((b>>8)&255)+(a&255)-(b&255)
end
local function limitTwoColors(arr)
local colors = getKeys(stats(arr))
for i=1,#arr do
local v=arr[i]
if v==colors[1] then
arr[i]=0
goto continue
elseif v==colors[2] then
arr[i]=1
goto continue
else
--error("Pixel is not in the two colors (raster.lua:90)")
-- get closest color so atleast it kinda shows
if colorDifference(v,colors[1])<colorDifference(v,colors[2]) then
arr[i]=0
else
arr[i]=1
end
end
::continue::
end
return arr,colors[1] or 0,colors[2] or 0
end
local function arrayToBraille(arr)
local codePoint = 0x2800
for i=1,8 do
codePoint = codePoint | arr[i]<<(i-1)
end
if codePoint==0x2800 then return " " end
return utf8.char(codePoint)
end
function raster.update()
if renderBuffer~=nil then
gpu.setActiveBuffer(renderBuffer)
end
for y=1,raster.displayHeight,4 do
-- gpu.set(0,0,tostring(y))
for x=1,raster.displayWidth,2 do
local ci = math.floor(x/2)+math.floor(y/4)*raster.charWidth+1
if chunksAffected[ci] then
local chunk = {
raster.get(x,y),
raster.get(x,y+1),
raster.get(x,y+2),
raster.get(x+1,y),
raster.get(x+1,y+1),
raster.get(x+1,y+2),
raster.get(x,y+3),
raster.get(x+1,y+3)
}
local colorA = nil
local colorB = nil
chunk,colorA,colorB = limitTwoColors(chunk)
-- print(tostring(colorA)..","..tostring(colorB))
cx,cy=raster.units.brailleToChar(x,y)
gpu.setBackground(colorA)
gpu.setForeground(colorB)
-- gpu.set(cx,cy,tostring(colorB/0xFFFFFF))
gpu.set(cx,cy,arrayToBraille(chunk))
chunksAffected[ci] = false
end
end
end
if renderBuffer~=nil then
gpu.bitblt()
gpu.setActiveBuffer(0)
end
end
function raster.clear()
if renderBuffer~=nil then
gpu.setActiveBuffer(renderBuffer)
end
-- clear()
local bgcolor = raster.backgroundColor
gpu.setBackground(bgcolor)
gpu.fill(1,1,raster.displayWidth,raster.displayHeight," ")
display = {}
end
function raster.free()
if renderBuffer==nil then
return true
else
return gpu.freeBuffer(renderBuffer)
end
end
-- advanced rendering
function raster.drawLine(x1, y1, x2, y2, color)
x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
local dx = math.abs(x2 - x1)
local dy = math.abs(y2 - y1)
local sx = x1 < x2 and 1 or -1
local sy = y1 < y2 and 1 or -1
local err = dx - dy
while true do
raster.set(x1, y1, color)
if x1 == x2 and y1 == y2 then
break
end
local e2 = 2 * err
if e2 > -dy then
err = err - dy
x1 = x1 + sx
end
if e2 < dx then
err = err + dx
y1 = y1 + sy
end
end
end
function raster.drawRect(x1,y1,x2,y2,col)
x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
if x1 > x2 then x1, x2 = x2, x1 end
if y1 > y2 then y1, y2 = y2, y1 end
for x=x1,x2 do
raster.set(x,y1,col)
raster.set(x,y2,col)
end
for y=y1+1,y2-1 do
raster.set(x1,y,col)
raster.set(x2,y,col)
end
end
function raster.fillRect(x1,y1,x2,y2,col)
x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
if x1 > x2 then x1, x2 = x2, x1 end
if y1 > y2 then y1, y2 = y2, y1 end
for x=x1,x2 do
for y=y1,y2 do
raster.set(x,y,col)
end
end
end
function raster.drawCircle(xc, yc, radius, color)
xc=math.floor(xc)
yc=math.floor(yc)
radius=math.floor(radius)
local x = 0
local y = radius
local d = 3 - 2 * radius
while y >= x do
-- Draw 8 symmetric points
raster.set(xc + x, yc + y, color)
raster.set(xc - x, yc + y, color)
raster.set(xc + x, yc - y, color)
raster.set(xc - x, yc - y, color)
raster.set(xc + y, yc + x, color)
raster.set(xc - y, yc + x, color)
raster.set(xc + y, yc - x, color)
raster.set(xc - y, yc - x, color)
if d < 0 then
d = d + 4 * x + 6
else
d = d + 4 * (x - y) + 10
y = y - 1
end
x = x + 1
end
end
function raster.drawEllipse(x1, y1, x2, y2, color)
if x1 > x2 then x1, x2 = x2, x1 end
if y1 > y2 then y1, y2 = y2, y1 end
local xc = math.floor((x1 + x2) / 2)
local yc = math.floor((y1 + y2) / 2)
local a = math.floor((x2 - x1) / 2)
local b = math.floor((y2 - y1) / 2)
if a <= 0 or b <= 0 then
return
end
if a == b then
raster.drawCircle(xc, yc, a, color)
return
end
if a <= 1 and b <= 1 then
raster.set(xc, yc, color)
return
elseif a <= 1 then
for y = yc - b, yc + b do
raster.set(xc, y, color)
end
return
elseif b <= 1 then
for x = xc - a, xc + a do
raster.set(x, yc, color)
end
return
end
local x = 0
local y = b
local a2 = a * a
local b2 = b * b
local d1 = b2 - (a2 * b) + (0.25 * a2)
local dx = 2 * b2 * x
local dy = 2 * a2 * y
while dx < dy do
raster.set(xc + x, yc + y, color)
raster.set(xc - x, yc + y, color)
raster.set(xc + x, yc - y, color)
if d1 < 0 then
x = x + 1
dx = dx + (2 * b2)
d1 = d1 + dx + b2
else
x = x + 1
y = y - 1
dx = dx + (2 * b2)
dy = dy - (2 * a2)
d1 = d1 + dx - dy + b2
end
end
local d2 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2
while y >= 0 do
raster.set(xc + x, yc + y, color)
raster.set(xc - x, yc + y, color)
raster.set(xc + x, yc - y, color)
raster.set(xc - x, yc - y, color)
if d2 > 0 then
y = y - 1
dy = dy - (2 * a2)
d2 = d2 - dy + a2
else
y = y - 1
x = x + 1
dx = dx + (2 * b2)
dy = dy - (2 * a2)
d2 = d2 + dx - dy + a2
end
end
end
function raster.fillCircle(x, y, r, color)
x, y = math.floor(x + 0.5), math.floor(y + 0.5)
r = math.floor(r + 0.5)
if r <= 0 then return end
local minX, maxX = x - r, x + r
local minY, maxY = y - r, y + r
for py = minY, maxY do
for px = minX, maxX do
local dx, dy = px - x, py - y
local distSquared = dx*dx + dy*dy
if distSquared <= r*r then
raster.set(px, py, color)
end
end
end
end
function raster.fillEllipse(x1, y1, x2, y2, color)
local centerX = (x1 + x2) / 2
local centerY = (y1 + y2) / 2
local a = math.abs(x2 - x1) / 2
local b = math.abs(y2 - y1) / 2
centerX = math.floor(centerX + 0.5)
centerY = math.floor(centerY + 0.5)
a = math.floor(a + 0.5)
b = math.floor(b + 0.5)
if a <= 0 or b <= 0 then return end
if a == b then
raster.fillCircle(centerX, centerY, a, color)
return
end
local minX = centerX - a
local maxX = centerX + a
local minY = centerY - b
local maxY = centerY + b
for y = minY, maxY do
for x = minX, maxX do
local dx = x - centerX
local dy = y - centerY
local value = (dx*dx)/(a*a) + (dy*dy)/(b*b)
if value <= 1 then
raster.set(x, y, color)
end
end
end
end
return raster
Error: no such file. (``)
+1 -125
View File
@@ -1,125 +1 @@
local serialize = {}
function serialize.string(str)
return '"'..str:gsub("[%z\1-\31\34\92\127-\159]",function(c)
local byte = c:byte()
if byte== 7 then return "\\a" end
if byte== 8 then return "\\b" end
if byte== 9 then return "\\t" end
if byte==10 then return "\\n" end
if byte==11 then return "\\v" end
if byte==12 then return "\\f" end
if byte==13 then return "\\r" end
if byte==34 then return "\\\"" end
if byte==92 then return "\\\\" end
return string.format("\\x%02x",byte)
end)..'"'
end
function serialize.table(tbl,colors,stack)
stack = table.copy(stack or {})
table.insert(stack,tbl)
local keyAmount = 0
local keyNumber = true
local out = ""
local first = true
for key,val in pairs(tbl) do
if not first then out=out..",\n" end
first=false
out=out.." "
if type(key)=="string" then
if key:match("^[%a_][%w_]*$") then
out=out..key.."="
else
out=out..'['..serialize.string(key)..']='
end
else
out=out.."["..tostring(key).."]="
end
if type(key)~="number" then
keyNumber=false
end
local success,reason = pcall(function()
local valStr = ""
if type(val)=="table" then
if #stack>4 or table.find(stack,val) then
valStr="..."
else
valStr=serialize.table(val,colors,stack)
end
elseif type(val)=="string" then
local lines = {}
for line in (val.."\n"):gmatch("([^\n]*)\n") do table.insert(lines,line) end
if #lines[#lines]==0 then
lines[#lines]=nil
lines[#lines]=lines[#lines].."\n"
end
for i=1,#lines do
if i<#lines then
lines[i]=serialize.string(lines[i].."\n")
else
lines[i]=serialize.string(lines[i])
end
end
valStr=table.concat(lines," ..\n ")
else
valStr=tostring(val)
end
local lines = {}
for line in (valStr.."\n"):gmatch("([^\n]*)\n") do table.insert(lines,line) end
out=out..table.concat(lines,"\n ")
lines = nil
keyAmount=keyAmount+1
end)
if not success then
if colors then out=out.."\x1b[91m" end
out=out.."["..tostring(reason).."]"
if colors then out=out.."\x1b[39m" end
end
coroutine.yield()
end
local metatbl = getmetatable(tbl)
local metakeys = {}
if type(metatbl)=="table" then
for i,v in pairs(metatbl) do
keyNumber=false
table.insert(metakeys,i)
end
end
if #metakeys>0 then
out=out.."\n "
if colors then out=out.."\x1b[92m" end
if table.find(metakeys,"__tostring") then
out=out.."tostring: "..serialize.string(tostring(tbl)).."\n "
table.remove(metakeys,table.find(metakeys,"__tostring"))
end
out=out..table.concat(metakeys,", ")
if colors then out=out.."\x1b[39m" end
end
if keyAmount==0 then return "{}" end
if keyNumber then
-- fix strings not being serialised
local vals = {}
for _,v in pairs(tbl) do
if #vals>=5 and #stack>1 then
table.insert(vals,"...")
break
end
if type(v)=="table" then
table.insert(vals,serialize.table(v,colors,stack))
elseif type(v)=="string" then
table.insert(vals,serialize.string(v))
else
table.insert(vals,tostring(v))
end
end
return "{"..table.concat(vals,", ").."}"
end
return "{\n"..out.."\n}"
end
return serialize
Error: no such file. (``)
+1 -102
View File
@@ -1,102 +1 @@
local unicodeLib
local LLunicode
if table.copy then
unicodeLib = table.copy(unicode)
LLunicode = table.copy(unicode)
else
unicodeLib = {}
LLunicode = unicode
end
function unicodeLib.readCodePoint(readByte)
checkArg(1,readByte,"function")
local function inRange(min,max,...)
for _,v in ipairs({...}) do
if not (v and v>=min and v<max) then return false end
end
return true
end
local byte = readByte()
if byte==nil then return end
if byte < 0x80 then
-- ASCII character (0xxxxxxx)
return byte
elseif byte < 0xC0 then
-- Continuation byte (10xxxxxx), invalid at start position
return nil
elseif byte < 0xE0 then
-- 2-byte sequence (110xxxxx 10xxxxxx)
local byte2 = readByte()
if byte2==nil then return nil end
if inRange(0x80,0xC0,byte2) then
local code_point = ((byte & 0x1F) << 6) | (byte2 & 0x3F)
return code_point
end
elseif byte < 0xF0 then
-- 3-byte sequence (1110xxxx 10xxxxxx 10xxxxxx)
local byte2, byte3 = readByte(), readByte()
if byte2==nil and byte3==nil then return nil end
if inRange(0x80,0xC0,byte2,byte3)then
local code_point = ((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F)
return code_point
end
elseif byte < 0xF8 then
-- 4-byte sequence (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
local byte2, byte3, byte4 = readByte(), readByte(), readByte()
if byte2==nil and byte3==nil and byte4==nil then return nil end
if inRange(0x80,0xC0,byte2,byte3,byte4) then
local code_point = ((byte & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F)
return code_point
end
end
-- Invalid UTF-8 byte sequence
return nil
end
function unicodeLib.readChar(readByte)
checkArg(1,readByte,"function")
return LLunicode.char(unicodeLib.readCodePoint(readByte))
end
function unicodeLib.codepoint(chr)
checkArg(1,chr,"string")
local ptr = 1
return unicode.readCodePoint(function()
local byte = chr:byte(ptr)
ptr=ptr+1
return byte
end),ptr-1
end
function unicodeLib.iterate(readByte)
checkArg(1,readByte,"string","function")
if type(readByte)=="string" then
local str,ptr = readByte,0
readByte = function()
ptr=ptr+1
return str:byte(ptr)
end
end
return function()
local point = unicodeLib.readCodePoint(readByte)
if point==nil then return nil end
return LLunicode.char(point),point
end
end
unicodeLib.char = LLunicode.char
unicodeLib.charWidth = LLunicode.charWidth
unicodeLib.isWide = LLunicode.isWide
unicodeLib.len = LLunicode.len
unicodeLib.lower = LLunicode.lower
unicodeLib.reverse = LLunicode.reverse
unicodeLib.sub = LLunicode.sub
unicodeLib.upper = LLunicode.upper
unicodeLib.wlen = LLunicode.wlen
unicodeLib.wtrunc = LLunicode.wtrunc
return unicodeLib
Error: no such file. (``)