I forgot you have to give it write permissions (minified)
This commit is contained in:
+1
-691
@@ -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
@@ -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
@@ -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
@@ -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 +1 @@
|
||||
clear()
|
||||
-- truly so much going on here
|
||||
Error: no such file. (``)
|
||||
|
||||
+1
-26
@@ -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 +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 +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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 +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
@@ -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
@@ -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 +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
@@ -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
@@ -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 @@
|
||||
import("computer").shutdown(true)
|
||||
Error: no such file. (``)
|
||||
|
||||
+1
-15
@@ -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
@@ -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
@@ -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 @@
|
||||
import("computer").shutdown()
|
||||
Error: no such file. (``)
|
||||
|
||||
Reference in New Issue
Block a user