Compare commits
149 Commits
main
...
0ae00dd61a
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ae00dd61a | |||
| 593e8a8512 | |||
| 93c632ed6e | |||
| ab48b57e1b | |||
| 45a09284c2 | |||
| 8fc249433b | |||
| 69a033f9a2 | |||
| 11dea2b9e8 | |||
| 393802b34e | |||
| a3e0ec64ae | |||
| 9b9c005194 | |||
| 81e832ef5d | |||
| 6c356c7a13 | |||
| 14b25d59fc | |||
| afe27f2b41 | |||
| 317c0df9e8 | |||
| b139e2da01 | |||
| af61b8661a | |||
| cb0f663f94 | |||
| 364dda8850 | |||
| d091dcad18 | |||
| 7453215c91 | |||
| 95befaa72b | |||
| 399dd37b2d | |||
| 0c197d758a | |||
| ac1e58abcf | |||
| 08af85f3b4 | |||
| 4d6dbadc32 | |||
| b756bc516e | |||
| 16214c253d | |||
| 35e3a2313f | |||
| f81e9089d3 | |||
| 8c33ee0eb9 | |||
| 202f6d42ac | |||
| 2b897106c5 | |||
| cd5b71c110 | |||
| e3464a920e | |||
| 137f8645fd | |||
| 44f391253c | |||
| 477d1de809 | |||
| bf541b8b9d | |||
| 2bff0e749a | |||
| 60283fc40e | |||
| f275247b00 | |||
| d84324c707 | |||
| 8dda210eb3 | |||
| 95b1c56d65 | |||
| 56a849c1a8 | |||
| 233ad0598d | |||
| 442e83c8e9 | |||
| 5ea263e0bc | |||
| e001c1b17e | |||
| 4bc3a64a8c | |||
| 82fc244209 | |||
| 7bb4923bf0 | |||
| 568b4d0b2c | |||
| 26a61c6e6c | |||
| b6cdae3408 | |||
| e8b6714b9a | |||
| 6f377c2bd5 | |||
| 4e837fc928 | |||
| 6688bbcaaf | |||
| eb2e6b9596 | |||
| 2173713694 | |||
| c5b330ac9d | |||
| 2d6dbe41a1 | |||
| 65facb89f7 | |||
| 647854b1da | |||
| a7809384d9 | |||
| 88f2a55ca0 | |||
| 3ab72fe1dd | |||
| 1e9ba6c01a | |||
| bca8830ead | |||
| 5feed553af | |||
| d24e00c308 | |||
| f5fcc84903 | |||
| 86f825d14b | |||
| 3c99c26ea3 | |||
| fa1ef3926b | |||
| bef22740f6 | |||
| 3e3e35860c | |||
| ad7596efee | |||
| c4b6445c23 | |||
| ead5a09747 | |||
| be2ddf1dd4 | |||
| ca5d1114d2 | |||
| c5418be165 | |||
| f0c0acfcdc | |||
| ae1652b1b9 | |||
| c1c6a50b09 | |||
| 51124da54b | |||
| 8144d44deb | |||
| 337f8af1df | |||
| 30b38ee0d9 | |||
| 8548855d7f | |||
| f1d69b51b2 | |||
| c9883c2c64 | |||
| 668ed93491 | |||
| 8ab525b9ac | |||
| 245b6a524d | |||
| 883f20f269 | |||
| 61eea92fe0 | |||
| 26c1f055d8 | |||
| d771a1fe39 | |||
| a020229a69 | |||
| e1270d7bd7 | |||
| f1877f6338 | |||
| 61a7e3d139 | |||
| 8296127266 | |||
| 62a2466c5e | |||
| 1798d63864 | |||
| 33f2573eb6 | |||
| ea074a8f87 | |||
| 4a9683a256 | |||
| 296aba9a2f | |||
| 1d49683d3c | |||
| e0b6feb98c | |||
| d63941814f | |||
| db01a8d741 | |||
| a89953056b | |||
| 2c47a6df59 | |||
| 943f1020fa | |||
| 3d9ec665b9 | |||
| 9c0e33c116 | |||
| cd3dd80c23 | |||
| 58c8ce3f2d | |||
| de5d779d9a | |||
| 0ca8cfeeeb | |||
| 0c604a5870 | |||
| c83fe8a7f4 | |||
| f28812205e | |||
| 2f512b5e99 | |||
| 732f747347 | |||
| 99725b43ba | |||
| ad0f2197a3 | |||
| cf26f610b4 | |||
| 39897457f9 | |||
| 87d0e6bbcb | |||
| 8b51217324 | |||
| 894641734f | |||
| 90252f83f1 | |||
| 0b2745ab9c | |||
| 099fbee8c6 | |||
| 66783e455c | |||
| ff04e730f9 | |||
| 3c087aaddf | |||
| 8244f1590c | |||
| d3d5f21ab1 | |||
| ef0ffa1886 |
@@ -0,0 +1,3 @@
|
|||||||
|
[*.lua]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.stfolder
|
||||||
|
.idea
|
||||||
|
home/*
|
||||||
|
halyde/logs/*
|
||||||
|
*.kate-swp
|
||||||
+2
-1
@@ -14,7 +14,8 @@
|
|||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"disable": [
|
"disable": [
|
||||||
"undefined-global",
|
"undefined-global",
|
||||||
"lowercase-global"
|
"lowercase-global",
|
||||||
|
"missing-fields"
|
||||||
],
|
],
|
||||||
"globals": [
|
"globals": [
|
||||||
"_G",
|
"_G",
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# Halyde
|
# Halyde
|
||||||
|
### If you are viewing on GitHub: Halyde has moved to [Gitea](https://git.sting.lt/Cerulean-Blue/Halyde). This repository is now a read-only mirror. Contributions, issues and pull requests will not be processed here. Please go to [the Gitea instance](https://git.sting.lt/Cerulean-Blue/Halyde) for that.
|
||||||
|
|
||||||
A universal, customizable and feature-packed operating system for OpenComputers.
|
A universal, customizable and feature-packed operating system for OpenComputers.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -6,8 +8,8 @@ A universal, customizable and feature-packed operating system for OpenComputers.
|
|||||||
<img src="https://img.shields.io/badge/Written_in-Lua-blue?style=plastic&logo=lua" /></a>
|
<img src="https://img.shields.io/badge/Written_in-Lua-blue?style=plastic&logo=lua" /></a>
|
||||||
<a href="https://ocdoc.cil.li/">
|
<a href="https://ocdoc.cil.li/">
|
||||||
<img src="https://img.shields.io/badge/Made_for-OpenComputers-yellow?style=plastic" /></a>
|
<img src="https://img.shields.io/badge/Made_for-OpenComputers-yellow?style=plastic" /></a>
|
||||||
<a href="https://cerulean-blue.gitbook.io/halyde-docs">
|
<a href="https://wiki.sting.lt/">
|
||||||
<img src="https://img.shields.io/badge/Documented_on-GitBook-green?style=plastic&logo=gitbook" /></a>
|
<img src="https://img.shields.io/badge/Documented_on-DokuWiki-green?style=plastic" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@@ -20,4 +22,4 @@ If for some reason that doesn't work, try:
|
|||||||
`wget -f https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/webinstall.lua /tmp/webinstall.lua && /tmp/webinstall.lua`
|
`wget -f https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/webinstall.lua /tmp/webinstall.lua && /tmp/webinstall.lua`
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
Halyde is [documented on GitBook](https://cerulean-blue.gitbook.io/halyde-docs).
|
Halyde is [documented on DokuWiki](https://wiki.sting.lt/), however there is an alternative documentation on [GitBook](https://cerulean-blue.gitbook.io/halyde-docs/).
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"halyde": "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/Pre-Alpha-3.0.0/",
|
||||||
|
"argentum": "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/Pre-Alpha-3.0.0/",
|
||||||
|
"edit": "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/Pre-Alpha-3.0.0/",
|
||||||
|
"package1": "https://raw.githubusercontent.com/WahPlus/ArgentumPackages/refs/heads/main/",
|
||||||
|
"package2": "https://raw.githubusercontent.com/WahPlus/ArgentumPackages/refs/heads/main/",
|
||||||
|
"vpkg": "https://raw.githubusercontent.com/WahPlus/ArgentumPackages/refs/heads/main/",
|
||||||
|
"grouper": "https://raw.githubusercontent.com/WahPlus/ArgentumPackages/refs/heads/main/"
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
local agregistry = {
|
local agregistry = {
|
||||||
["halyde"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/",
|
["halyde"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/",
|
||||||
["edit"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/",
|
["edit"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/",
|
||||||
@@ -8,7 +9,10 @@ local agregistry = {
|
|||||||
["hextra"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
["hextra"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
||||||
["utape"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
["utape"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
||||||
["libctif"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
["libctif"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
||||||
["ctif-viewer"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/"
|
["ctif-viewer"] = "https://raw.githubusercontent.com/Ponali/ArgentumPackages/refs/heads/master/",
|
||||||
|
["libsha256"] = "https://raw.githubusercontent.com/tema5002/ag-packages/refs/heads/main/",
|
||||||
|
["sha256sum"] = "https://raw.githubusercontent.com/tema5002/ag-packages/refs/heads/main/",
|
||||||
|
["base64"] = "https://raw.githubusercontent.com/mcplayer3/AgPackages/refs/heads/main/"
|
||||||
}
|
}
|
||||||
|
|
||||||
return agregistry
|
return agregistry
|
||||||
|
|||||||
@@ -0,0 +1,520 @@
|
|||||||
|
local cliparse = require("cliparse")
|
||||||
|
local fs = require("filesystem")
|
||||||
|
local component = require("component")
|
||||||
|
local json = require("json")
|
||||||
|
|
||||||
|
local function getFile(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
if path:sub(1, 7) == "http://" or path:sub(1, 8) == "https://" then
|
||||||
|
if not component.list("internet")() then
|
||||||
|
return false, "Internet card required but not found."
|
||||||
|
end
|
||||||
|
local handle, data, tmpdata = component.internet.request(path), "", nil
|
||||||
|
local success, errorMessage = pcall(function()
|
||||||
|
handle:finishConnect()
|
||||||
|
end)
|
||||||
|
if not success then
|
||||||
|
return false, errorMessage
|
||||||
|
end
|
||||||
|
local code, message = handle:response()
|
||||||
|
if code and code ~= 200 then
|
||||||
|
return false, ("%d %s"):format(code, message)
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
tmpdata = handle.read(math.huge or math.maxinteger)
|
||||||
|
data = data .. (tmpdata or "")
|
||||||
|
until not tmpdata
|
||||||
|
return true, data
|
||||||
|
elseif path:sub(1, 1) == "/" then
|
||||||
|
if not fs.exists(path) then
|
||||||
|
return false, "No such file or directory: " .. path
|
||||||
|
end
|
||||||
|
if fs.isDirectory(path) then
|
||||||
|
return false, "Expected file, found directory: " .. path
|
||||||
|
end
|
||||||
|
local handle, data, tmpdata = fs.open(path, "r", false), "", nil
|
||||||
|
if not handle then
|
||||||
|
return false, data
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
tmpdata = handle:read(math.huge or math.maxinteger)
|
||||||
|
data = data .. (tmpdata or "")
|
||||||
|
until not tmpdata
|
||||||
|
return true, data
|
||||||
|
else
|
||||||
|
return false, "Unsupported path: " .. path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cliparse.config({
|
||||||
|
["x"] = 0,
|
||||||
|
["exclude-deps"] = 0,
|
||||||
|
["u"] = 0,
|
||||||
|
["update-registry"] = 0,
|
||||||
|
["f"] = 0,
|
||||||
|
["force"] = 0,
|
||||||
|
["c"] = 0,
|
||||||
|
["clean"] = 0,
|
||||||
|
["s"] = 1,
|
||||||
|
["source"] = 1,
|
||||||
|
["C"] = 0,
|
||||||
|
["cascade"] = 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
local parsed, errorMessage = cliparse.parse(...)
|
||||||
|
|
||||||
|
if not parsed then
|
||||||
|
print(("\27[91m%s\n\27[0mExiting."):format(errorMessage))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local command = parsed.args[1]
|
||||||
|
|
||||||
|
if not command then
|
||||||
|
print("\27[91mNo command specified.\n\27[0mExiting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if
|
||||||
|
not (
|
||||||
|
command == "install"
|
||||||
|
or command == "remove"
|
||||||
|
or command == "update"
|
||||||
|
or command == "list"
|
||||||
|
or command == "repo-list"
|
||||||
|
or command == "repo-add"
|
||||||
|
or command == "repo-remove"
|
||||||
|
or command == "info"
|
||||||
|
)
|
||||||
|
then
|
||||||
|
print(("\27[91mInvalid command: %s\n\27[0mExiting."):format(command))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local packages = parsed.args
|
||||||
|
table.remove(packages, 1)
|
||||||
|
-- Remove the command from the actual package list
|
||||||
|
-- local result, data, failure
|
||||||
|
do
|
||||||
|
local function check(condition, message)
|
||||||
|
if not condition then
|
||||||
|
print(message)
|
||||||
|
failure = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if parsed.flags.u or parsed.flags["update-registry"] then
|
||||||
|
terminal.write("Updating registry...")
|
||||||
|
result, data = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/Pre-Alpha-3.0.0/ag2/registry.json")
|
||||||
|
check(result, "\27[91mFailed to get registry: " .. data .. "\27[0m")
|
||||||
|
local handle, errorMessage = fs.open("/ag2/registry.json", "w")
|
||||||
|
check(handle, "\27[91mFailed to open write handle to registry: " .. errorMessage .. "\27[0m")
|
||||||
|
local success, errorMessage = handle:write(data)
|
||||||
|
check(success, "\27[91mFailed to write to registry: " .. errorMessage .. "\27[0m")
|
||||||
|
handle:close()
|
||||||
|
else
|
||||||
|
result, data = getFile("/ag2/registry.json")
|
||||||
|
check(result, "\27[91mFailed to get registry: " .. data .. "\27[0m")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local success, registry = pcall(function()
|
||||||
|
return json.decode(data)
|
||||||
|
end)
|
||||||
|
if not success then
|
||||||
|
print(("\27[91mFailed to parse registry: %s\n\27[0mExiting."):format(registry))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getServersidePackageConfig(source, package)
|
||||||
|
local success, data = getFile(fs.concat(source, "/ag2.json"))
|
||||||
|
if not success then
|
||||||
|
return false, ("\27[91mFailed to get package config (ag2.json) of package '%s': " .. data .. "\27[0m"):format(package)
|
||||||
|
end
|
||||||
|
local success, packageConfig = pcall(function()
|
||||||
|
return json.decode(data)
|
||||||
|
end)
|
||||||
|
if not success then
|
||||||
|
return false, ("\27[91mFailed to parse package config (ag2.json) of package '%s': " .. packageConfig .. "\27[0m"):format(package)
|
||||||
|
end
|
||||||
|
if not packageConfig[package] then
|
||||||
|
return false, ("\27[91mRepository package config (ag2.json) does not contain package '%s'.\27[0m"):format(package)
|
||||||
|
end
|
||||||
|
return packageConfig[package]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if everything is valid
|
||||||
|
failure = false
|
||||||
|
local dependencyCounter = 0
|
||||||
|
local previousI = 1 -- See 190
|
||||||
|
::RESETLOOP::
|
||||||
|
if command == "install" then
|
||||||
|
for i = previousI, #packages do
|
||||||
|
if not packages[i] then
|
||||||
|
-- When packages are removed, the last packages can end up reading as nil
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
local otherPackages = table.copy(packages)
|
||||||
|
table.remove(otherPackages, i)
|
||||||
|
-- This is to check if the package can be found in the others, or in other words, checking for duplicates
|
||||||
|
if table.find(otherPackages, packages[i]) then
|
||||||
|
print(("\27[93mDuplicate package specified (%s), skipping\27[0m"):format(packages[i]))
|
||||||
|
table.remove(packages, i)
|
||||||
|
i = i - 1
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
local source
|
||||||
|
if parsed.s or parsed.source then
|
||||||
|
source = parsed.s or parsed.source
|
||||||
|
else
|
||||||
|
source = registry[packages[i]]
|
||||||
|
end
|
||||||
|
if not source then
|
||||||
|
print("\27[91mCould not find package in registry and no source provided: " .. packages[i] .. "\27[0m")
|
||||||
|
failure = true
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
local packageConfig, errorMessage = getServersidePackageConfig(source, packages[i])
|
||||||
|
if not packageConfig then
|
||||||
|
failure = true
|
||||||
|
print(errorMessage)
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
if packageConfig.type == "group" then
|
||||||
|
table.remove(packages, i)
|
||||||
|
for _, package in ipairs(packageConfig.packages) do
|
||||||
|
table.insert(packages, package)
|
||||||
|
end
|
||||||
|
previousI = i
|
||||||
|
goto RESETLOOP
|
||||||
|
-- Apparently "for i = 1, n" loops don't change when n changes. So when the table gets extended, packages near the end won't get picked up.
|
||||||
|
-- This is why it is needed to restart the loop.
|
||||||
|
elseif packageConfig.type == "virtual-package" then
|
||||||
|
print(("Installing virtual package %s"):format(packages[i]))
|
||||||
|
local pkgAskText = ("Select a package by typing in its number: 1) %s"):format(packageConfig.packages[1])
|
||||||
|
-- This is all a silly workaround to place commas correctly
|
||||||
|
for i = 2, #packageConfig.packages do
|
||||||
|
pkgAskText = pkgAskText .. (", %d) %s"):format(i, packageConfig.packages[i])
|
||||||
|
end
|
||||||
|
print(pkgAskText)
|
||||||
|
::RETRY::
|
||||||
|
local packageSel = terminal.read()
|
||||||
|
if not tonumber(packageSel) or tonumber(packageSel) % 1 ~= 0 then
|
||||||
|
-- Is there really no better way to check for an int..?
|
||||||
|
print("\27[93mNon-integer received - try again\27[0m")
|
||||||
|
goto RETRY
|
||||||
|
end
|
||||||
|
if tonumber(packageSel) < 1 or tonumber(packageSel) > #packageConfig.packages then
|
||||||
|
print("\27[93mInteger out of range - try again\27[0m")
|
||||||
|
end
|
||||||
|
packages[i] = packageConfig.packages[tonumber(packageSel)]
|
||||||
|
i = i - 1
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
if fs.exists(("/ag2/pkg/%s.json"):format(packages[i])) then
|
||||||
|
print(("\27[93mPackage %s is already installed, skipping\27[0m"):format(packages[i]))
|
||||||
|
table.remove(packages, i)
|
||||||
|
i = i - 1
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
if packageConfig.dependencies then
|
||||||
|
for _, dependency in ipairs(packageConfig.dependencies) do
|
||||||
|
table.insert(packages, i + 1, dependency)
|
||||||
|
dependencyCounter = dependencyCounter + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- TODO: Add checks for conflicting packages
|
||||||
|
::SKIP::
|
||||||
|
end
|
||||||
|
elseif command == "remove" then
|
||||||
|
::JUMPBACK::
|
||||||
|
local doJumpBack = false
|
||||||
|
for i = 1, #packages do
|
||||||
|
if not fs.exists(("/ag2/pkg/%s.json"):format(packages[i])) then
|
||||||
|
if parsed.s or parsed.source then
|
||||||
|
source = parsed.s or parsed.source
|
||||||
|
else
|
||||||
|
source = registry[package]
|
||||||
|
end
|
||||||
|
if source then
|
||||||
|
local packageConfig = getServersidePackageConfig(source, packages[i])
|
||||||
|
if packageConfig then
|
||||||
|
if packageConfig.type == "virtual-package" or packageConfig.type == "group" then
|
||||||
|
table.remove(packages, i)
|
||||||
|
for _, groupPackage in ipairs(packageConfig.packages) do
|
||||||
|
table.insert(packages, groupPackage)
|
||||||
|
goto GOAHEAD
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print(("\27[93mPackage %s is not installed, skipping\27[0m"):format(packages[i]))
|
||||||
|
table.remove(packages, i)
|
||||||
|
i = i - 1
|
||||||
|
::GOAHEAD::
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- I was originally gonna add this in the dependency cascade section, but realized it could shorten the normal dependency check code a bit
|
||||||
|
local dependencyList = {}
|
||||||
|
for _, packageConfig in ipairs(fs.list("/ag2/pkg/")) do
|
||||||
|
local package = packageConfig:sub(1, -6)
|
||||||
|
-- I'm not adding error handling here because if this fails then fuck you for touching the files by hand and good luck figuring this shit out
|
||||||
|
local _, data = getFile(("/ag2/pkg/%s.json"):format(package))
|
||||||
|
data = json.decode(data)
|
||||||
|
dependencyList[package] = data.dependencies
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, package in ipairs(packages) do
|
||||||
|
if dependencyList[package] then
|
||||||
|
-- Check if all the deps are no longer needed and if they're auto-installed and stuff
|
||||||
|
for _, dependency in pairs(dependencyList[package]) do
|
||||||
|
if fs.exists(("/ag2/pkg/%s.json"):format(dependency)) then
|
||||||
|
local _, data = getFile(("/ag2/pkg/%s.json"):format(dependency))
|
||||||
|
data = json.decode(data)
|
||||||
|
if data.autoInstalled
|
||||||
|
and not table.find(packages, dependency) -- Just to prevent dependency loops and issues when re-checking the packages after jumpback
|
||||||
|
then
|
||||||
|
dependencyCounter = dependencyCounter + 1
|
||||||
|
table.insert(packages, dependency)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- It could still be a group or a vpackage, and checking that is the job of the loop 2 loops back
|
||||||
|
table.insert(packages, dependency)
|
||||||
|
doJumpBack = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check for cascading dependencies
|
||||||
|
for packageName, dependencies in pairs(dependencyList) do
|
||||||
|
if not table.find(packages, packageName) then
|
||||||
|
for _, dependency in ipairs(dependencies) do
|
||||||
|
if table.find(packages, dependency) then
|
||||||
|
if parsed.flags.cascade or parsed.flags.C then
|
||||||
|
table.insert(packages, packageName)
|
||||||
|
dependencyCounter = dependencyCounter + 1
|
||||||
|
doJumpBack = true
|
||||||
|
-- Listen, I'm so sorry for this abhorrent bullshit code, but the newly added packages have to get checked one way or another and hopefully this is readable enough.
|
||||||
|
else
|
||||||
|
-- The Pyramids of Giza were built entirely out of silver. No they weren't...
|
||||||
|
print(("\27[93mPackage %s is depended on by %s, cannot uninstall without --cascade\27[0m"):format(dependency, packageName))
|
||||||
|
failure = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if doJumpBack then
|
||||||
|
goto JUMPBACK
|
||||||
|
-- IT'S NOT SPAGHETTI SHUT UP SHUT UP SHU
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- TODO: Add checks for the other commands
|
||||||
|
|
||||||
|
if #packages == 0 then
|
||||||
|
print("\27[93mNo packages selected.\n\27[0mExiting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if failure then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if command == "install" then
|
||||||
|
if dependencyCounter == 1 then
|
||||||
|
print("\27[93m1 dependency pulled in.\27[0m")
|
||||||
|
elseif dependencyCounter >= 2 then
|
||||||
|
print(("\27[93m%d dependencies pulled in.\27[0m"):format(dependencyCounter))
|
||||||
|
end
|
||||||
|
print("Packages that will be installed:")
|
||||||
|
print(table.concat(packages, ", "))
|
||||||
|
local answer = terminal.read({prefix = "\nContinue? [Y/n] "})
|
||||||
|
if answer:lower() == "n" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, package in ipairs(packages) do
|
||||||
|
local source
|
||||||
|
if parsed.s or parsed.source then
|
||||||
|
source = parsed.s or parsed.source
|
||||||
|
else
|
||||||
|
source = registry[package]
|
||||||
|
end
|
||||||
|
print(("Installing %s..."):format(package))
|
||||||
|
local _, data = getFile(fs.concat(source, "/ag2.json"))
|
||||||
|
local packageConfig = json.decode(data)[package]
|
||||||
|
if packageConfig.directories then
|
||||||
|
for _, directory in ipairs(packageConfig.directories) do
|
||||||
|
print((" Creating directory %s..."):format(directory))
|
||||||
|
fs.makeDirectory(directory)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if packageConfig.files then
|
||||||
|
for _, file in ipairs(packageConfig.files) do
|
||||||
|
::RETRY::
|
||||||
|
print((" Downloading file %s..."):format(file))
|
||||||
|
local success, data = getFile(fs.concat(source, file))
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
print(("\27[91mFailed to get file '%s' of package '%s': " .. data .. "\27[0m"):format(file, package))
|
||||||
|
local answer = terminal.read({prefix = "Abort, Retry, Skip? [a/R/s]"})
|
||||||
|
if answer:lower() == "a" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
elseif answer:lower() == "s" then
|
||||||
|
print((" \27[93mSkipped file %s.\27[0m"):format(file))
|
||||||
|
goto SKIP
|
||||||
|
else
|
||||||
|
goto RETRY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if fs.exists(file) then
|
||||||
|
print(("\27[93mFile '%s' already exists.\27[0m"):format(file))
|
||||||
|
local answer = terminal.read({prefix = "Abort, Overwrite, Skip? [a/O/s]"})
|
||||||
|
if answer:lower() == "a" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
elseif answer:lower() == "s" then
|
||||||
|
print((" \27[93mSkipped file %s.\27[0m"):format(file))
|
||||||
|
goto SKIP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local handle, errorMessage = fs.open(file, "w")
|
||||||
|
if not handle then
|
||||||
|
print(("\27[91mFailed to open write handle to file '%s': " .. errorMessage .. "\27[0m"):format(file))
|
||||||
|
local answer = terminal.read({prefix = "Abort, Retry, Skip? [a/R/s]"})
|
||||||
|
if answer:lower() == "a" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
elseif answer:lower() == "s" then
|
||||||
|
print((" \27[93mSkipped file %s.\27[0m"):format(file))
|
||||||
|
goto SKIP
|
||||||
|
else
|
||||||
|
goto RETRY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local success, errorMessage = handle:write(data)
|
||||||
|
if not success then
|
||||||
|
handle:close()
|
||||||
|
print(("\27[91mFailed to write to file '%s': " .. errorMessage .. "\27[0m"):format(file))
|
||||||
|
local answer = terminal.read({prefix = "Abort, Retry, Skip? [a/R/s]"})
|
||||||
|
if answer:lower() == "a" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
elseif answer:lower() == "s" then
|
||||||
|
print((" \27[93mSkipped file %s.\27[0m"):format(file))
|
||||||
|
goto SKIP
|
||||||
|
else
|
||||||
|
goto RETRY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
handle:close()
|
||||||
|
|
||||||
|
::SKIP::
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print(" Writing tracking file...")
|
||||||
|
if not fs.exists("/ag2/pkg/") then
|
||||||
|
fs.makeDirectory("/ag2/pkg/")
|
||||||
|
-- Technically this would break if /ag2/pkg/ was a file, but... why would it be a file?
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: Make functions for reading from and writing to a file with error handling since this is really repetitive
|
||||||
|
::RETRY::
|
||||||
|
local handle, errorMessage = fs.open(("/ag2/pkg/%s.json"):format(package), "w")
|
||||||
|
if not handle then
|
||||||
|
print(("\27[91mFailed to open write handle to file '/ag2/pkg/%s.json': " .. errorMessage .. "\27[0m"):format(package))
|
||||||
|
local answer = terminal.read({prefix = "Abort, Retry, Skip? [a/R/s]"})
|
||||||
|
if answer:lower() == "a" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
elseif answer:lower() == "s" then
|
||||||
|
print((" \27[93mSkipped file /ag2/pkg/%s.json.\27[0m"):format(package))
|
||||||
|
goto SKIP
|
||||||
|
else
|
||||||
|
goto RETRY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local packageData = {
|
||||||
|
name = package,
|
||||||
|
version = packageConfig.version,
|
||||||
|
autoInstalled = false,
|
||||||
|
-- TODO: Make the above actually work
|
||||||
|
dependencies = packageConfig.dependencies,
|
||||||
|
conflicts = packageConfig.conflicts,
|
||||||
|
files = packageConfig.files,
|
||||||
|
directories = packageConfig.directories,
|
||||||
|
config = packageConfig.config
|
||||||
|
}
|
||||||
|
|
||||||
|
local trackingFile = json.encode(packageData)
|
||||||
|
|
||||||
|
local success, errorMessage = handle:write(trackingFile)
|
||||||
|
if not success then
|
||||||
|
handle:close()
|
||||||
|
print(("\27[91mFailed to write to file '/ag2/pkg/%s.json': " .. errorMessage .. "\27[0m"):format(package))
|
||||||
|
local answer = terminal.read({prefix = "Abort, Retry, Skip? [a/R/s]"})
|
||||||
|
if answer:lower() == "a" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
elseif answer:lower() == "s" then
|
||||||
|
print((" \27[93mSkipped file /ag2/pkg/%s.json.\27[0m"):format(package))
|
||||||
|
goto SKIP
|
||||||
|
else
|
||||||
|
goto RETRY
|
||||||
|
end
|
||||||
|
else
|
||||||
|
handle:close()
|
||||||
|
end
|
||||||
|
::SKIP::
|
||||||
|
end
|
||||||
|
elseif command == "remove" then
|
||||||
|
if dependencyCounter == 1 then
|
||||||
|
print("\27[93m1 orphaned dependency will be removed.\27[0m")
|
||||||
|
elseif dependencyCounter >= 2 then
|
||||||
|
print(("\27[93m%d orphaned dependencies will be removed.\27[0m"):format(dependencyCounter))
|
||||||
|
end
|
||||||
|
print("Packages that will be removed:")
|
||||||
|
print(table.concat(packages, ", "))
|
||||||
|
local answer = terminal.read({prefix = "\nContinue? [Y/n] "})
|
||||||
|
if answer:lower() == "n" then
|
||||||
|
print("Exiting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for _, package in ipairs(packages) do
|
||||||
|
-- See line 263
|
||||||
|
local _, data = getFile(("/ag2/pkg/%s.json"):format(package))
|
||||||
|
data = json.decode(data)
|
||||||
|
if data.files then
|
||||||
|
for _, file in ipairs(data.files) do
|
||||||
|
print((" Removing file %s..."):format(file))
|
||||||
|
fs.remove(file) -- I cannot think of how this could fail. If you can, please add error handling here
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if data.directories then
|
||||||
|
for _, directory in ipairs(data.directories) do
|
||||||
|
if fs.isDirectory(directory) then
|
||||||
|
if next(fs.list(directory)) == nil then
|
||||||
|
-- Apparently THAT's the best way to check if a table is empty in Lua. Alright I guess.
|
||||||
|
print((" Removing directory %s..."):format(directory))
|
||||||
|
fs.remove(directory)
|
||||||
|
else
|
||||||
|
print((" Directory %s specified by package %s still has something in it, skipping"):format(directory))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print(" Removing tracking file...")
|
||||||
|
fs.remove(("/ag2/pkg/%s.json"):format(package)) -- See line 500
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print("Operation completed successfully.")
|
||||||
+41
-44
@@ -1,6 +1,6 @@
|
|||||||
local packages = {...}
|
local packages = {...}
|
||||||
local command = packages[1]
|
local command = table.remove(packages,1)
|
||||||
table.remove(packages, 1)
|
local shell = require("shell")
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
local component = require("component")
|
local component = require("component")
|
||||||
local agReg = require("/argentum/registry.cfg")
|
local agReg = require("/argentum/registry.cfg")
|
||||||
@@ -9,7 +9,7 @@ if not command then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not component.list("internet")() then
|
if not component.list("internet")() then
|
||||||
print("\27[91mThis program requires an internet card to run.")
|
print("\27[91mThis program requires an internet card to run.\27[0m")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local internet = component.internet
|
local internet = component.internet
|
||||||
@@ -69,12 +69,12 @@ local function getAgConfig(package, source)
|
|||||||
source = source or agReg[package]
|
source = source or agReg[package]
|
||||||
local data, errorMessage = getFile(source .. "argentum.cfg")
|
local data, errorMessage = getFile(source .. "argentum.cfg")
|
||||||
if not data or data == "" then
|
if not data or data == "" then
|
||||||
print("\27[91mCould not fetch Ag config: " .. (errorMessage or "returned nil data"))
|
print("\27[91mCould not fetch Ag config: " .. (errorMessage or "returned nil data") .. "\27[0m")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local func, errorMessage = load(data, "=argentum.cfg", "bt", {})
|
local func, errorMessage = load(data, "=argentum.cfg", "bt", {})
|
||||||
if not func then
|
if not func then
|
||||||
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
|
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.\27[0m")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local agcfg
|
local agcfg
|
||||||
@@ -82,22 +82,22 @@ local function getAgConfig(package, source)
|
|||||||
agcfg = func()
|
agcfg = func()
|
||||||
end)
|
end)
|
||||||
if not status then
|
if not status then
|
||||||
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
|
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.\27[0m")
|
||||||
return false
|
return false
|
||||||
end
|
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
|
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.")
|
local response = "\27[91mAg config of " .. package .. " is improperly configured.\nPlease contact the package owner.\27[0m"
|
||||||
end
|
end
|
||||||
return agcfg
|
return agcfg
|
||||||
end
|
end
|
||||||
|
|
||||||
local function doChecks(package)
|
local function doChecks(package)
|
||||||
if not agReg[package] and not source then
|
if not agReg[package] and not source then
|
||||||
print("\27[91mPackage " .. package .. " does not exist.")
|
print("\27[91mPackage " .. package .. " does not exist.\27[0m")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if fs.exists("/argentum/store/" .. package) then
|
if fs.exists("/argentum/store/" .. package) then
|
||||||
print("\27[91mPackage " .. package .. " is already installed.")
|
print("\27[91mPackage " .. package .. " is already installed.\27[0m")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
agcfg = getAgConfig(package, source)
|
agcfg = getAgConfig(package, source)
|
||||||
@@ -107,7 +107,7 @@ local function doChecks(package)
|
|||||||
if agcfg[package].dependencies then
|
if agcfg[package].dependencies then
|
||||||
for _, dependency in ipairs(agcfg[package].dependencies) do
|
for _, dependency in ipairs(agcfg[package].dependencies) do
|
||||||
if not agReg[dependency] and not agcfg[dependency] then
|
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]")
|
local response = terminal.read({prefix = "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]\27[0m"})
|
||||||
if response:lower() ~= "s" then
|
if response:lower() ~= "s" then
|
||||||
fs.remove("/argentum/store/" .. package)
|
fs.remove("/argentum/store/" .. package)
|
||||||
return false
|
return false
|
||||||
@@ -132,24 +132,21 @@ local function lpad(str, len, char)
|
|||||||
return string.rep(char, len - #str) .. str
|
return string.rep(char, len - #str) .. str
|
||||||
end
|
end
|
||||||
|
|
||||||
local gpu = component.gpu
|
local width, height = terminal.getResolution()
|
||||||
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 function progress(package, progress)
|
||||||
local progX = math.floor(progress*width)
|
terminal.write("\x1b[s")
|
||||||
gpu.setBackground(0x00FF00)
|
local info = string.format("%s %s%%", package, lpad(math.floor(progress * 100), 2))
|
||||||
gpu.setForeground(0x000000)
|
info = info .. string.rep(" ", width - #info)
|
||||||
gpu.set(1,height,info:sub(1,progX))
|
local progX = math.floor(progress * width)
|
||||||
gpu.setBackground(0x000000)
|
terminal.write("\x1b[42m\x1b[30m" .. info:sub(1, progX) .. "\x1b[40m\x1b[37m" .. info:sub(progX + 1) .. "\x1b[0m")
|
||||||
gpu.setForeground(0xFFFFFF)
|
terminal.write("\x1b[u")
|
||||||
gpu.set(progX+1,height,info:sub(progX+1))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clearProgress()
|
local function clearProgress()
|
||||||
gpu.setBackground(0x000000)
|
terminal.write("\x1b[s")
|
||||||
gpu.fill(1,height,width,1," ")
|
terminal.write("\r\x1b[40m" .. string.rep(" ", width) .. "\x1b[0m\r")
|
||||||
|
terminal.write("\x1b[u")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function installPackage(package, overwriteFlag)
|
local function installPackage(package, overwriteFlag)
|
||||||
@@ -166,7 +163,7 @@ local function installPackage(package, overwriteFlag)
|
|||||||
if agcfg[package].dependencies then
|
if agcfg[package].dependencies then
|
||||||
for _, dependency in ipairs(agcfg[package].dependencies) do
|
for _, dependency in ipairs(agcfg[package].dependencies) do
|
||||||
if not agReg[dependency] and not agcfg[dependency] then
|
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]")
|
local response = terminal.read({prefix = "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]\27[0m"})
|
||||||
if response:lower() ~= "s" then
|
if response:lower() ~= "s" then
|
||||||
fs.remove("/argentum/store/" .. package)
|
fs.remove("/argentum/store/" .. package)
|
||||||
return false
|
return false
|
||||||
@@ -199,7 +196,7 @@ local function installPackage(package, overwriteFlag)
|
|||||||
local data, errorMessage = getFile(source .. agcfg[package].maindir .. file)
|
local data, errorMessage = getFile(source .. agcfg[package].maindir .. file)
|
||||||
if not data then
|
if not data then
|
||||||
clearProgress()
|
clearProgress()
|
||||||
local response = read(nil, "\27[91mCould not fetch " .. file .. ": " .. errorMessage .. "\n\27[0m[a - Abort/R - Retry/s - Skip]")
|
local response = terminal.read({prefix = "\27[91mCould not fetch " .. file .. ": " .. errorMessage .. "\n\27[0m[a - Abort/R - Retry/s - Skip]"})
|
||||||
if response:lower() == "a" then
|
if response:lower() == "a" then
|
||||||
fs.remove("/argentum/store/" .. package)
|
fs.remove("/argentum/store/" .. package)
|
||||||
return false
|
return false
|
||||||
@@ -218,7 +215,7 @@ local function installPackage(package, overwriteFlag)
|
|||||||
else
|
else
|
||||||
packageStore = packageStore .. "\nA" .. file
|
packageStore = packageStore .. "\nA" .. file
|
||||||
end
|
end
|
||||||
local handle = fs.open(file, "w")
|
local handle, err = fs.open(file, "w")
|
||||||
handle:write(data)
|
handle:write(data)
|
||||||
handle:close()
|
handle:close()
|
||||||
::skip::
|
::skip::
|
||||||
@@ -234,7 +231,7 @@ end
|
|||||||
local function removePackage(package)
|
local function removePackage(package)
|
||||||
print("Removing " .. package .. "...")
|
print("Removing " .. package .. "...")
|
||||||
if not fs.exists("/argentum/store/" .. package .. "/package.cfg") then
|
if not fs.exists("/argentum/store/" .. package .. "/package.cfg") then
|
||||||
print("\27[91mLocal Ag config of " .. package .. " does not exist.")
|
print("\27[91mLocal Ag config of " .. package .. " does not exist.\27[0m")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
|
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
|
||||||
@@ -258,7 +255,7 @@ local function removePackage(package)
|
|||||||
local result, errorMessage = fs.remove(line:sub(2))
|
local result, errorMessage = fs.remove(line:sub(2))
|
||||||
if not result then
|
if not result then
|
||||||
clearProgress()
|
clearProgress()
|
||||||
local response = read(nil, "\27[91mFailed to remove " .. line:sub(2) .. ": " .. errorMessage .. "\n\27[0m[a - Abort/r - Retry/S - Skip]")
|
local response = terminal.read({prefix = "\27[91mFailed to remove " .. line:sub(2) .. ": " .. errorMessage .. "\n\27[0m[a - Abort/r - Retry/S - Skip]"})
|
||||||
if response:lower() == "a" then
|
if response:lower() == "a" then
|
||||||
return false
|
return false
|
||||||
elseif response:lower() == "r" then
|
elseif response:lower() == "r" then
|
||||||
@@ -274,7 +271,7 @@ local function removePackage(package)
|
|||||||
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/files/" .. line:sub(2), "r"), "", nil
|
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/files/" .. line:sub(2), "r"), "", nil
|
||||||
if not handle then
|
if not handle then
|
||||||
clearProgress()
|
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
|
local response = terminal.read({prefix = "\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
|
if response:lower() == "a" then
|
||||||
return false
|
return false
|
||||||
elseif response:lower() == "s" then
|
elseif response:lower() == "s" then
|
||||||
@@ -344,7 +341,7 @@ if command == "install" then
|
|||||||
handle:write(newRegistry)
|
handle:write(newRegistry)
|
||||||
handle:close()
|
handle:close()
|
||||||
else
|
else
|
||||||
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
|
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil") .. "\27[0m")
|
||||||
end
|
end
|
||||||
agReg = require("/argentum/registry.cfg")
|
agReg = require("/argentum/registry.cfg")
|
||||||
while true do
|
while true do
|
||||||
@@ -360,7 +357,7 @@ if command == "install" then
|
|||||||
local answer
|
local answer
|
||||||
if #fails == 0 then
|
if #fails == 0 then
|
||||||
print("Packages that will be installed: " .. table.concat(packageList, ", "))
|
print("Packages that will be installed: " .. table.concat(packageList, ", "))
|
||||||
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
|
if terminal.read({prefix = "Would you like to proceed? [Y/n] "}):lower() == "n" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
elseif #packageList == 0 then
|
elseif #packageList == 0 then
|
||||||
@@ -370,7 +367,7 @@ if command == "install" then
|
|||||||
print("Some packages cannot be installed.")
|
print("Some packages cannot be installed.")
|
||||||
print("Packages that will be installed: " .. table.concat(packageList, ", "))
|
print("Packages that will be installed: " .. table.concat(packageList, ", "))
|
||||||
print("Packages that cannot be installed: " .. table.concat(fails, ", "))
|
print("Packages that cannot be installed: " .. table.concat(fails, ", "))
|
||||||
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
|
if terminal.read({prefix = "Would you like to proceed? [y/N] "}):lower() ~= "y" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -402,19 +399,19 @@ elseif command == "remove" then
|
|||||||
end
|
end
|
||||||
while true do
|
while true do
|
||||||
if not fs.exists("/argentum/store/" .. packages[i]) then
|
if not fs.exists("/argentum/store/" .. packages[i]) then
|
||||||
print("\27[91mPackage " .. packages[i] .. " is not installed.")
|
print("\27[91mPackage " .. packages[i] .. " is not installed.\27[0m")
|
||||||
table.insert(fails, packages[i])
|
table.insert(fails, packages[i])
|
||||||
table.remove(packageList, table.find(packageList, packages[i]))
|
table.remove(packageList, table.find(packageList, packages[i]))
|
||||||
table.remove(packages, table.find(packages, packages[i]))
|
table.remove(packages, table.find(packages, packages[i]))
|
||||||
i = i - 1
|
i = i - 1
|
||||||
elseif packages[i] == "halyde" then -- yes, this stuff is hard-coded.
|
elseif packages[i] == "halyde" then -- yes, this stuff is hard-coded.
|
||||||
print("\27[91mFor obvious reasons, you can't uninstall Halyde.")
|
print("\27[91mFor obvious reasons, you can't uninstall Halyde.\27[0m")
|
||||||
table.insert(fails, packages[i])
|
table.insert(fails, packages[i])
|
||||||
table.remove(packageList, table.find(packageList, packages[i]))
|
table.remove(packageList, table.find(packageList, packages[i]))
|
||||||
table.remove(packages, table.find(packages, packages[i]))
|
table.remove(packages, table.find(packages, packages[i]))
|
||||||
i = i - 1
|
i = i - 1
|
||||||
elseif packages[i] == "argentum" then
|
elseif packages[i] == "argentum" then
|
||||||
print("\27[91mFor obvious reasons, you can't uninstall Argentum.")
|
print("\27[91mFor obvious reasons, you can't uninstall Argentum.\27[0m")
|
||||||
table.insert(fails, packages[i])
|
table.insert(fails, packages[i])
|
||||||
table.remove(packageList, table.find(packageList, packages[i]))
|
table.remove(packageList, table.find(packageList, packages[i]))
|
||||||
table.remove(packages, table.find(packages, packages[i]))
|
table.remove(packages, table.find(packages, packages[i]))
|
||||||
@@ -452,7 +449,7 @@ elseif command == "remove" then
|
|||||||
local answer
|
local answer
|
||||||
if #fails == 0 then
|
if #fails == 0 then
|
||||||
print("Packages that will be removed: " .. table.concat(packageList, ", "))
|
print("Packages that will be removed: " .. table.concat(packageList, ", "))
|
||||||
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
|
if terminal.read({prefix = "Would you like to proceed? [Y/n] "}):lower() == "n" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
elseif #packageList == 0 then
|
elseif #packageList == 0 then
|
||||||
@@ -462,7 +459,7 @@ elseif command == "remove" then
|
|||||||
print("Some packages cannot be removed.")
|
print("Some packages cannot be removed.")
|
||||||
print("Packages that will be removed: " .. table.concat(packageList, ", "))
|
print("Packages that will be removed: " .. table.concat(packageList, ", "))
|
||||||
print("Packages that cannot be removed: " .. table.concat(fails, ", "))
|
print("Packages that cannot be removed: " .. table.concat(fails, ", "))
|
||||||
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
|
if terminal.read({prefix = "Would you like to proceed? [y/N] "}):lower() ~= "y" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -495,7 +492,7 @@ elseif command == "update" then
|
|||||||
handle:write(newRegistry)
|
handle:write(newRegistry)
|
||||||
handle:close()
|
handle:close()
|
||||||
else
|
else
|
||||||
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
|
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil") .. "\27[0m")
|
||||||
end
|
end
|
||||||
agReg = require("/argentum/registry.cfg")
|
agReg = require("/argentum/registry.cfg")
|
||||||
if not packages[1] then
|
if not packages[1] then
|
||||||
@@ -541,7 +538,7 @@ elseif command == "update" then
|
|||||||
table.remove(packages, table.find(packages, packages[i]))
|
table.remove(packages, table.find(packages, packages[i]))
|
||||||
i = i - 1
|
i = i - 1
|
||||||
else
|
else
|
||||||
print(packages[i].." is out of date [\x1b[93m"..version.."\x1b[39m < \x1b[92m"..agcfg[packages[i]].version.."\x1b[39m]")
|
print(packages[i].." is out of date [\x1b[93m"..version.."\x1b[0m < \x1b[92m"..agcfg[packages[i]].version.."\x1b[0m")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
@@ -560,14 +557,14 @@ elseif command == "update" then
|
|||||||
end
|
end
|
||||||
elseif #fails == 0 then
|
elseif #fails == 0 then
|
||||||
print("Packages that will be updated: " .. table.concat(packageList, ", "))
|
print("Packages that will be updated: " .. table.concat(packageList, ", "))
|
||||||
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
|
if terminal.read({prefix = "Would you like to proceed? [Y/n] "}):lower() == "n" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print("Some packages cannot be updated.")
|
print("Some packages cannot be updated.")
|
||||||
print("Packages that will be updated: " .. table.concat(packageList, ", "))
|
print("Packages that will be updated: " .. table.concat(packageList, ", "))
|
||||||
print("Packages that cannot be updated: " .. table.concat(fails, ", "))
|
print("Packages that cannot be updated: " .. table.concat(fails, ", "))
|
||||||
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
|
if terminal.read({prefix = "Would you like to proceed? [y/N] "}):lower() ~= "y" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -630,7 +627,7 @@ elseif command == "info" then
|
|||||||
handle:write(newRegistry)
|
handle:write(newRegistry)
|
||||||
handle:close()
|
handle:close()
|
||||||
else
|
else
|
||||||
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
|
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil") .. "\27[0m")
|
||||||
end
|
end
|
||||||
agReg = require("/argentum/registry.cfg")
|
agReg = require("/argentum/registry.cfg")
|
||||||
if not agReg[packages[1]] and not source then
|
if not agReg[packages[1]] and not source then
|
||||||
@@ -677,7 +674,7 @@ elseif command == "list" then
|
|||||||
handle:write(newRegistry)
|
handle:write(newRegistry)
|
||||||
handle:close()
|
handle:close()
|
||||||
else
|
else
|
||||||
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil"))
|
print("\27[91mFailed to fetch Ag registry: " .. (errorMessage or "returned nil") .. "\27[0m")
|
||||||
end
|
end
|
||||||
agReg = require("/argentum/registry.cfg")
|
agReg = require("/argentum/registry.cfg")
|
||||||
local sortedPackages = {}
|
local sortedPackages = {}
|
||||||
|
|||||||
@@ -0,0 +1,334 @@
|
|||||||
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
local gpu = require("component").gpu
|
||||||
|
local event = require("event")
|
||||||
|
local computer = require("computer")
|
||||||
|
local ocelot = require("component").ocelot
|
||||||
|
|
||||||
|
local resX, resY = gpu.getResolution()
|
||||||
|
local textBuffer = gpu.allocateBuffer(resX, resY - 1)
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
local file = args[1]
|
||||||
|
if not file then
|
||||||
|
print("\x1b[91mEnter a file name.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if fs.isDirectory(file) then
|
||||||
|
print("\x1b[91mThe specified file is a directory.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if file:sub(1, 1) ~= "/" then
|
||||||
|
file = fs.concat(shell.getWorkingDirectory(), file)
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = ""
|
||||||
|
if fs.exists(file) then
|
||||||
|
local handle = fs.open(file)
|
||||||
|
local tmpdata
|
||||||
|
repeat
|
||||||
|
tmpdata = handle:read(math.huge or math.maxinteger)
|
||||||
|
data = data .. (tmpdata or "")
|
||||||
|
until not tmpdata
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
for line in data:gmatch("[^\r\n]+") do
|
||||||
|
table.insert(lines, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function renderText(xOffset, yOffset)
|
||||||
|
gpu.setActiveBuffer(textBuffer)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.fill(1, 1, resX, resY - 1, " ")
|
||||||
|
for i = yOffset + 1, #lines do
|
||||||
|
gpu.set(1, i - yOffset, lines[i]:sub(xOffset + 1))
|
||||||
|
end
|
||||||
|
gpu.setActiveBuffer(0)
|
||||||
|
gpu.bitblt(0, 1, 1, resX, resY - 1, textBuffer, 1, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addLine(pos)
|
||||||
|
if pos <= #lines then
|
||||||
|
for i = #lines, pos, -1 do
|
||||||
|
lines[i + 1] = lines[i]
|
||||||
|
end
|
||||||
|
lines[pos] = ""
|
||||||
|
else
|
||||||
|
table.insert(lines, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function removeLine(pos)
|
||||||
|
length = #lines
|
||||||
|
for i = pos + 1, length do
|
||||||
|
lines[i - 1] = lines[i]
|
||||||
|
end
|
||||||
|
lines[length] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function save()
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.set(1, resY, "Enter a location to save:")
|
||||||
|
|
||||||
|
local savepath = file or ""
|
||||||
|
local saveCursorX = 27 + #savepath
|
||||||
|
local ready = false
|
||||||
|
local eventArgs = {}
|
||||||
|
|
||||||
|
gpu.fill(27, resY, resX - 27, 1, " ")
|
||||||
|
gpu.set(27, resY, savepath)
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
gpu.set(saveCursorX, resY, " ")
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
|
||||||
|
repeat
|
||||||
|
local shouldRender = false
|
||||||
|
coroutine.yield()
|
||||||
|
|
||||||
|
eventArgs = {event.pull("key_down", 0)}
|
||||||
|
if keyboard.keys[eventArgs[4]] == "enter" then
|
||||||
|
ready = true
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "back" then
|
||||||
|
savepath = string.sub(savepath, 1, #savepath - 1)
|
||||||
|
if saveCursorX > 27 then
|
||||||
|
saveCursorX = saveCursorX - 1
|
||||||
|
end
|
||||||
|
shouldRender = true
|
||||||
|
end
|
||||||
|
if not keyboard.keys.special[eventArgs[4]] and keyboard.keys[eventArgs[4]] then
|
||||||
|
savepath = savepath .. (string.char(eventArgs[3]) or "")
|
||||||
|
saveCursorX = saveCursorX + 1
|
||||||
|
shouldRender = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if shouldRender then
|
||||||
|
gpu.fill(27, resY, resX - 27, 1, " ")
|
||||||
|
gpu.set(27, resY, savepath)
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
gpu.set(saveCursorX, resY, " ")
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
end
|
||||||
|
until ready
|
||||||
|
|
||||||
|
gpu.fill(1, resY, resX, 1, " ")
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
gpu.set(1, resY, "^X")
|
||||||
|
gpu.set(10, resY, "^S")
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.set(4, resY, "Exit")
|
||||||
|
gpu.set(13, resY, "Save")
|
||||||
|
|
||||||
|
local text = table.concat(lines, "\n")
|
||||||
|
local handle = fs.open(savepath, "w")
|
||||||
|
handle:write(text)
|
||||||
|
handle:close()
|
||||||
|
file = savepath
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize screen
|
||||||
|
renderText(0, 0)
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
gpu.set(1, resY, "^X")
|
||||||
|
gpu.set(10, resY, "^S")
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.set(4, resY, "Exit")
|
||||||
|
gpu.set(13, resY, "Save")
|
||||||
|
|
||||||
|
local scrollX = 0
|
||||||
|
local scrollY = 0
|
||||||
|
local cursorX = 1 -- Absolute position, not accounting for scrolling
|
||||||
|
local cursorY = 1
|
||||||
|
local cursorWhite = true
|
||||||
|
local oldTime = computer.uptime()
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local renderBufferFlag = false -- Flag to render the whole text buffer
|
||||||
|
-- Handle events
|
||||||
|
local previousCursorX -- Used for blackening the previous cursor location when the cursor is moved
|
||||||
|
local previousCursorY
|
||||||
|
coroutine.yield()
|
||||||
|
local eventArgs = {}
|
||||||
|
repeat
|
||||||
|
eventArgs = {event.pull("key_down", 0)}
|
||||||
|
|
||||||
|
-- The logical solution here for flashing the cursor would be to set the timeout to 0.5, and, if the timeout is reached, change the color.
|
||||||
|
-- However, that makes scrolling freeze the screen up completely.
|
||||||
|
-- Thus, for flashing the cursor, a timer is needed.
|
||||||
|
|
||||||
|
if computer.uptime() >= oldTime + 0.5 then
|
||||||
|
oldTime = computer.uptime()
|
||||||
|
cursorWhite = not cursorWhite
|
||||||
|
end
|
||||||
|
|
||||||
|
if next(eventArgs) ~= nil then
|
||||||
|
cursorWhite = true
|
||||||
|
oldTime = computer.uptime()
|
||||||
|
end
|
||||||
|
|
||||||
|
if eventArgs[1] == "key_down" then
|
||||||
|
-- Mouse events might be added later, that's why this if statement is here
|
||||||
|
if keyboard.getCtrlDown() then
|
||||||
|
-- Special commands
|
||||||
|
if keyboard.keys[eventArgs[4]] == "x" then
|
||||||
|
goto exit
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "s" then
|
||||||
|
save()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if keyboard.keys[eventArgs[4]] == "up" and cursorY > 1 then
|
||||||
|
if cursorY - scrollY <= 1 then
|
||||||
|
renderBufferFlag = true
|
||||||
|
scrollY = scrollY - 1
|
||||||
|
else
|
||||||
|
if not previousCursorX and not previousCursorY then
|
||||||
|
previousCursorX = cursorX
|
||||||
|
previousCursorY = cursorY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cursorY = cursorY - 1
|
||||||
|
-- The cursor absolute position still has to be moved, even if on-screen it won't move
|
||||||
|
if cursorX > string.len(lines[cursorY]) + 1 then -- cursor snapping, +1 to be 1 char in front of end of line
|
||||||
|
cursorX = string.len(lines[cursorY]) + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "down" then
|
||||||
|
if cursorY - scrollY >= resY - 1 then
|
||||||
|
renderBufferFlag = true
|
||||||
|
scrollY = scrollY + 1
|
||||||
|
else
|
||||||
|
if not previousCursorX and not previousCursorY then
|
||||||
|
previousCursorX = cursorX
|
||||||
|
previousCursorY = cursorY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cursorY = cursorY + 1
|
||||||
|
if cursorX > string.len(lines[cursorY]) + 1 then
|
||||||
|
cursorX = string.len(lines[cursorY]) + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "left" and cursorX > 1 then
|
||||||
|
if cursorX - scrollX <= 1 then
|
||||||
|
renderBufferFlag = true
|
||||||
|
scrollX = scrollX - 1
|
||||||
|
else
|
||||||
|
if not previousCursorX and not previousCursorY then
|
||||||
|
previousCursorX = cursorX
|
||||||
|
previousCursorY = cursorY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cursorX = cursorX - 1
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "right" and cursorX < string.len(lines[cursorY]) + 1 then
|
||||||
|
if cursorX - scrollX >= resX then
|
||||||
|
renderBufferFlag = true
|
||||||
|
scrollX = scrollX + 1
|
||||||
|
else
|
||||||
|
if not previousCursorX and not previousCursorY then
|
||||||
|
previousCursorX = cursorX
|
||||||
|
previousCursorY = cursorY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cursorX = cursorX + 1
|
||||||
|
end
|
||||||
|
if not keyboard.keys.special[eventArgs[4]] then
|
||||||
|
local line = lines[cursorY] or ""
|
||||||
|
line = string.sub(line, 1, cursorX - 1) .. string.char(eventArgs[3]) .. string.sub(line, cursorX, -1)
|
||||||
|
lines[cursorY] = line
|
||||||
|
cursorX = cursorX + 1
|
||||||
|
renderBufferFlag = true
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "back" then
|
||||||
|
local line = lines[cursorY]
|
||||||
|
local prevline = lines[cursorY - 1]
|
||||||
|
if cursorX > 1 then
|
||||||
|
line = string.sub(line, 1, cursorX - 2) .. string.sub(line, cursorX, -1) -- remove 1 char
|
||||||
|
elseif prevline then
|
||||||
|
prevline = prevline .. line -- copy line up to the next before removing it
|
||||||
|
ocelot.log(prevline)
|
||||||
|
line = nil
|
||||||
|
end
|
||||||
|
if line then
|
||||||
|
lines[cursorY] = line
|
||||||
|
else
|
||||||
|
removeLine(cursorY)
|
||||||
|
end
|
||||||
|
lines[cursorY - 1] = prevline
|
||||||
|
if not line then
|
||||||
|
cursorY = cursorY - 1 -- this can only trigger if the line is not the first
|
||||||
|
end
|
||||||
|
if cursorX > 1 then
|
||||||
|
cursorX = cursorX - 1
|
||||||
|
end
|
||||||
|
renderBufferFlag = true
|
||||||
|
end
|
||||||
|
if keyboard.keys[eventArgs[4]] == "enter" then
|
||||||
|
addLine(cursorY + 1)
|
||||||
|
cursorY = cursorY + 1
|
||||||
|
cursorX = 1
|
||||||
|
renderBufferFlag = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
until next(eventArgs) == nil
|
||||||
|
local displayedCursorX = cursorX - scrollX
|
||||||
|
local displayedCursorY = cursorY - scrollY
|
||||||
|
local previousDisplayedCursorX -- What a mouthful
|
||||||
|
local previousDisplayedCursorY
|
||||||
|
if previousCursorX and previousCursorY then
|
||||||
|
previousDisplayedCursorX = previousCursorX - scrollX
|
||||||
|
previousDisplayedCursorY = previousCursorY - scrollY
|
||||||
|
end
|
||||||
|
|
||||||
|
if renderBufferFlag then
|
||||||
|
renderText(scrollX, scrollY)
|
||||||
|
if cursorWhite then
|
||||||
|
-- If the cursor is black, then there's no need to do anything because there is no cursor after calling renderText().
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
local letter = gpu.get(displayedCursorX, displayedCursorY)
|
||||||
|
gpu.set(displayedCursorX, displayedCursorY, letter)
|
||||||
|
-- TODO: Account for scrolling
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if cursorWhite then
|
||||||
|
if previousCursorX or previousCursorY then
|
||||||
|
-- Remove old cursor
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
local letter = gpu.get(previousDisplayedCursorX, previousDisplayedCursorY)
|
||||||
|
gpu.set(previousDisplayedCursorX, previousDisplayedCursorY, letter)
|
||||||
|
end
|
||||||
|
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
local letter = gpu.get(displayedCursorX, displayedCursorY)
|
||||||
|
gpu.set(displayedCursorX, displayedCursorY, letter)
|
||||||
|
else
|
||||||
|
-- If renderText() hasn't been called, the cursor may still be white and need to be turned black.
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
local letter = gpu.get(displayedCursorX, displayedCursorY)
|
||||||
|
gpu.set(displayedCursorX, displayedCursorY, letter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cleanup
|
||||||
|
::exit::
|
||||||
|
gpu.freeBuffer(textBuffer)
|
||||||
|
gpu.setActiveBuffer(0)
|
||||||
|
terminal.clear()
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
local computer = require("computer")
|
||||||
|
local cliparse = require("cliparse")
|
||||||
|
|
||||||
|
cliparse.config({
|
||||||
|
["f"] = 1,
|
||||||
|
["frequency"] = 1,
|
||||||
|
["t"] = 1,
|
||||||
|
["time"] = 1,
|
||||||
|
})
|
||||||
|
local parsed, err = cliparse.parse(...)
|
||||||
|
if not parsed then
|
||||||
|
return print("\x1b[91m" .. err .. "\x1b[0m")
|
||||||
|
end
|
||||||
|
|
||||||
|
local freq =
|
||||||
|
tonumber(parsed.flags.f and parsed.flags.f[1] or parsed.flags.frequency and parsed.flags.frequency[1] or "440")
|
||||||
|
local time = tonumber(parsed.flags.t and parsed.flags.t[1] or parsed.flags.time and parsed.flags.time[1] or "0.1")
|
||||||
|
|
||||||
|
computer.beep(freq, time)
|
||||||
@@ -34,27 +34,27 @@ if type(args[1])=="string" then
|
|||||||
local compID,err = getComponentID(args[1])
|
local compID,err = getComponentID(args[1])
|
||||||
if not compID then
|
if not compID then
|
||||||
print("\x1b[91mCould not get component ID from '"..args[1].."'.")
|
print("\x1b[91mCould not get component ID from '"..args[1].."'.")
|
||||||
if type(err)=="string" then print("\x1b[91m"..err) end
|
if type(err)=="string" then print("\x1b[91m"..err.."\x1b[0m") end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not force then
|
if not force then
|
||||||
if componentlib.additions[compID] then
|
if component.virtual.check(compID) then
|
||||||
return print("\x1b[91mThis component is virtual and cannot be booted from directly.\nID: "..compID)
|
return print("\x1b[91mThis component is virtual and cannot be booted from directly.\nID: "..compID.."\x1b[0m")
|
||||||
end
|
end
|
||||||
local type = component.type(compID)
|
local type = component.type(compID)
|
||||||
if type~="filesystem" and type~="drive" then
|
if type~="filesystem" and type~="drive" then
|
||||||
return print("\x1b[91mThis component is not a storage medium.\nID: "..compID)
|
return print("\x1b[91mThis component is not a storage medium.\nID: "..compID.."\x1b[0m")
|
||||||
end
|
end
|
||||||
if type=="filesystem" and not fileExists(compID,"/init.lua") then
|
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)
|
return print("\x1b[91mThis storage medium doesn't have an \"init.lua\" file.\nID: "..compID.."\x1b[0m")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
computer.setBootAddress(compID)
|
computer.setBootAddress(compID)
|
||||||
if computer.getBootAddress()~=compID then
|
if computer.getBootAddress()~=compID then
|
||||||
return print("\x1b[91mFailed to set the boot address.")
|
return print("\x1b[91mFailed to set the boot address.\x1b[0m")
|
||||||
end
|
end
|
||||||
computer.shutdown(true)
|
computer.shutdown(true)
|
||||||
else
|
else
|
||||||
shell.run("help boot")
|
require("shell").run("help boot")
|
||||||
end
|
end
|
||||||
|
|||||||
+26
-16
@@ -1,20 +1,30 @@
|
|||||||
local files = {...}
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
if not files or not files[1] then
|
local shell = require("shell")
|
||||||
shell.run("help cat")
|
|
||||||
return
|
local args = {...}
|
||||||
|
|
||||||
|
if not args[1] then
|
||||||
|
return shell.run("help cat")
|
||||||
end
|
end
|
||||||
for _, file in ipairs(files) do
|
|
||||||
if file:sub(1, 1) ~= "/" then
|
for _, file in pairs(args) do
|
||||||
file = fs.concat(shell.workingDirectory, file)
|
file = shell.resolvePath(file)
|
||||||
end
|
|
||||||
if not fs.exists(file) then
|
|
||||||
print("\27[91mFile does not exist.")
|
|
||||||
end
|
|
||||||
local handle = fs.open(file, "r")
|
local handle = fs.open(file, "r")
|
||||||
local data
|
if handle == nil then
|
||||||
repeat
|
terminal.write("\27[91mCan't open " .. file .. "\27[0m\n")
|
||||||
data = handle:read(math.huge or math.maxinteger)
|
goto continue
|
||||||
termlib.write(data)
|
end
|
||||||
until not data
|
local enddata
|
||||||
|
while true do
|
||||||
|
local data = handle:read(math.huge or math.maxinteger)
|
||||||
|
if data == nil then break end
|
||||||
|
terminal.write(data)
|
||||||
|
enddata = data
|
||||||
|
end
|
||||||
|
handle:close()
|
||||||
|
if string.sub(enddata, -1, -1) ~= "\n" then
|
||||||
|
print("")
|
||||||
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
|
|||||||
+21
-9
@@ -1,14 +1,26 @@
|
|||||||
local directory = ...
|
local args = {...}
|
||||||
local fs = require("filesystem")
|
|
||||||
|
|
||||||
if not directory then
|
if args[2] then
|
||||||
|
terminal.write("\27[91mToo many arguments.\27[0m")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not args[1] then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if directory:sub(1, 1) ~= "/" then
|
|
||||||
directory = fs.concat(shell.workingDirectory, directory)
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
|
local directory = shell.resolvePath(args[1])
|
||||||
|
|
||||||
|
if not fs.exists(directory) then
|
||||||
|
terminal.write("\27[91mError: " .. directory .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
end
|
end
|
||||||
if fs.exists(directory) and fs.isDirectory(directory) then
|
|
||||||
shell.workingDirectory = fs.canonical(directory)
|
if not fs.isDirectory(directory) then
|
||||||
else
|
terminal.write("\27[91mError: " .. directory .. ": Not a directory\27[0m\n")
|
||||||
print("\27[91mNo such directory.")
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shell.setWorkingDirectory(fs.canonical(directory))
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
clear()
|
terminal.clear()
|
||||||
-- truly so much going on here
|
-- truly so much going on here
|
||||||
|
-- meow
|
||||||
|
|||||||
+62
-18
@@ -1,26 +1,70 @@
|
|||||||
local fromFile, toFile = ...
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
if not fromFile or not toFile then
|
local args = {...}
|
||||||
shell.run("help cp")
|
|
||||||
|
if not args[1] then
|
||||||
|
return shell.run("help cp")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not args[2] then
|
||||||
|
terminal.write("\27[91mError: No destination\27[0m\n")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if fromFile:sub(1, 1) ~= "/" then
|
|
||||||
fromFile = fs.concat(shell.workingDirectory, fromFile)
|
local dest = shell.resolvePath(args[#args])
|
||||||
end
|
|
||||||
if toFile:sub(1, 1) ~= "/" then
|
if fs.isFile(dest) then
|
||||||
toFile = fs.concat(shell.workingDirectory, toFile)
|
if #args ~= 2 then
|
||||||
end
|
terminal.write("\27[91mError: Destination is not a directory\27[0m\n")
|
||||||
if fromFile == toFile then
|
|
||||||
print("\27[91mSource and destination are the same.")
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not fs.exists(fromFile) then
|
local src = shell.resolvePath(args[1])
|
||||||
print("\27[91mSource file does not exist.")
|
if not fs.exists(src) then
|
||||||
|
terminal.write("\27[91mError: " .. src .. ": No such file or directory\27[0m\n")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if fs.exists(toFile) and not (table.find({...}, "-o") or table.find({...}, "--overwrite")) then
|
if fs.isDirectory(src) then
|
||||||
print("\27[91mDestination file already exists. Run this command again with -o to overwrite it.")
|
terminal.write("\27[91mError: Cannot write directory " .. src .. " to file " .. dest .. "\27[0m\n")
|
||||||
return
|
return
|
||||||
|
end
|
||||||
|
fs.copy(src, dest)
|
||||||
|
elseif fs.isDirectory(dest) then
|
||||||
|
for i = 1, #args - 1 do
|
||||||
|
local src = shell.resolvePath(args[i])
|
||||||
|
if src == dest then
|
||||||
|
terminal.write("\27[91mError: Source and destination are the same\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fs.exists(src) then
|
||||||
|
terminal.write("\27[91mError: " .. src .. ": No such file or directory\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
fs.copy(src, fs.concat(dest, fs.basename(src)))
|
||||||
|
::continue::
|
||||||
|
end
|
||||||
|
elseif not fs.exists(dest) then
|
||||||
|
if #args ~= 2 then
|
||||||
|
terminal.write("\27[91mError: " .. dest .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local src = shell.resolvePath(args[1])
|
||||||
|
if not fs.exists(src) then
|
||||||
|
terminal.write("\27[91mError: " .. src .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local destp = fs.parent(dest)
|
||||||
|
if not fs.exists(destp) then
|
||||||
|
terminal.write("\27[91mError: " .. destp .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not fs.isDirectory(destp) then
|
||||||
|
terminal.write("\27[91mError: " .. destp .. ": Not a directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
fs.copy(src, dest)
|
||||||
|
else
|
||||||
|
terminal.write("\27[91mUnknown error\27[0m\n")
|
||||||
end
|
end
|
||||||
fs.copy(fromFile, toFile)
|
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ local component = require("component")
|
|||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
|
||||||
if not component.list("internet")() then
|
if not component.list("internet")() then
|
||||||
print("\27[91mThis program requires an internet card to run.")
|
print("\27[91mThis program requires an internet card to run.\27[0m")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not url then
|
if not url then
|
||||||
print("Please enter a URL to download from.")
|
print("Please enter a URL to download from.")
|
||||||
shell.run("help download")
|
require("shell").run("help download")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -26,11 +26,11 @@ local status, errorMessage = pcall(function()
|
|||||||
request:finishConnect()
|
request:finishConnect()
|
||||||
end)
|
end)
|
||||||
if not status then
|
if not status then
|
||||||
print("\27[91mDownload failed: " .. errorMessage)
|
print("\27[91mDownload failed: " .. errorMessage .. "\27[0m")
|
||||||
end
|
end
|
||||||
local responseCode = request:response()
|
local responseCode = request:response()
|
||||||
if responseCode and responseCode ~= 200 then
|
if responseCode and responseCode ~= 200 then
|
||||||
print("\27[91mDownload failed: " .. tostring(responseCode))
|
print("\27[91mDownload failed: " .. tostring(responseCode) .. "\27[0m")
|
||||||
end
|
end
|
||||||
repeat
|
repeat
|
||||||
tmpdata = request.read(math.huge)
|
tmpdata = request.read(math.huge)
|
||||||
@@ -39,11 +39,11 @@ until not tmpdata
|
|||||||
local saveLocation
|
local saveLocation
|
||||||
local saveLocationOK = false
|
local saveLocationOK = false
|
||||||
repeat
|
repeat
|
||||||
saveLocation = read(nil, "File save location: ", fs.concat(shell.workingDirectory, url:match("/([^/]+)$")))
|
saveLocation = terminal.read(nil, "File save location: ", fs.concat(require("shell").getWorkingDirectory(), url:match("/([^/]+)$")))
|
||||||
if fs.isDirectory(saveLocation) then
|
if fs.isDirectory(saveLocation) then
|
||||||
print("\27[91mThe specified location is a directory.")
|
print("\27[91mThe specified location is a directory.\27[0m")
|
||||||
elseif fs.exists(saveLocation) then
|
elseif fs.exists(saveLocation) then
|
||||||
local answer = read(nil, "\27[91mThere is already a file at the specified directory. Overwrite it? [Y/n]")
|
local answer = terminal.read({prefix = "\27[91mThere is already a file at the specified directory. Overwrite it? [Y/n]\27[0m"})
|
||||||
if answer:lower() ~= "n" then
|
if answer:lower() ~= "n" then
|
||||||
saveLocationOK = true
|
saveLocationOK = true
|
||||||
end
|
end
|
||||||
|
|||||||
+12
-15
@@ -3,6 +3,7 @@ local fs = require("filesystem")
|
|||||||
local event = require("event")
|
local event = require("event")
|
||||||
local component = require("component")
|
local component = require("component")
|
||||||
local unicode = require("unicode")
|
local unicode = require("unicode")
|
||||||
|
local workingDirectory = require("shell").getWorkingDirectory()
|
||||||
local gpu = component.gpu
|
local gpu = component.gpu
|
||||||
local width, height = gpu.getResolution()
|
local width, height = gpu.getResolution()
|
||||||
local scrollPosX, scrollPosY = 1, 1
|
local scrollPosX, scrollPosY = 1, 1
|
||||||
@@ -15,9 +16,7 @@ local tab = " "
|
|||||||
--local ocelot = component.ocelot
|
--local ocelot = component.ocelot
|
||||||
|
|
||||||
local function rawset(x, y, text)
|
local function rawset(x, y, text)
|
||||||
termlib.cursorPosX = x
|
terminal.write("\x1b[".. tostring(y) .. ";" .. tostring(x) .. "H" .. text)
|
||||||
termlib.cursorPosY = y
|
|
||||||
termlib.write(text, false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local filestring, filepath, handle, data, tmpdata
|
local filestring, filepath, handle, data, tmpdata
|
||||||
@@ -25,7 +24,7 @@ if file then
|
|||||||
if file:sub(1, 1) == "/" then
|
if file:sub(1, 1) == "/" then
|
||||||
filepath = file
|
filepath = file
|
||||||
else
|
else
|
||||||
filepath = shell.workingDirectory .. file
|
filepath = workingDirectory .. file
|
||||||
end
|
end
|
||||||
handle, data, tmpdata = fs.open(filepath, "r"), "", nil
|
handle, data, tmpdata = fs.open(filepath, "r"), "", nil
|
||||||
if fs.exists(filepath) then
|
if fs.exists(filepath) then
|
||||||
@@ -44,7 +43,7 @@ if file then
|
|||||||
tmpdata = {data}
|
tmpdata = {data}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
filepath = shell.workingDirectory .. file
|
filepath = workingDirectory .. file
|
||||||
filestring = "[NEW FILE]"
|
filestring = "[NEW FILE]"
|
||||||
tmpdata = {""}
|
tmpdata = {""}
|
||||||
end
|
end
|
||||||
@@ -55,7 +54,7 @@ else
|
|||||||
end
|
end
|
||||||
local function render()
|
local function render()
|
||||||
gpu.setActiveBuffer(renderBuffer)
|
gpu.setActiveBuffer(renderBuffer)
|
||||||
clear()
|
terminal.clear()
|
||||||
--ocelot.log(tostring(scrollPosY))
|
--ocelot.log(tostring(scrollPosY))
|
||||||
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
|
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
|
||||||
if realCursorX < 1 then
|
if realCursorX < 1 then
|
||||||
@@ -152,7 +151,7 @@ local function processEvent(args)
|
|||||||
if args[1] == "key_down" then
|
if args[1] == "key_down" then
|
||||||
local keycode = args[4]
|
local keycode = args[4]
|
||||||
local key = keyboard.keys[keycode]
|
local key = keyboard.keys[keycode]
|
||||||
if keyboard.ctrlDown then
|
if keyboard.getCtrlDown() then
|
||||||
return false, false, key
|
return false, false, key
|
||||||
end
|
end
|
||||||
if key == "down" and cursorPosY < #tmpdata then
|
if key == "down" and cursorPosY < #tmpdata then
|
||||||
@@ -261,14 +260,13 @@ local function save()
|
|||||||
gpu.setBackground(0xFFFFFF)
|
gpu.setBackground(0xFFFFFF)
|
||||||
gpu.setForeground(0)
|
gpu.setForeground(0)
|
||||||
gpu.set(1, height - 1, string.rep(" ", width))
|
gpu.set(1, height - 1, string.rep(" ", width))
|
||||||
termlib.cursorPosX = 1
|
rawset(1, height - 1)
|
||||||
termlib.cursorPosY = height - 1
|
local savepath = terminal.read({prefix = "\27[107m\27[30mSave location: ", defaultText = filepath})
|
||||||
local savepath = read(nil, "\27[107m\27[30mSave location: ", filepath)
|
|
||||||
gpu.setBackground(0xFFFFFF)
|
gpu.setBackground(0xFFFFFF)
|
||||||
gpu.setForeground(0)
|
gpu.setForeground(0)
|
||||||
if fs.exists(savepath) then
|
if fs.exists(savepath) then
|
||||||
gpu.set(1, height - 1, string.rep(" ", width))
|
gpu.set(1, height - 1, string.rep(" ", width))
|
||||||
local answer = read(nil, "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] ")
|
local answer = terminal.read({prefix = "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] "})
|
||||||
if answer:lower() == "n" then
|
if answer:lower() == "n" then
|
||||||
gpu.setBackground(0xFFFFFF)
|
gpu.setBackground(0xFFFFFF)
|
||||||
gpu.setForeground(0)
|
gpu.setForeground(0)
|
||||||
@@ -301,15 +299,14 @@ while true do
|
|||||||
renderFlag, cursorRenderFlag, specialKey = processEvent(args)
|
renderFlag, cursorRenderFlag, specialKey = processEvent(args)
|
||||||
if specialKey == "x" then
|
if specialKey == "x" then
|
||||||
if changesMade then
|
if changesMade then
|
||||||
termlib.cursorPosX = 1
|
rawset(1, height - 1)
|
||||||
termlib.cursorPosY = height - 1
|
local response = terminal.read({prefix = "\27[107m\27[30mWould you like to save changes? [Y/n] "})
|
||||||
local response = read(nil, "\27[107m\27[30mWould you like to save changes? [Y/n] ")
|
|
||||||
if response:lower() ~= "n" then
|
if response:lower() ~= "n" then
|
||||||
save()
|
save()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
gpu.freeAllBuffers()
|
gpu.freeAllBuffers()
|
||||||
clear()
|
terminal.clear()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if specialKey == "s" then
|
if specialKey == "s" then
|
||||||
|
|||||||
+50
-54
@@ -1,70 +1,66 @@
|
|||||||
local component = require("component")
|
local component = require("component")
|
||||||
local computer = require("computer")
|
local computer = require("computer")
|
||||||
|
local filesystem = require("filesystem")
|
||||||
|
|
||||||
|
local function convert(value, fromUnit, toUnit)
|
||||||
|
local units = {B = 1, KiB = 1024, MiB = 1024^2, GiB = 1024^3}
|
||||||
|
return value * units[fromUnit] / units[toUnit]
|
||||||
|
end
|
||||||
|
|
||||||
local function printstat(text)
|
local function printstat(text)
|
||||||
terminal.cursorPosX = 35
|
terminal.write("\27[35G" .. text .. "\n")
|
||||||
terminal.write(text .. "\n", false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
terminal.write(_OSLOGO, false)
|
local logo = ""
|
||||||
terminal.cursorPosY = terminal.cursorPosY - 17
|
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
||||||
printstat("\27[92mOS\27[0m: ".._OSVERSION)
|
repeat
|
||||||
printstat("\27[92mArchitecture\27[0m: ".._VERSION)
|
tmpdata = handle:read(math.huge)
|
||||||
|
logo = logo .. (tmpdata or "")
|
||||||
|
until not tmpdata
|
||||||
|
handle:close()
|
||||||
|
|
||||||
|
terminal.write(logo)
|
||||||
|
|
||||||
|
terminal.write("\27[17A")
|
||||||
|
|
||||||
|
printstat("\27[92mOS\27[0m: " .. _OSVERSION)
|
||||||
|
printstat("\27[92mArchitecture\27[0m: " .. _VERSION)
|
||||||
|
|
||||||
local componentCounter = 0
|
local componentCounter = 0
|
||||||
for _, _ in component.list() do
|
for _ in component.list() do
|
||||||
componentCounter = componentCounter + 1
|
componentCounter = componentCounter + 1
|
||||||
end
|
end
|
||||||
printstat("\27[92mComponents\27[0m: "..tostring(componentCounter))
|
printstat("\27[92mComponents\27[0m: " .. tostring(componentCounter))
|
||||||
printstat("\27[92mCoroutines\27[0m: "..tostring(#tsched.getTasks()))
|
printstat("\27[92mCoroutines\27[0m: " .. tostring(#tsched.getTasks()))
|
||||||
printstat("\27[92mBattery\27[0m: "..tostring(math.floor(computer.energy() / computer.maxEnergy() * 1000 + 0.5) / 10).."%")
|
printstat("\27[92mBattery\27[0m: " .. tostring(math.floor(computer.energy() / computer.maxEnergy() * 1000 + 0.5) / 10) .. "%")
|
||||||
|
|
||||||
local totalMemory = computer.totalMemory()
|
local totalMemory = computer.totalMemory()
|
||||||
local usedMemory = computer.totalMemory() - computer.freeMemory()
|
local usedMemory = computer.totalMemory() - computer.freeMemory()
|
||||||
local totalMemoryString
|
|
||||||
if convert(totalMemory, "B", "GiB") >= 1 then
|
local function formatBytes(bytes)
|
||||||
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
|
if convert(bytes, "B", "GiB") >= 1 then
|
||||||
elseif convert(totalMemory, "B", "MiB") >= 1 then
|
return tostring(math.floor(convert(bytes, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
|
||||||
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
|
elseif convert(bytes, "B", "MiB") >= 1 then
|
||||||
elseif convert(totalMemory, "B", "KiB") >= 1 then
|
return tostring(math.floor(convert(bytes, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
|
||||||
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
|
elseif convert(bytes, "B", "KiB") >= 1 then
|
||||||
else
|
return tostring(math.floor(convert(bytes, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
|
||||||
totalMemoryString = tostring(totalMemory) .. " B"
|
else
|
||||||
|
return tostring(bytes) .. " B"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local usedMemoryString
|
|
||||||
if convert(usedMemory, "B", "GiB") >= 1 then
|
printstat("\27[92mMemory\27[0m: " .. formatBytes(usedMemory) .. " / " .. formatBytes(totalMemory))
|
||||||
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 totalDisk = component.invoke(computer.getBootAddress(), "spaceTotal")
|
||||||
local usedDisk = component.invoke(computer.getBootAddress(), "spaceUsed")
|
local usedDisk = component.invoke(computer.getBootAddress(), "spaceUsed")
|
||||||
local totalDiskString
|
|
||||||
if convert(totalDisk, "B", "GiB") >= 1 then
|
printstat("\27[92mDisk\27[0m: " .. formatBytes(usedDisk) .. " / " .. formatBytes(totalDisk))
|
||||||
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
|
|
||||||
elseif convert(totalDisk, "B", "MiB") >= 1 then
|
local gpuComponent = component.list("gpu")()
|
||||||
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
|
local width, height = component.invoke(gpuComponent, "getResolution")
|
||||||
elseif convert(totalDisk, "B", "KiB") >= 1 then
|
printstat("\27[92mResolution\27[0m: " .. tostring(width) .. "x" .. tostring(height) .. "\n")
|
||||||
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[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 ")
|
printstat("\27[100m \27[101m \27[102m \27[103m \27[104m \27[105m \27[106m \27[107m ")
|
||||||
terminal.cursorPosY = terminal.cursorPosY + 5
|
|
||||||
|
terminal.write("\27[5B\27[0m")
|
||||||
|
|||||||
+261
-31
@@ -1,38 +1,268 @@
|
|||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
local args = {...}
|
local shell = require("shell")
|
||||||
local command = args[1]
|
|
||||||
args = nil
|
local arg = ... or "default"
|
||||||
if not command then
|
local what = arg
|
||||||
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/default.txt", "r"), "", nil
|
|
||||||
repeat
|
local aliases = shell.getAliases()
|
||||||
tmpdata = handle:read(math.huge or math.maxinteger)
|
if aliases[what] then
|
||||||
data = data .. (tmpdata or "")
|
what = aliases[what]
|
||||||
until not tmpdata
|
end
|
||||||
print(data)
|
local path = "/halyde/apps/helpdb/" .. what
|
||||||
|
if not fs.exists(path) then
|
||||||
|
print("Could not find help file for: " .. arg .. ".")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if shell.aliases[command] then
|
if path == "/halyde/apps/helpdb/default" then
|
||||||
command = shell.aliases[command]
|
return shell.run("cat " .. path) -- smh
|
||||||
end
|
end
|
||||||
if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
|
local handle = fs.open(path, "r")
|
||||||
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/" .. command .. ".txt", "r"), "", nil
|
local data = {
|
||||||
repeat
|
command = "",
|
||||||
tmpdata = handle:read(math.huge or math.maxinteger)
|
usage = "",
|
||||||
data = data .. (tmpdata or "")
|
description = "",
|
||||||
until not tmpdata
|
args = {},
|
||||||
print(data)
|
examples = {}
|
||||||
local aliases = table.copy(shell.aliases)
|
}
|
||||||
if table.find(aliases, command) then
|
|
||||||
local aliasIndex = table.find(aliases, command)
|
while true do
|
||||||
local aliasString = "Aliases:\n " .. aliasIndex
|
local line = ""
|
||||||
aliases[aliasIndex] = nil
|
while true do
|
||||||
while table.find(aliases, command) do
|
local char = handle:read(1)
|
||||||
aliasIndex = table.find(aliases, command)
|
if not char then
|
||||||
aliasString = aliasString .. ", " .. aliasIndex
|
if line == "" then
|
||||||
aliases[aliasIndex] = nil
|
line = nil
|
||||||
|
break
|
||||||
end
|
end
|
||||||
print(aliasString)
|
break
|
||||||
|
end
|
||||||
|
if char == "\n" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if char == "\r" then
|
||||||
|
local next_char = handle:read(1)
|
||||||
|
if next_char and next_char == "\n" then
|
||||||
|
break
|
||||||
|
elseif next_char then
|
||||||
|
local pos = file:seek("cur")
|
||||||
|
if pos then
|
||||||
|
file:seek("set", pos - 1)
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
line = line .. char
|
||||||
|
end
|
||||||
|
if line == nil then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
line = line:match("^%s*(.-)%s*$")
|
||||||
|
if line then
|
||||||
|
local key, value = line:match("^(%w+)%s+(.*)$")
|
||||||
|
if not key then goto continue end
|
||||||
|
if key:lower() == "command" then
|
||||||
|
data.command = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower() == "usage" then
|
||||||
|
data.usage = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower() == "description" then
|
||||||
|
data.description = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower():match("^arg%d+$") then
|
||||||
|
local num = key:lower():match("^arg(%d+)$")
|
||||||
|
if not data.args[tonumber(num)] then data.args[tonumber(num)] = {} end
|
||||||
|
data.args[tonumber(num)].name = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower():match("^arg%d+description$") then
|
||||||
|
local num = key:lower():match("^arg(%d+)description$")
|
||||||
|
if not data.args[tonumber(num)] then data.args[tonumber(num)] = {} end
|
||||||
|
data.args[tonumber(num)].description = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower():match("^arg%d+sub%d+$") then
|
||||||
|
local main_num, sub_num = key:lower():match("^arg(%d+)sub(%d+)$")
|
||||||
|
if main_num and sub_num then
|
||||||
|
if not data.args[tonumber(main_num)] then data.args[tonumber(main_num)] = {} end
|
||||||
|
if not data.args[tonumber(main_num)].subflags then data.args[tonumber(main_num)].subflags = {} end
|
||||||
|
if not data.args[tonumber(main_num)].subflags[tonumber(sub_num)] then
|
||||||
|
data.args[tonumber(main_num)].subflags[tonumber(sub_num)] = {}
|
||||||
|
end
|
||||||
|
data.args[tonumber(main_num)].subflags[tonumber(sub_num)].name = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower():match("^arg%d+sub%d+description$") then
|
||||||
|
local main_num, sub_num = key:lower():match("^arg(%d+)sub(%d+)description$")
|
||||||
|
if main_num and sub_num then
|
||||||
|
if not data.args[tonumber(main_num)] then data.args[tonumber(main_num)] = {} end
|
||||||
|
if not data.args[tonumber(main_num)].subflags then data.args[tonumber(main_num)].subflags = {} end
|
||||||
|
if not data.args[tonumber(main_num)].subflags[tonumber(sub_num)] then
|
||||||
|
data.args[tonumber(main_num)].subflags[tonumber(sub_num)] = {}
|
||||||
|
end
|
||||||
|
data.args[tonumber(main_num)].subflags[tonumber(sub_num)].description = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower():match("^example%d+$") then
|
||||||
|
local num = key:lower():match("^example(%d+)$")
|
||||||
|
if not data.examples[tonumber(num)] then data.examples[tonumber(num)] = {} end
|
||||||
|
data.examples[tonumber(num)].name = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if key:lower():match("^example%d+description$") then
|
||||||
|
local num = key:lower():match("^example(%d+)description$")
|
||||||
|
if not data.examples[tonumber(num)] then data.examples[tonumber(num)] = {} end
|
||||||
|
data.examples[tonumber(num)].description = value
|
||||||
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
else
|
end
|
||||||
print("Could not find help file for: " .. command .. ".")
|
|
||||||
|
handle:close()
|
||||||
|
|
||||||
|
--print(require("serialize")(data, "\t"))
|
||||||
|
|
||||||
|
-- Halyde terminal doesn't support bold (CSI 1 m) but who cares
|
||||||
|
|
||||||
|
if data.command then
|
||||||
|
terminal.write("\27[1mUsage: \27[0m\n")
|
||||||
|
terminal.write(" \27[96m" .. data.command)
|
||||||
|
if data.usage then
|
||||||
|
terminal.write("\27[93m " .. data.usage)
|
||||||
|
end
|
||||||
|
terminal.write("\27[0m\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local width, height = terminal.getResolution()
|
||||||
|
|
||||||
|
local function wrap_text(text, indent)
|
||||||
|
if not text then return "" end
|
||||||
|
local words = {}
|
||||||
|
for word in text:gmatch("%S+") do
|
||||||
|
table.insert(words, word)
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
local current_line = ""
|
||||||
|
|
||||||
|
for i, word in ipairs(words) do
|
||||||
|
if #current_line + #word + 1 <= width * 0.66 - indent then
|
||||||
|
if current_line == "" then
|
||||||
|
current_line = word
|
||||||
|
else
|
||||||
|
current_line = current_line .. " " .. word
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(lines, current_line)
|
||||||
|
current_line = word
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if current_line ~= "" then
|
||||||
|
table.insert(lines, current_line)
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = {}
|
||||||
|
for i, line in ipairs(lines) do
|
||||||
|
if i == 1 then
|
||||||
|
table.insert(result, line)
|
||||||
|
else
|
||||||
|
table.insert(result, string.rep(" ", indent) .. line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(result, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.description then
|
||||||
|
terminal.write("\27[1mDescription:\27[0m\n")
|
||||||
|
terminal.write(" " .. wrap_text(data.description, 2))
|
||||||
|
terminal.write("\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
if #data.args > 0 then
|
||||||
|
terminal.write("\27[1mArguments:\27[0m\n")
|
||||||
|
local max_len = 0
|
||||||
|
for _, flag in ipairs(data.args) do
|
||||||
|
if flag.name then
|
||||||
|
max_len = math.max(max_len, #flag.name)
|
||||||
|
end
|
||||||
|
for _, subf in ipairs(flag.subflags or {}) do
|
||||||
|
if subf.name then
|
||||||
|
max_len = math.max(max_len, #subf.name + 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, flag in ipairs(data.args) do
|
||||||
|
terminal.write(" \27[93m" .. (flag.name or "") .. "\27[0m" .. string.rep(" ", max_len - (flag.name and #flag.name or 0) + 2) .. wrap_text(flag.description, 4 + max_len) .. "\n")
|
||||||
|
for _, subf in ipairs(flag.subflags or {}) do
|
||||||
|
terminal.write(" \27[92m" .. (subf.name or "") .. "\27[0m" .. string.rep(" ", max_len - (subf.name and #subf.name or 0)) .. wrap_text(subf.description, 4 + max_len) .. "\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
terminal.write("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function formatExampleName(name, utility)
|
||||||
|
if not name then return name end
|
||||||
|
|
||||||
|
local contains = false
|
||||||
|
if name:find(utility, 1, true) then
|
||||||
|
contains = true
|
||||||
|
else
|
||||||
|
for alias, cmd in pairs(aliases) do
|
||||||
|
if cmd == utility and name:find(alias, 1, true) then
|
||||||
|
contains = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not contains then
|
||||||
|
return "\27[92m" .. name
|
||||||
|
end
|
||||||
|
|
||||||
|
local formatted = name
|
||||||
|
formatted = formatted:gsub("(" .. utility .. ")", "\27[96m%1\27[92m")
|
||||||
|
for alias, cmd in pairs(aliases) do
|
||||||
|
if cmd == utility then
|
||||||
|
formatted = formatted:gsub("(" .. alias .. ")", "\27[96m%1\27[92m")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
end
|
||||||
|
|
||||||
|
if #data.examples > 0 then
|
||||||
|
terminal.write("\27[1mExamples:\27[0m\n")
|
||||||
|
local max_len = 0
|
||||||
|
for _, flag in ipairs(data.examples) do
|
||||||
|
max_len = math.max(max_len, #flag.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, flag in ipairs(data.examples) do
|
||||||
|
terminal.write(" " .. formatExampleName(flag.name, arg) .. "\27[0m" .. string.rep(" ", max_len - #flag.name + 2) .. wrap_text(flag.description, 4 + max_len) .. "\n")
|
||||||
|
end
|
||||||
|
terminal.write("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local first = true
|
||||||
|
for k, v in pairs(aliases) do
|
||||||
|
if v == arg then
|
||||||
|
if first then
|
||||||
|
terminal.write("\27[1mAliases:\27[0m\n ")
|
||||||
|
end
|
||||||
|
terminal.write("\27[96m" .. k)
|
||||||
|
if not first then
|
||||||
|
terminal.write("\27[0m, ")
|
||||||
|
end
|
||||||
|
first = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not first then
|
||||||
|
terminal.writec(0xa)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
COMMAND ag2
|
||||||
|
USAGE [COMMAND] [PACKAGES] [FLAGS]
|
||||||
|
DESCRIPTION Uses the Argentum 2 package manager.
|
||||||
|
ARG1 COMMAND
|
||||||
|
ARG1SUB1 install
|
||||||
|
ARG1SUB2 remove
|
||||||
|
ARG1SUB3 update
|
||||||
|
ARG1SUB4 list
|
||||||
|
ARG1SUB5 repo-list
|
||||||
|
ARG1SUB6 repo-add
|
||||||
|
ARG1SUB7 repo-remove
|
||||||
|
ARG1SUB8 info
|
||||||
|
ARG2 PACKAGES
|
||||||
|
ARG3 FLAGS
|
||||||
|
ARG3SUB1 -x, --exclude-deps
|
||||||
|
ARG3SUB2 -u, --update-repos
|
||||||
|
ARG3SUB3 -f, --force
|
||||||
|
ARG3SUB4 -c, --clean
|
||||||
|
ARG3SUB5 -s, --source [URL]
|
||||||
|
ARG3SUB6 -C, --cascade
|
||||||
|
ARG1DESCRIPTION Specifies the operation for Argentum 2 to do.
|
||||||
|
ARG1SUB1DESCRIPTION Installs packages.
|
||||||
|
ARG1SUB2DESCRIPTION Removes packages.
|
||||||
|
ARG1SUB3DESCRIPTION Updates packages.
|
||||||
|
ARG1SUB4DESCRIPTION Lists all available packages.
|
||||||
|
ARG1SUB5DESCRIPTION Lists all installed repositories.
|
||||||
|
ARG1SUB6DESCRIPTION Adds a custom repository.
|
||||||
|
ARG1SUB7DESCRIPTION Removes a repository.
|
||||||
|
ARG1SUB8DESCRIPTION Shows a packages version, description and other relevant information.
|
||||||
|
ARG2DESCRIPTION Packages to apply operations to.
|
||||||
|
ARG3DESCRIPTION These flags are available and can be inserted anywhere
|
||||||
|
ARG3SUB1DESCRIPTION Ignore dependencies. WARNING: Using this can and will leave you with broken packages. Use it at your own risk and only when truly necessary.
|
||||||
|
ARG3SUB2DESCRIPTION Update the list of repositories.
|
||||||
|
ARG3SUB3DESCRIPTION Force the operation, even if there are conflicts or unresolvable dependencies. WARNING: Using this can and will leave you with broken packages. Use it at your own risk and only when truly necessary.
|
||||||
|
ARG3SUB4DESCRIPTION Clean up now-unnecessary packages (previous dependencies).
|
||||||
|
ARG3SUB5DESCRIPTION Use a custom source for the operation.
|
||||||
|
ARG3SUB6DESCRIPTION When removing a package that other packages depend on, remove those packages too instead of aborting.
|
||||||
|
EXAMPLE1 ag2 install halyde
|
||||||
|
EXAMPLE2 ag2 list
|
||||||
|
EXAMPLE3 ag2 info halyde
|
||||||
|
EXAMPLE4 ag2 remove -x edit
|
||||||
|
EXAMPLE5 ag2 remove -c hal-draw
|
||||||
|
EXAMPLE1DESCRIPTION Installs the halyde package.
|
||||||
|
EXAMPLE2DESCRIPTION Lists all packages.
|
||||||
|
EXAMPLE3DESCRIPTION Shows information about the halyde package.
|
||||||
|
EXAMPLE4DESCRIPTION Removes edit, but does not remove any packages that depend on it.
|
||||||
|
EXAMPLE5DESCRIPTION Removes hal-draw and any dependencies that are no longer needed.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
COMMAND argentum
|
||||||
|
USAGE [COMMAND] [PACKAGES]
|
||||||
|
DESCRIPTION Uses the Argentum package manager.
|
||||||
|
ARG1 COMMAND
|
||||||
|
ARG1SUB1 install
|
||||||
|
ARG1SUB2 remove
|
||||||
|
ARG1SUB3 update
|
||||||
|
ARG1SUB4 list
|
||||||
|
ARG1SUB5 search
|
||||||
|
ARG1SUB6 info
|
||||||
|
ARG2 PACKAGES
|
||||||
|
ARG1DESCRIPTION Specifies the operation for Ag to do.
|
||||||
|
ARG1SUB1DESCRIPTION Installs packages.
|
||||||
|
ARG1SUB2DESCRIPTION Removes packages.
|
||||||
|
ARG1SUB3DESCRIPTION Updates packages.
|
||||||
|
ARG1SUB4DESCRIPTION Lists all available packages.
|
||||||
|
ARG1SUB5DESCRIPTION Searches all available packages.
|
||||||
|
ARG1SUB6DESCRIPTION Shows information on a specific package.
|
||||||
|
ARG2DESCRIPTION Packages to apply operations to.
|
||||||
|
EXAMPLE1 ag install hal-draw
|
||||||
|
EXAMPLE2 ag list
|
||||||
|
EXAMPLE3 ag info hal-draw
|
||||||
|
EXAMPLE4 ag update hal-draw
|
||||||
|
EXAMPLE5 ag update hal-draw
|
||||||
|
EXAMPLE1DESCRIPTION Installs the hal-draw package.
|
||||||
|
EXAMPLE2DESCRIPTION Lists all packages.
|
||||||
|
EXAMPLE3DESCRIPTION Shows information about hal-draw.
|
||||||
|
EXAMPLE4DESCRIPTION Updates the hal-draw package if it's not at the newest version.
|
||||||
|
EXAMPLE5DESCRIPTION Updates all packages.
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
Usage: argentum [COMMAND] [PACKAGES]
|
|
||||||
Uses the Argentum package manager.
|
|
||||||
|
|
||||||
COMMAND Specifies the operation for Ag to do.
|
|
||||||
install Installs packages.
|
|
||||||
remove Removes packages.
|
|
||||||
update Updates packages.
|
|
||||||
list Lists all available packages.
|
|
||||||
search Searches all available packages.
|
|
||||||
info Shows information on a specific package.
|
|
||||||
PACKAGES* Packages to apply operations to.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
ag install hal-draw Installs the hal-draw package.
|
|
||||||
ag list Lists all packages.
|
|
||||||
ag info hal-draw Shows information about hal-draw.
|
|
||||||
ag update hal-draw Updates the hal-draw package if it's not at the newest version.
|
|
||||||
ag update Updates all packages.
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
COMMAND beep
|
||||||
|
USAGE [FLAGS]
|
||||||
|
DESCRIPTION Make the computer beep.
|
||||||
|
ARG1 FLAGS
|
||||||
|
ARG1SUB1 -f, --frequency
|
||||||
|
ARG1SUB2 -t, --time
|
||||||
|
ARG1SUB1DESCRIPTION Specifies the frequency, in Hz. Defaults to 440Hz.
|
||||||
|
ARG1SUB2DESCRIPTION Specifies how long, in seconds, the computer should beep. Defaults to 0.1s.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
COMMAND boot
|
||||||
|
USAGE [ADDRESS] [FLAGS]
|
||||||
|
DESCRIPTION Restarts and automatically boots into any storage medium. Meant to be used for systems using a Lua BIOS EEPROM.
|
||||||
|
ARG1 ADDRESS
|
||||||
|
ARG1SUB1 hdd1
|
||||||
|
ARG1SUB2 hdd2
|
||||||
|
ARG1SUB3 floppy
|
||||||
|
ARG1SUB4
|
||||||
|
ARG2 FLAGS
|
||||||
|
ARG2SUB1 -f, --force
|
||||||
|
ARG1DESCRIPTION The storage medium to boot to.
|
||||||
|
ARG1SUB1DESCRIPTION The first hard drive inserted in the computer.
|
||||||
|
ARG1SUB2DESCRIPTION The second hard drive inserted in the computer.
|
||||||
|
ARG1SUB3DESCRIPTION The floppy disk that is inserted in the computer.
|
||||||
|
ARG1SUB4DESCRIPTION The ID of the component, abbreviated. Must have three or more characters.
|
||||||
|
ARG2DESCRIPTION Specifies extra options when executing the command.
|
||||||
|
ARG2SUB1DESCRIPTION Forces booting into the storage medium.
|
||||||
|
EXAMPLE1 boot hdd1
|
||||||
|
EXAMPLE2 boot hdd2
|
||||||
|
EXAMPLE3 boot floppy
|
||||||
|
EXAMPLE1DESCRIPTION Boot into the first hard drive inserted in the computer.
|
||||||
|
EXAMPLE2DESCRIPTION Boot into the second hard drive inserted in the computer.
|
||||||
|
EXAMPLE3DESCRIPTION Boot into the floppy disk inserted in the comuter.
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
Usage: boot [ADDRESS] [FLAGS]
|
|
||||||
Restarts and automatically boots into any storage medium. Meant to be used for systems using a Lua BIOS EEPROM.
|
|
||||||
|
|
||||||
ADDRESS The storage medium to boot to.
|
|
||||||
hdd1 The first hard drive inserted in the computer.
|
|
||||||
hdd2 The second hard drive inserted in the computer.
|
|
||||||
floppy The floppy disk that is inserted in the computer.
|
|
||||||
The ID of the component, abbreviated. Must have three or more characters.
|
|
||||||
FLAGS Specifies extra options when executing the command.
|
|
||||||
-f, --force Forces booting into the storage medium.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
boot hdd1 Boot into the first hard drive inserted in the computer.
|
|
||||||
boot hdd2 Boot into the second hard drive inserted in the computer.
|
|
||||||
boot floppy Boot into the floppy disk inserted in the comuter.
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
COMMAND cat
|
||||||
|
USAGE [FILES]...
|
||||||
|
DESCRIPTION Concatenates and prints a file.
|
||||||
|
ARG1 FILES
|
||||||
|
ARG1DESCRIPTION Specifies the paths to the files to print.
|
||||||
|
EXAMPLE1 cat /init.lua
|
||||||
|
EXAMPLE2 cat help.lua cat.lua
|
||||||
|
EXAMPLE1DESCRIPTION Concatenates and prints init.lua in the root directory.
|
||||||
|
EXAMPLE2DESCRIPTION Concatenates and prints help.lua and cat.lua in the current working directory.
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
Usage: cat [FILES]...
|
|
||||||
Concatenates and prints a file.
|
|
||||||
|
|
||||||
FILES Specifies the paths to the files to print.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
cat /init.lua Concatenates and prints init.lua in the root directory.
|
|
||||||
cat help.lua cat.lua Concatenates and prints help.lua and cat.lua in the current working directory.
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
COMMAND cd
|
||||||
|
USAGE [PATH]
|
||||||
|
DESCRIPTION Sets the shell working directory.
|
||||||
|
ARG1 PATH
|
||||||
|
ARG1DESCRIPTION Specifies the path to set the shell working directory to.
|
||||||
|
EXAMPLE1 cd /home/
|
||||||
|
EXAMPLE2 cd halyde
|
||||||
|
EXAMPLE3 cd ..
|
||||||
|
EXAMPLE4 ..
|
||||||
|
EXAMPLE1DESCRIPTION Sets the shell working directory to /home/.
|
||||||
|
EXAMPLE2DESCRIPTION Sets the shell working directory to a directory named "halyde" in the current working directory.
|
||||||
|
EXAMPLE3DESCRIPTION Sets the shell working directory back one directory.
|
||||||
|
EXAMPLE4DESCRIPTION Equivalent of "cd ..".
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
Usage: cd [PATH]
|
|
||||||
Sets the shell working directory.
|
|
||||||
|
|
||||||
PATH Specifies the path to set the shell working directory to.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
cd /home/ Sets the shell working directory to /home/.
|
|
||||||
cd halyde Sets the shell working directory to a directory named "halyde" in the current working directory.
|
|
||||||
cd .. Sets the shell working directory back one directory.
|
|
||||||
.. Equivalent of "cd ..".
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
COMMAND clear
|
||||||
|
DESCRIPTION Clears the screen.
|
||||||
|
EXAMPLE1 clear
|
||||||
|
EXAMPLE1DESCRIPTION Clears the screen.
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Usage: clear
|
|
||||||
Clears the screen.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
clear Clears the screen.
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
COMMAND cp
|
||||||
|
USAGE [SOURCES]... [DESTINATION]
|
||||||
|
DESCRIPTION Copy files and directories.
|
||||||
|
ARG1 SOURCES
|
||||||
|
ARG2 DESTINATION
|
||||||
|
ARG1DESCRIPTION Specifies the files and directories to be copied.
|
||||||
|
ARG2DESCRIPTION Specifies the path or a directory to copy to.
|
||||||
|
EXAMPLE1 cp /home/a.txt /b.txt
|
||||||
|
EXAMPLE2 cp c.lua /halyde/apps .
|
||||||
|
EXAMPLE1DESCRIPTION Copies the file at /home/a.txt to /b.txt.
|
||||||
|
EXAMPLE2DESCRIPTION Copies c.lua and /halyde/apps to the shell working directory.
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
Usage: cp [FLAGS] [SOURCE] [DESTINATION]
|
|
||||||
Copies a file.
|
|
||||||
|
|
||||||
FLAGS Specifies extra options when executing the command.
|
|
||||||
-o, --overwrite Allows any file that might be at the destination to be overwritten.
|
|
||||||
SOURCE Specifies the file to be copied.
|
|
||||||
DESTINATION Specifies the path to copy the file to.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
cp /home/a.txt /b.txt Copies the file at /home/a.txt to /b.txt.
|
|
||||||
cp -o c.lua d.txt Copies the file c.lua to another file called d.txt in the shell working directory, overwriting any file that might be there.
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
All default Halyde shell commands:
|
||||||
|
argentum Uses the Argentum package manager.
|
||||||
|
boot Boots to another OS.
|
||||||
|
cat Concatenates and prints a file.
|
||||||
|
cd Changes directory.
|
||||||
|
clear Clears the screen.
|
||||||
|
cp Copies a file.
|
||||||
|
download Downloads a file from the internet.
|
||||||
|
echo Prints a message.
|
||||||
|
edit Opens the text editor.
|
||||||
|
fetch Displays system information.
|
||||||
|
help Shows this.
|
||||||
|
label Labels storage devices and EEPROMS.
|
||||||
|
ls Lists files.
|
||||||
|
lscor Lists coroutines.
|
||||||
|
lua Starts the Lua shell.
|
||||||
|
mkdir Makes a directory.
|
||||||
|
mv Moves/renames a file.
|
||||||
|
reboot Reboots the computer.
|
||||||
|
resolution Sets the resolution.
|
||||||
|
rm Deletes a file.
|
||||||
|
shutdown Shuts down the computer.
|
||||||
|
|
||||||
|
You can get additional information on any app or command by running:
|
||||||
|
help [COMMAND]
|
||||||
|
|
||||||
|
In the help documentation, an asterisk (*) next to an argument means it is optional.
|
||||||
|
This is excluding flags, which are all optional.
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
All default Halyde shell commands:
|
|
||||||
argentum Uses the Argentum package manager.
|
|
||||||
cat Concatenates and prints a file.
|
|
||||||
cd Changes directory.
|
|
||||||
clear Clears the screen.
|
|
||||||
cp Copies a file.
|
|
||||||
download Downloads a file from the internet.
|
|
||||||
echo Prints a message.
|
|
||||||
edit Opens the text editor.
|
|
||||||
fetch Displays system information.
|
|
||||||
help Shows this.
|
|
||||||
ls Lists files.
|
|
||||||
lscor Lists coroutines.
|
|
||||||
lua Starts the Lua shell.
|
|
||||||
mkdir Makes a directory.
|
|
||||||
mv Moves/renames a file.
|
|
||||||
reboot Reboots the computer.
|
|
||||||
rm Deletes a file.
|
|
||||||
shutdown Shuts down the computer.
|
|
||||||
|
|
||||||
You can get additional information on any app or command by running:
|
|
||||||
help [COMMAND]
|
|
||||||
|
|
||||||
In the help documentation, an asterisk (*) next to an argument means it is optional.
|
|
||||||
This is excluding flags, which are all optional.
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
COMMAND download
|
||||||
|
USAGE [URL]
|
||||||
|
DESCRIPTION Downloads a file from the internet.
|
||||||
|
ARG1 URL
|
||||||
|
ARG1DESCRIPTION Specifies the URL from which to download the file from.
|
||||||
|
EXAMPLE1 download https://github.com/
|
||||||
|
EXAMPLE1DESCRIPTION Downloads github.com.
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
Usage: download [URL]
|
|
||||||
Downloads a file from the internet.
|
|
||||||
|
|
||||||
URL Specifies the URL from which to download the file from.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
download https://github.com/ Downloads github.com.
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
COMMAND echo
|
||||||
|
USAGE [TEXT]...
|
||||||
|
DESCRIPTION Concatenates and prints text to the standard output.
|
||||||
|
ARG1 TEXT
|
||||||
|
ARG1DESCRIPTION Text to print.
|
||||||
|
EXAMPLE1 echo test
|
||||||
|
EXAMPLE2 echo Hello World!
|
||||||
|
EXAMPLE1DESCRIPTION Prints "test" to the standard output.
|
||||||
|
EXAMPLE2DESCRIPTION Prints "Hello World!" to the standard output.
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
Usage: echo [TEXT]...
|
|
||||||
Concatenates and prints text to the terminal.
|
|
||||||
|
|
||||||
TEXT Text to print.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
echo test Prints "test" to the terminal.
|
|
||||||
echo Hello World! Prints "Hello World!" to the terminal.
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
COMMAND edit
|
||||||
|
USAGE [PATH]
|
||||||
|
DESCRIPTION Opens a file with the text editor, or a new blank file if not specified.
|
||||||
|
ARG1 PATH
|
||||||
|
ARG1DESCRIPTION Specifies the file to be opened.
|
||||||
|
EXAMPLE1 edit
|
||||||
|
EXAMPLE2 edit /LICENSE
|
||||||
|
EXAMPLE1DESCRIPTION Opens a new blank file in the text editor.
|
||||||
|
EXAMPLE2DESCRIPTION Opens /LICENSE in the text editor.
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
Usage: edit [PATH]
|
|
||||||
Opens a file with the text editor, or a new blank file if not specified.
|
|
||||||
|
|
||||||
PATH* Specifies the file to be opened.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
edit Opens a new blank file in the text editor.
|
|
||||||
edit /LICENSE Opens /LICENSE in the text editor.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
COMMAND fetch
|
||||||
|
DESCRIPTION Displays system information including OS version, Lua version, memory, etc.
|
||||||
|
EXAMPLE1 fetch
|
||||||
|
EXAMPLE1DESCRIPTION Displays system information.
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Usage: fetch
|
|
||||||
Displays system information including OS version, Lua version, memory, etc.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
fetch Displays system information.
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
COMMAND help
|
||||||
|
USAGE [COMMAND]
|
||||||
|
DESCRIPTION Displays info on the command specified, or a list of commands if one is not specified.
|
||||||
|
ARG1 COMMAND
|
||||||
|
ARG1DESCRIPTION Command to display information on.
|
||||||
|
EXAMPLE1 help
|
||||||
|
EXAMPLE2 help cp
|
||||||
|
EXAMPLE1DESCRIPTION Displays a list of all default commands available.
|
||||||
|
EXAMPLE2DESCRIPTION Displays information about the cp command.
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
Usage: help [COMMAND]
|
|
||||||
Displays info on the command specified, or a list of commands if one is not specified.
|
|
||||||
|
|
||||||
COMMAND* Command to display information on.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
help Displays a list of all default commands available.
|
|
||||||
help cp Displays information about the cp command.
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
COMMAND label
|
||||||
|
USAGE [ADDRESS] [LABEL]
|
||||||
|
DESCRIPTION Get or set a label of a component that supports labelling.
|
||||||
|
ARG1 ADDRESS
|
||||||
|
ARG1SUB1 eeprom
|
||||||
|
ARG1SUB2 halyde
|
||||||
|
ARG1SUB3 slotN
|
||||||
|
ARG1SUB4 #N
|
||||||
|
ARG2 LABEL
|
||||||
|
ARG1DESCRIPTION The component to use for getting or setting the label.
|
||||||
|
ARG1SUB1DESCRIPTION The computer's EEPROM.
|
||||||
|
ARG1SUB2DESCRIPTION The drive where the Halyde installation resides in.
|
||||||
|
ARG1SUB3DESCRIPTION The slot number of the drive, in top-to-bottom order (range 7-9)
|
||||||
|
ARG1SUB4DESCRIPTION The slot number of the drive, in drive space (range 1-3)
|
||||||
|
ARG1SUB5DESCRIPTION The ID of the component, abbreviated. Must have three or more characters.
|
||||||
|
ARG2DESCRIPTION The label to set the component to. If not found, the current label will be printed out.
|
||||||
|
EXAMPLE1 label #3
|
||||||
|
EXAMPLE2 label eeprom
|
||||||
|
EXAMPLE3 label slot8 Storage
|
||||||
|
EXAMPLE4 label halyde Halyde
|
||||||
|
EXAMPLE1DESCRIPTION Get the label of the third drive in the computer.
|
||||||
|
EXAMPLE2DESCRIPTION Get the label of the EEPROM inserted in the computer.
|
||||||
|
EXAMPLE3DESCRIPTION Set the drive at slot 8 to have the label "Storage"
|
||||||
|
EXAMPLE4DESCRIPTION Set the label of the Halyde installation to "Halyde"
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
Usage: label [ADDRESS] [LABEL]
|
|
||||||
Get or set a label of a component that supports labelling.
|
|
||||||
|
|
||||||
ADDRESS The component to use for getting or setting the label.
|
|
||||||
eeprom The computer's EEPROM.
|
|
||||||
halyde The drive where the Halyde installation resides in.
|
|
||||||
slotN The slot number of the drive, in top-to-bottom order (range 7-9)
|
|
||||||
#N The slot number of the drive, in drive space (range 1-3)
|
|
||||||
The ID of the component, abbreviated. Must have three or more characters.
|
|
||||||
LABEL* The label to set the component to. If not found, the current label will be printed out.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
label #3 Get the label of the third drive in the computer.
|
|
||||||
label eeprom Get the label of the EEPROM inserted in the computer.
|
|
||||||
label slot8 Storage Set the drive at slot 8 to have the label "Storage"
|
|
||||||
label halyde Halyde Set the label of the Halyde installation to "Halyde"
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
COMMAND log
|
||||||
|
USAGE [OPERATION] [ARGS]
|
||||||
|
DESCRIPTION Tool to manage system logs.
|
||||||
|
ARG1 OPERATION
|
||||||
|
ARG1SUB1 view [LOG]
|
||||||
|
ARG1SUB2 list
|
||||||
|
ARG1SUB3 clear [LOG]
|
||||||
|
ARG1SUB4 info/warn/error [LOG] [TEXT]
|
||||||
|
ARG2 ARGS
|
||||||
|
ARG1DESCRIPTION Operation to do with the system logs.
|
||||||
|
ARG1SUB1DESCRIPTION View a log file.
|
||||||
|
ARG1SUB2DESCRIPTION List all logs.
|
||||||
|
ARG1SUB3DESCRIPTION Clear a log file, or all if none specified.
|
||||||
|
ARG1SUB4DESCRIPTION Create a log entry for the specified log at the specified log level.
|
||||||
|
ARG2DESCRIPTION Arguments (specified under OPERATION)
|
||||||
|
EXAMPLE1 log view example
|
||||||
|
EXAMPLE2 log list
|
||||||
|
EXAMPLE3 log clear example
|
||||||
|
EXAMPLE4 log info example This is an example.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
COMMAND ls
|
||||||
|
USAGE [PATH]...
|
||||||
|
DESCRIPTION Lists all files and directories in the specified path, or in the shell working directory if the path isn't specified. Directories are shown in [93myellow[0m, executable files are shown in [92mgreen[0m, and other files are shown in white.
|
||||||
|
ARG1 PATH
|
||||||
|
ARG1DESCRIPTION Path to the directories to list files and subdirectories from.
|
||||||
|
EXAMPLE1 ls
|
||||||
|
EXAMPLE2 ls /halyde
|
||||||
|
EXAMPLE3 ls apps
|
||||||
|
EXAMPLE1DESCRIPTION Lists all files and directories from the current shell working directory.
|
||||||
|
EXAMPLE2DESCRIPTION Lists all files and directories from /halyde.
|
||||||
|
EXAMPLE3DESCRIPTION Lists all files and directories from the apps directory in the shell working directory.
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
Usage: ls [PATH]
|
|
||||||
Lists all files and directories in the specified path, or in the shell working directory if the path isn't specified.
|
|
||||||
Directories are shown in [93myellow[0m, executable files are shown in [92mgreen[0m, and other files are shown in white.
|
|
||||||
|
|
||||||
PATH* Path to the folder to list files and directories from.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
ls Lists all files and directories from the current shell working directory.
|
|
||||||
ls /halyde Lists all files and directories from /halyde.
|
|
||||||
ls apps Lists all files and directories from the apps directory in the shell working directory.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
COMMAND lscor
|
||||||
|
DESCRIPTION Lists every active coroutine by ID and name.
|
||||||
|
EXAMPLE1 lscor
|
||||||
|
EXAMPLE1DESCRIPTION Lists every active coroutine by ID and name.
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Usage: lscor
|
|
||||||
Lists every active coroutine by ID and name.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
lscor Lists every active coroutine by ID and name.
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
COMMAND lsdrv
|
||||||
|
USAGE [FLAGS]
|
||||||
|
DESCRIPTION Shows all drives that are inserted into the computer.
|
||||||
|
ARG1 FLAGS
|
||||||
|
ARG1SUB1 -a, --all
|
||||||
|
ARG1SUB2 -o, --output [COLS]
|
||||||
|
ARG1SUB3 -s, --show [EXPR]
|
||||||
|
ARG1SUB4 -S, --sort [EXPR]
|
||||||
|
ARG1SUB5 EXPR
|
||||||
|
ARG2 PACKAGES
|
||||||
|
ARG1DESCRIPTION Specifies extra options when executing the command.
|
||||||
|
ARG1SUB1DESCRIPTION Shows every column and every component. Acts the same as '-o all -s all'. Possible columns are: "slot", "capacity", "managed", "readOnly", "id", "mount", "bootable", and "label". If the list of columns start with a "+", the default columns will appear first. Default columns are slots, capacity, the entire ID, the mount point, and the drive label.
|
||||||
|
ARG1SUB2DESCRIPTION Specifies the columns to output in the output table.
|
||||||
|
ARG1SUB3DESCRIPTION Only list drives when the expression returns 'true'.
|
||||||
|
ARG1SUB4DESCRIPTION Sort the output by an expression that returns a number. The higher the number, the lower the drive is displayed, and vice-versa.
|
||||||
|
ARG1SUB5DESCRIPTION An expression in Lua, for filtering or sorting output. If this expression contains spaces, make sure to put quotation marks on them!
|
||||||
|
ARG1SUB6DESCRIPTION Built-in variables are: "component", "computer", "type", "id", "readonly", "capacity", "managed", "eeprom", "halyde", "tmp", "proxy", "slot", and "all" (true).
|
||||||
|
EXAMPLE1 lsdrv
|
||||||
|
EXAMPLE2 lsdrv -a
|
||||||
|
EXAMPLE3 lsdrv -o +bootable
|
||||||
|
EXAMPLE4 lsdrv -o slot,label -s halyde
|
||||||
|
EXAMPLE5 lsdrv -o mount,capacity,label -s "not halyde"
|
||||||
|
EXAMPLE6 lsdrv -s type=='filesystem'
|
||||||
|
EXAMPLE7 lsdrv -s slot==1
|
||||||
|
EXAMPLE8 lsdrv -S capacity
|
||||||
|
EXAMPLE9 lsdrv -S -capacity
|
||||||
|
EXAMPLE10 lsdrv -o +managed -S managed
|
||||||
|
EXAMPLE1DESCRIPTION Show regular drives, with the default columns.
|
||||||
|
EXAMPLE2DESCRIPTION Show all storage components, with every column.
|
||||||
|
EXAMPLE3DESCRIPTION Show drives, with an added "bootable" category.
|
||||||
|
EXAMPLE4DESCRIPTION Show the slot and the label of the drive where Halyde is installed.
|
||||||
|
EXAMPLE5DESCRIPTION Show the mount points, capacities and labels of all drives other than Halyde.
|
||||||
|
EXAMPLE6DESCRIPTION Only show managed drives.
|
||||||
|
EXAMPLE7DESCRIPTION Show all drives that aren't physical (Virtual components, tmpfs)
|
||||||
|
EXAMPLE8DESCRIPTION Sort the drives by capacity, in ascending order.
|
||||||
|
EXAMPLE9DESCRIPTION Sort the drives by capacity, in descending order.
|
||||||
|
EXAMPLE10DESCRIPTION Show managed drives first, then unmanaged drives second, with an extra "managed" column.
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
Usage: lsdrv [FLAGS]
|
|
||||||
Shows all drives that are inserted into the computer.
|
|
||||||
|
|
||||||
FLAGS Specifies extra options when executing the command.
|
|
||||||
-a, --all Shows every column and every component. Acts the same as '-o all -s all'.
|
|
||||||
-o, --output [COLS] Specifies the columns to output in the output table.
|
|
||||||
Possible columns are: "slot", "capacity", "managed", "readOnly", "id", "mount", "bootable", and "label".
|
|
||||||
If the list of columns start with a "+", the default columns will appear first.
|
|
||||||
Default columns are slots, capacity, the entire ID, the mount point, and the drive label.
|
|
||||||
-s, --show [EXPR] Only list drives when the expression returns 'true'.
|
|
||||||
-S, --sort [EXPR] Sort the output by an expression that returns a number.
|
|
||||||
The higher the number, the lower the drive is displayed, and vice-versa.
|
|
||||||
EXPR An expression in Lua, for filtering or sorting output.
|
|
||||||
If this expression contains spaces, make sure to put quotation marks on them!
|
|
||||||
Built-in variables are: "component", "computer", "type", "id", "readonly", "capacity", "managed", "eeprom", "halyde", "tmp", "proxy", "slot", and "all" (true).
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
lsblk Show regular drives, with the default columns.
|
|
||||||
lsblk -a Show all storage components, with every column.
|
|
||||||
lsblk -o +bootable Show drives, with an added "bootable" category.
|
|
||||||
lsblk -o slot,label -s halyde Show the slot and the label of the drive where Halyde is installed.
|
|
||||||
lsblk -o mount,capacity,label -s "not halyde" Show the mount points, capacities and labels of all drives other than Halyde.
|
|
||||||
lsblk -s type=='filesystem' Only show managed drives.
|
|
||||||
lsblk -s slot==1 Show all drives that aren't physical (Virtual components, tmpfs)
|
|
||||||
lsblk -S capacity Sort the drives by capacity, in ascending order.
|
|
||||||
lsblk -S -capacity Sort the drives by capacity, in descending order.
|
|
||||||
lsblk -o +managed -S managed Show managed drives first, then unmanaged drives second, with an extra "managed" column.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
COMMAND lua
|
||||||
|
DESCRIPTION Starts the Lua shell, where you can type commands to interpret them in real time.
|
||||||
|
EXAMPLE1 lua
|
||||||
|
EXAMPLE1DESCRIPTION Starts the Lua shell.
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Usage: lua
|
|
||||||
Starts the Lua shell, where you can type commands to interpret them in real time.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
lua Starts the Lua shell.
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
COMMAND maindrv
|
||||||
|
DESCRIPTION Shows the entire ID of the drive where Halyde is installed to.
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Usage: maindrv
|
|
||||||
Shows the entire ID of the drive where Halyde is installed to.
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
COMMAND mkdir
|
||||||
|
USAGE [PATH]...
|
||||||
|
DESCRIPTION Makes a directory.
|
||||||
|
ARG1 PATH
|
||||||
|
ARG1DESCRIPTION Specifies the path to create the directory in.
|
||||||
|
EXAMPLE1 mkdir a
|
||||||
|
EXAMPLE1DESCRIPTION Creates a directory named a in the current shell working directory.
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
Usage: mkdir [PATH]
|
|
||||||
Makes a directory.
|
|
||||||
|
|
||||||
PATH Specifies the path to create the directory in.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
mkdir a Creates a directory named a in the current shell working directory.
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
COMMAND mv
|
||||||
|
USAGE [SOURCE].. [DESTINATION]
|
||||||
|
DESCRIPTION Moves/renames a file.
|
||||||
|
ARG1 SOURCE
|
||||||
|
ARG2 DESTINATION
|
||||||
|
ARG1DESCRIPTION Specifies the files and directories to be moved.
|
||||||
|
ARG2DESCRIPTION Specifies the path or a directory to copy to.
|
||||||
|
EXAMPLE1 mv /home/a.txt /b.txt
|
||||||
|
EXAMPLE2 mv ../c.lua /halyde/apps .
|
||||||
|
EXAMPLE1DESCRIPTION Moves the file at /home/a.txt to /b.txt.
|
||||||
|
EXAMPLE2DESCRIPTION Moves c.lua from a subdirectory and /halyde/apps to the shell working directory.
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
Usage: mv [FLAGS] [SOURCE] [DESTINATION]
|
|
||||||
Moves/renames a file.
|
|
||||||
|
|
||||||
FLAGS Specifies extra options when executing the command.
|
|
||||||
-o, --overwrite Allows any file that might be at the destination to be overwritten.
|
|
||||||
SOURCE Specifies the file to be moved/renamed.
|
|
||||||
DESTINATION Specifies the path/filename to move/rename the file to.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
mv /home/a.txt /b.txt Moves the file at /home/a.txt to /b.txt.
|
|
||||||
mv -o c.lua d.txt Renames the file c.lua to another file called d.txt in the shell working directory, overwriting any file that might be there.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
COMMAND reboot
|
||||||
|
DESCRIPTION Reboots the computer.
|
||||||
|
EXAMPLE1 reboot
|
||||||
|
EXAMPLE1DESCRIPTION Reboots the computer.
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Usage: reboot
|
|
||||||
Reboots the computer.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
reboot Reboots the computer.
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
COMMAND res
|
||||||
|
USAGE [FLAGS]
|
||||||
|
DESCRIPTION Gets or sets the current resolution.
|
||||||
|
ARG1 FLAGS
|
||||||
|
ARG1SUB1 [no flags]
|
||||||
|
ARG1SUB2 -x [number]
|
||||||
|
ARG1SUB3 -y [number]
|
||||||
|
ARG1DESCRIPTION Specifies extra options when executing the command.
|
||||||
|
ARG1SUB1DESCRIPTION Displays the current and maximum resolution.
|
||||||
|
ARG1SUB2DESCRIPTION Displays the current and maximum resolution on the x-axis. A new x-axis resolution can be specified as a number.
|
||||||
|
ARG1SUB3DESCRIPTION Displays the current and maximum resolution on the y-axis. A new y-axis resolution can be specified as a number.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
COMMAND rm
|
||||||
|
USAGE [PATH]...
|
||||||
|
DESCRIPTION Removes files and directories.
|
||||||
|
ARG1 PATH
|
||||||
|
ARG1DESCRIPTION Specifies the files and directories to be moved/renamed.
|
||||||
|
EXAMPLE1 rm a.txt
|
||||||
|
EXAMPLE1DESCRIPTION Removes a.txt in the current shell working directory.
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
Usage: rm [PATH]
|
|
||||||
Removes files and directories.
|
|
||||||
|
|
||||||
PATH Specifies the file to be moved/renamed.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
rm a.txt Removes a.txt in the current shell working directory.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
COMMAND shutdown
|
||||||
|
DESCRIPTION Shuts down the computer.
|
||||||
|
EXAMPLE1 shutdown
|
||||||
|
EXAMPLE1DESCRIPTION Shuts down the computer.
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Usage: shutdown
|
|
||||||
Shuts down the computer.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
shutdown Shuts down the computer.
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
COMMAND touch
|
||||||
|
USAGE [FILE]...
|
||||||
|
DESCRIPTION Create an empty file.
|
||||||
|
ARG1 FILE
|
||||||
|
ARG1DESCRIPTION The path of the files to create.
|
||||||
+11
-11
@@ -1,9 +1,9 @@
|
|||||||
local component = require("component")
|
local component = require("component")
|
||||||
local computer = require("computer")
|
local computer = require("computer")
|
||||||
local args = {...}
|
local args = {...}
|
||||||
if not args then return print("\x1b[91mCannot get arguments.") end
|
if not args then return print("\x1b[91mCannot get arguments.\x1b[0m") end
|
||||||
if not args[1] then
|
if not args[1] then
|
||||||
return shell.run("help label")
|
return require("shell").run("help label")
|
||||||
end
|
end
|
||||||
local inputID = args[1]
|
local inputID = args[1]
|
||||||
local comp
|
local comp
|
||||||
@@ -29,27 +29,27 @@ elseif inputID:sub(1,1)=="#" and tonumber(inputID:sub(2)) then
|
|||||||
componentFromSlot(slotNum)
|
componentFromSlot(slotNum)
|
||||||
elseif #inputID>=3 then
|
elseif #inputID>=3 then
|
||||||
local fullID = component.get(inputID)
|
local fullID = component.get(inputID)
|
||||||
if not fullID then return print("\x1b[91mCould not find entire component ID from \""..inputID.."\".") end
|
if not fullID then return print("\x1b[91mCould not find entire component ID from \""..inputID.."\".\x1b[0m") end
|
||||||
comp = component.proxy(fullID)
|
comp = component.proxy(fullID)
|
||||||
else
|
else
|
||||||
print("\x1b[91mAddress must have atleast 3 characters")
|
print("\x1b[91mAddress must have atleast 3 characters\x1b[0m")
|
||||||
return shell.run("help label")
|
return require("shell").run("help label")
|
||||||
end
|
end
|
||||||
if not comp then
|
if not comp then
|
||||||
return print("\x1b[91mCould not find component from \""..inputID.."\".")
|
return print("\x1b[91mCould not find component from \""..inputID.."\".\x1b[0m")
|
||||||
end
|
end
|
||||||
local compID = comp.address
|
local compID = comp.address
|
||||||
|
|
||||||
local function formatID(id)
|
local function formatID(id)
|
||||||
return id:sub(1,8).."\x1b[37m"..id:sub(9).."\x1b[39m"
|
return id:sub(1,8).."\x1b[37m"..id:sub(9).."\x1b[0m"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function unsupported(act)
|
local function unsupported(act)
|
||||||
print("This \x1b[92m"..(comp.type or "unknown").."\x1b[39m component doesn't support "..act.." labels.\nID: "..formatID(compID))
|
print("This \x1b[92m"..(comp.type or "unknown").."\x1b[0m component doesn't support "..act.." labels.\nID: "..formatID(compID).."\x1b[0m")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function compError(act,reason)
|
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)
|
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.."\x1b[0m")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function formatLabel(label)
|
local function formatLabel(label)
|
||||||
@@ -67,7 +67,7 @@ if type(args[2])~="string" then
|
|||||||
label = comp.getLabel()
|
label = comp.getLabel()
|
||||||
end)
|
end)
|
||||||
if success then
|
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")
|
print("Label of "..formatID(compID)..((comp.type and comp.type~="filesystem") and " ("..comp.type..")" or "")..":\n \x1b[92m"..formatLabel(label).."\x1b[0m")
|
||||||
else
|
else
|
||||||
compError("getting",reason)
|
compError("getting",reason)
|
||||||
end
|
end
|
||||||
@@ -85,7 +85,7 @@ else
|
|||||||
label = comp.setLabel(newLabel)
|
label = comp.setLabel(newLabel)
|
||||||
end)
|
end)
|
||||||
if success then
|
if success then
|
||||||
print("Successfully set label of "..formatID(compID)..(comp.type and " ("..comp.type..")" or "").." to:\n \x1b[92m"..formatLabel(label).."\x1b[39m")
|
print("Successfully set label of "..formatID(compID)..(comp.type and " ("..comp.type..")" or "").." to:\n \x1b[92m"..formatLabel(label).."\x1b[0m")
|
||||||
else
|
else
|
||||||
compError("setting",reason)
|
compError("setting",reason)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
local log = require("log")
|
||||||
|
local shell = require("shell")
|
||||||
|
local fs = require("filesystem")
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
if #args == 0 then
|
||||||
|
shell.run("help log")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local function viewlog(logname)
|
||||||
|
local logpath = "/halyde/logs/" .. logname .. ".log"
|
||||||
|
if not fs.exists(logpath) then
|
||||||
|
print("Log not found.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local handle = fs.open(logpath)
|
||||||
|
local entry = ""
|
||||||
|
local byte
|
||||||
|
while true do
|
||||||
|
byte = handle:read(1)
|
||||||
|
if not byte then return end
|
||||||
|
if string.byte(byte) == 0x0a then --check for newline
|
||||||
|
if string.byte(string.sub(entry, -1, -1)) == 0x0d then --failsafe in case line endings are CRLF
|
||||||
|
entry = string.sub(entry, 1, -2)
|
||||||
|
else
|
||||||
|
entry = string.sub(entry, 1, -1)
|
||||||
|
end
|
||||||
|
if entry:sub(1, 4) == "WARN" then
|
||||||
|
print("\x1b[93m" .. entry .. "\x1b[0m")
|
||||||
|
elseif entry:sub(1, 5) == "ERROR" then
|
||||||
|
print("\x1b[91m" .. entry .. "\x1b[0m")
|
||||||
|
else
|
||||||
|
print(entry)
|
||||||
|
end
|
||||||
|
entry = ""
|
||||||
|
else
|
||||||
|
entry = entry .. byte
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function listlogs()
|
||||||
|
local files = fs.list("/halyde/logs")
|
||||||
|
local logs = {}
|
||||||
|
local j = 1
|
||||||
|
for i in ipairs(files) do
|
||||||
|
if not(string.sub(files[i], -1, -1) == "/") and string.sub(files[i], -4, -1) == ".log" then
|
||||||
|
logs[j] = string.sub(files[i], 1, -5)
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return logs
|
||||||
|
end
|
||||||
|
|
||||||
|
local function listlogs2()
|
||||||
|
local logs = listlogs()
|
||||||
|
print("Found \x1b[93m" .. #logs .. "\x1b[0m logs.")
|
||||||
|
for i in ipairs(logs) do
|
||||||
|
if i == #logs then
|
||||||
|
print("\x1b[93m└ \x1b[0m" .. logs[i] .. "\x1b[90m.log\x1b[0m")
|
||||||
|
else
|
||||||
|
print("\x1b[93m├ \x1b[0m" .. logs[i] .. "\x1b[90m.log\x1b[0m")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clearlog(logname)
|
||||||
|
if logname then
|
||||||
|
local logpath = "/halyde/logs/" .. logname .. ".log"
|
||||||
|
if not fs.exists(logpath) then
|
||||||
|
print("Log file not found.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local success, err = fs.remove(logpath)
|
||||||
|
if not success then
|
||||||
|
print("Failed to remove log file: " .. err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local logs = listlogs()
|
||||||
|
local j
|
||||||
|
for i in ipairs(logs) do
|
||||||
|
local success, err = fs.remove("/halyde/logs/" .. logs[i] .. ".log")
|
||||||
|
if not success then
|
||||||
|
print("Failed to remove log " .. logs[i] .. ": " .. err)
|
||||||
|
print("Removed" .. i - 1 .. "logs.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
j = i
|
||||||
|
end
|
||||||
|
print("Removed " .. j .. " log(s) successfully.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if args[1] == "view" then
|
||||||
|
viewlog(args[2])
|
||||||
|
elseif args[1] == "list" then
|
||||||
|
listlogs2()
|
||||||
|
elseif args[1] == "clear" then
|
||||||
|
clearlog(args[2])
|
||||||
|
elseif args[1] == "info" or args[1] == "warn" or args[1] == "error" then
|
||||||
|
local loglevel = args[1]
|
||||||
|
local logname = args[2]
|
||||||
|
local logtext = args[3]
|
||||||
|
for i = 4, #args do
|
||||||
|
logtext = logtext .. " " .. args[i]
|
||||||
|
end
|
||||||
|
log[logname][loglevel](logtext)
|
||||||
|
end
|
||||||
+48
-60
@@ -1,70 +1,58 @@
|
|||||||
local args = {...}
|
|
||||||
local target = args[1]
|
|
||||||
args = nil
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
local unicode = require("unicode")
|
local shell = require("shell")
|
||||||
local maxLength = 0
|
|
||||||
local margin = 2 -- minimum space between filename and size
|
|
||||||
local dirTable = {}
|
|
||||||
local fileTable = {}
|
|
||||||
|
|
||||||
if target then
|
local function formatSize(size, isDir)
|
||||||
if target:sub(1, 1) ~= "/" then
|
if isDir then return "[DIR]" end
|
||||||
target = fs.concat(shell.workingDirectory, target)
|
if size >= 1024^3 then return string.format("%.1fGiB", size / 1024^3) end
|
||||||
end
|
if size >= 1024^2 then return string.format("%.1fMiB", size / 1024^2) end
|
||||||
else
|
if size >= 1024 then return string.format("%.1fKiB", size / 1024) end
|
||||||
target = shell.workingDirectory
|
return size.."B"
|
||||||
end
|
end
|
||||||
|
|
||||||
local files = fs.list(target)
|
local function getFileColor(name, isDir)
|
||||||
|
if isDir then return "\27[93m" end
|
||||||
|
if name:match("%.lua$") then return "\27[92m" end
|
||||||
|
return "\27[0m"
|
||||||
|
end
|
||||||
|
|
||||||
if files then
|
local args = {...}
|
||||||
|
if not args[1] then
|
||||||
|
args = {require("shell").getWorkingDirectory()}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, path in pairs(args) do
|
||||||
|
path = shell.resolvePath(path)
|
||||||
|
local files = fs.list(path)
|
||||||
|
|
||||||
|
if not files then
|
||||||
|
terminal.write("\27[91mError: " .. path .. ": No such file or directory\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
local fileList = {}
|
||||||
for _, file in pairs(files) do
|
for _, file in pairs(files) do
|
||||||
if file:sub(-1, -1) == "/" then
|
local isDir = file:sub(-1) == "/"
|
||||||
table.insert(dirTable, file)
|
local name = isDir and file:sub(1, -2) or file
|
||||||
file = file:sub(1, -2)
|
local size = isDir and 0 or fs.size(fs.concat(path, file))
|
||||||
else
|
table.insert(fileList, {name = name, isDir = isDir, size = size})
|
||||||
table.insert(fileTable, file)
|
|
||||||
end
|
end
|
||||||
if unicode.wlen(file) > maxLength then
|
-- directories first
|
||||||
maxLength = unicode.wlen(file)
|
-- then files
|
||||||
end
|
table.sort(fileList, function(a, b)
|
||||||
end
|
if a.isDir ~= b.isDir then return a.isDir end
|
||||||
table.sort(dirTable)
|
return a.name < b.name
|
||||||
table.sort(fileTable)
|
end)
|
||||||
files = {}
|
local maxSizeLen = 0
|
||||||
for _, v in ipairs(dirTable) do
|
for _, item in ipairs(fileList) do
|
||||||
table.insert(files, v)
|
maxSizeLen = math.max(maxSizeLen, #formatSize(item.size, item.isDir))
|
||||||
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
|
||||||
|
|
||||||
|
terminal.write(path.."\n")
|
||||||
|
for _, item in ipairs(fileList) do
|
||||||
|
local sizeStr = formatSize(item.size, item.isDir)
|
||||||
|
sizeStr = string.rep(" ", maxSizeLen - #sizeStr) .. sizeStr
|
||||||
|
local color = getFileColor(item.name, item.isDir)
|
||||||
|
terminal.write(string.format("%s %s%s\27[0m\n", sizeStr, color, item.name))
|
||||||
end
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
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
|
|
||||||
+23
-10
@@ -77,7 +77,7 @@ elseif outArgIdx then
|
|||||||
if headers[word] then
|
if headers[word] then
|
||||||
addHeader(word)
|
addHeader(word)
|
||||||
else
|
else
|
||||||
print("\x1b[93mCategory \""..word.."\" doesn't exist\x1b[39m")
|
print("\x1b[93mCategory \""..word.."\" doesn't exist\x1b[0m")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -106,7 +106,7 @@ local function formatSize(mem)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function fileExists(proxy,path)
|
local function fileExists(proxy,path)
|
||||||
return proxy.exists(path) and not proxy.isDirectory(path)
|
return proxy.exists and proxy.isDirectory and proxy.exists(path) and not proxy.isDirectory(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getBootCode(proxy)
|
local function getBootCode(proxy)
|
||||||
@@ -140,24 +140,37 @@ local function handleComponent(id,type)
|
|||||||
-- for i=1,#tableOut do table.insert(out,"unknown") end
|
-- for i=1,#tableOut do table.insert(out,"unknown") end
|
||||||
local slot,capacity,managed,readOnly,mount,bootable,label
|
local slot,capacity,managed,readOnly,mount,bootable,label
|
||||||
|
|
||||||
|
local virtual,vproc = component.virtual.check(id)
|
||||||
local cslot = component.slot(id)
|
local cslot = component.slot(id)
|
||||||
if cslot==-1 then
|
if virtual then
|
||||||
slot="Virtual"
|
if vproc and vproc.name then
|
||||||
|
slot="Virtual ("..vproc.name..")"
|
||||||
|
else
|
||||||
|
slot="Virtual (unknown)"
|
||||||
|
end
|
||||||
|
elseif cslot==-1 then
|
||||||
|
slot="External"
|
||||||
elseif cslot==9 then
|
elseif cslot==9 then
|
||||||
slot="EEPROM"
|
slot="EEPROM"
|
||||||
|
elseif cslot==5 or cslot==6 then
|
||||||
|
slot="HDD #"..(cslot-4)
|
||||||
|
elseif cslot==7 then
|
||||||
|
slot="Floppy"
|
||||||
else
|
else
|
||||||
slot="#"..(cslot+2)
|
slot="#"..(cslot+2)
|
||||||
end
|
end
|
||||||
|
|
||||||
managed="Yes"
|
managed="No"
|
||||||
readOnly="No"
|
readOnly="No"
|
||||||
if type=="drive" then
|
if type=="drive" then
|
||||||
managed="No"
|
|
||||||
capacity=formatSize(proxy.getCapacity())
|
capacity=formatSize(proxy.getCapacity())
|
||||||
mount="/special/drive/"..id:sub(1,3)
|
mount="/special/drive/"..id:sub(1,3)
|
||||||
elseif type=="filesystem" then
|
elseif type=="filesystem" then
|
||||||
|
managed="Yes"
|
||||||
|
if proxy.spaceTotal then
|
||||||
capacity=formatSize(proxy.spaceTotal())
|
capacity=formatSize(proxy.spaceTotal())
|
||||||
if proxy.isReadOnly() then
|
end
|
||||||
|
if not proxy.isReadOnly or proxy.isReadOnly() then
|
||||||
readOnly="Yes"
|
readOnly="Yes"
|
||||||
end
|
end
|
||||||
mount="/mnt/"..id:sub(1,3)
|
mount="/mnt/"..id:sub(1,3)
|
||||||
@@ -177,7 +190,7 @@ local function handleComponent(id,type)
|
|||||||
|
|
||||||
if proxy.getLabel then
|
if proxy.getLabel then
|
||||||
local clabel = proxy.getLabel()
|
local clabel = proxy.getLabel()
|
||||||
label=clabel and serialize.string(clabel) or "None"
|
label=clabel and serialize(clabel) or "None"
|
||||||
else
|
else
|
||||||
label="Unsupported"
|
label="Unsupported"
|
||||||
end
|
end
|
||||||
@@ -253,7 +266,7 @@ if not showAll then
|
|||||||
if func then
|
if func then
|
||||||
filter(comps,func)
|
filter(comps,func)
|
||||||
else
|
else
|
||||||
return print("\x1b[91mInvalid component filter:\n\n"..tostring(err).."\x1b[39m")
|
return print("\x1b[91mInvalid component filter:\n\n"..tostring(err).."\x1b[0m")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
filter(comps,function(comp)
|
filter(comps,function(comp)
|
||||||
@@ -273,7 +286,7 @@ if sortArgIdx then
|
|||||||
return (boolToNum(func(a)) or 0)<(boolToNum(func(b)) or 0)
|
return (boolToNum(func(a)) or 0)<(boolToNum(func(b)) or 0)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
return print("\x1b[91mInvalid sort expression:\n\n"..tostring(err).."\x1b[39m")
|
return print("\x1b[91mInvalid sort expression:\n\n"..tostring(err).."\x1b[0m")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.sort(comps,function(a,b)
|
table.sort(comps,function(a,b)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
local tasks = tsched.getTasks()
|
||||||
|
print("\27[93m"..tostring(#tasks).."\27[0m tasks active")
|
||||||
|
for i=1, #tasks do
|
||||||
|
local pipeChar = "├ "
|
||||||
|
if i==#tasks then pipeChar = "└ " end
|
||||||
|
local task = tasks[i]
|
||||||
|
print("\27[93m"..pipeChar..(task.id or i).."\27[0m - "..task.name.."\27[37m "..table.concat(task.args or {}," ").." \27[0m")
|
||||||
|
end
|
||||||
+64
-12
@@ -1,31 +1,83 @@
|
|||||||
print("\27[44m".._VERSION.."\27[0m shell")
|
-- terminal.readHistory["lua"] = {""}
|
||||||
print('Type "exit" to exit.')
|
|
||||||
termlib.readHistory["lua"] = {""}
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
local computer = require("computer")
|
||||||
|
local log = require("log")
|
||||||
|
|
||||||
local loadedLibraries = ""
|
local bootTime = computer.uptime()
|
||||||
local libList = fs.list("halyde/lib")
|
local libList = fs.list("/lib/")
|
||||||
|
local failed = false
|
||||||
for _, lib in pairs(libList) do
|
for _, lib in pairs(libList) do
|
||||||
|
local status, err = xpcall(function()
|
||||||
if lib:match("(.+)%.lua") then
|
if lib:match("(.+)%.lua") then
|
||||||
loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = require("' .. lib:match("(.+)%.lua") .. '")\n'
|
local name = lib:match("(.+)%.lua")
|
||||||
|
_G[name] = require(name)
|
||||||
|
end
|
||||||
|
end, function(errMsg)
|
||||||
|
return errMsg .. "\n\n" .. debug.traceback()
|
||||||
|
end)
|
||||||
|
if not status then
|
||||||
|
local firstLine = tostring(err):match("^[^\n]*")
|
||||||
|
print(
|
||||||
|
string.format(
|
||||||
|
"\x1b[91mLibrary %s has failed loading:\n │ %s\x1b[0m",
|
||||||
|
lib:match("(.+)%.lua") or lib,
|
||||||
|
firstLine or "unknown error"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
log.lua.error(
|
||||||
|
string.format(
|
||||||
|
'The library located at "%s" has failed loading:\n%s',
|
||||||
|
lib,
|
||||||
|
type(err) ~= "nil" and tostring(err) or "unknown error"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
failed = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if failed then
|
||||||
|
print(
|
||||||
|
string.format(
|
||||||
|
'\x1b[93mOne or more libraries failed to load. For more information, check the log entries located at "%s".\x1b[0m',
|
||||||
|
tostring(log.lua.logpath or "[unknown]")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
print(string.format("\27[37mLoaded %d libraries in %.2f seconds\27[0m", #libList, computer.uptime() - bootTime))
|
||||||
|
print(string.format("\27[44m%s\27[0m shell", _VERSION))
|
||||||
|
print('Type "exit" to exit.')
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local command = read("lua", "\27[44mlua>\27[0m ")
|
local command = terminal.read({readHistoryType = "lua", prefix = "\27[44mlua>\27[0m "})
|
||||||
if command == "exit" then
|
if command == "exit" then
|
||||||
|
coroutine.yield()
|
||||||
return
|
return
|
||||||
else
|
elseif command ~= "" then
|
||||||
local function runCommand()
|
local function runCommand()
|
||||||
local func = load(loadedLibraries.."return "..command,"=stdin") or load(loadedLibraries..command,"=stdin")
|
local func, err = load("return " .. command, "=stdin")
|
||||||
local res = {assert(func)()}
|
local returns = true
|
||||||
if res and (type(res[1])~="nil" or type(res[2])~="nil") then print(table.unpack(res)) end
|
if not func then
|
||||||
|
func, err = load(command, "=stdin")
|
||||||
|
returns = false
|
||||||
|
end
|
||||||
|
if not func then
|
||||||
|
return print("\x1b[91msyntax error: " .. (err or "unknown error") .. "\x1b[0m")
|
||||||
|
end
|
||||||
|
local res = { func() }
|
||||||
|
if returns then
|
||||||
|
if res and type(res[1]) ~= "nil" then
|
||||||
|
print(table.unpack(res))
|
||||||
|
elseif res and type(res[2]) ~= "nil" then
|
||||||
|
print("nil", table.unpack(res))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local result, reason = xpcall(runCommand, function(errMsg)
|
local result, reason = xpcall(runCommand, function(errMsg)
|
||||||
return errMsg .. "\n\n" .. debug.traceback()
|
return errMsg .. "\n\n" .. debug.traceback()
|
||||||
end)
|
end)
|
||||||
if not result then
|
if not result then
|
||||||
print("\27[91m" .. reason)
|
print("\27[91m" .. reason .. "\27[0m")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
-- WTF: What the fuck is this for?? Why does it print the computer library???
|
||||||
|
-- TODO: Integrate this into lsdrv.
|
||||||
local computer = require("computer")
|
local computer = require("computer")
|
||||||
|
|
||||||
if type(computer)~="table" then
|
if type(computer)~="table" then
|
||||||
return print("\x1b[91mComputer library returned '"..type(computer).."' type\x1b[39m")
|
return print("\x1b[91mComputer library returned '"..type(computer).."' type\x1b[0m")
|
||||||
end
|
end
|
||||||
|
|
||||||
local address = computer.getBootAddress()
|
local address = computer.getBootAddress()
|
||||||
|
|||||||
+19
-10
@@ -1,14 +1,23 @@
|
|||||||
local directory = ...
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
if not directory then
|
local args = {...}
|
||||||
shell.run("help mkdir")
|
|
||||||
return
|
if not args[1] then
|
||||||
|
return shell.run("help mkdir")
|
||||||
end
|
end
|
||||||
if directory:sub(1, 1) ~= "/" then
|
|
||||||
directory = fs.concat(shell.workingDirectory, directory)
|
for _, directory in pairs(args) do
|
||||||
|
directory = shell.resolvePath(directory)
|
||||||
|
|
||||||
|
if fs.exists(directory) then
|
||||||
|
terminal.write("\27[91mError: " .. directory ..": An object already exists\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
local what, err = fs.makeDirectory(directory)
|
||||||
|
if err ~= nil then
|
||||||
|
terminal.write("\27[91mError: " .. err .. "\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
if fs.exists(directory) then
|
|
||||||
print("\27[91mAn object already exists at the specified path.")
|
|
||||||
end
|
|
||||||
fs.makeDirectory(directory)
|
|
||||||
|
|||||||
+64
-18
@@ -1,24 +1,70 @@
|
|||||||
local fromFile, toFile = ...
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
if not fromFile or not toFile then
|
local args = {...}
|
||||||
shell.run("help mv")
|
|
||||||
|
if not args[1] then
|
||||||
|
return shell.run("help mv")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not args[2] then
|
||||||
|
terminal.write("\27[91mError: No destination\27[0m\n")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if fromFile:sub(1, 1) ~= "/" then
|
|
||||||
fromFile = fs.concat(shell.workingDirectory, fromFile)
|
local dest = shell.resolvePath(args[#args])
|
||||||
end
|
|
||||||
if toFile:sub(1, 1) ~= "/" then
|
if fs.isFile(dest) then
|
||||||
toFile = fs.concat(shell.workingDirectory, toFile)
|
if #args ~= 2 then
|
||||||
end
|
terminal.write("\27[91mError: Destination is not a directory\27[0m\n")
|
||||||
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
|
return
|
||||||
|
end
|
||||||
|
local src = shell.resolvePath(args[1])
|
||||||
|
if not fs.exists(src) then
|
||||||
|
terminal.write("\27[91mError: " .. src .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if fs.isDirectory(src) then
|
||||||
|
terminal.write("\27[91mError: Cannot write directory " .. src .. " to file " .. dest .. "\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
fs.rename(src, dest)
|
||||||
|
elseif fs.isDirectory(dest) then
|
||||||
|
for i = 1, #args - 1 do
|
||||||
|
local src = shell.resolvePath(args[i])
|
||||||
|
if src == dest then
|
||||||
|
terminal.write("\27[91mError: Source and destination are the same\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fs.exists(src) then
|
||||||
|
terminal.write("\27[91mError: " .. src .. ": No such file or directory\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
fs.rename(src, fs.concat(dest, fs.basename(src)))
|
||||||
|
::continue::
|
||||||
|
end
|
||||||
|
elseif not fs.exists(dest) then
|
||||||
|
if #args ~= 2 then
|
||||||
|
terminal.write("\27[91mError: " .. dest .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local src = shell.resolvePath(args[1])
|
||||||
|
if not fs.exists(src) then
|
||||||
|
terminal.write("\27[91mError: " .. src .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local destp = fs.parent(dest)
|
||||||
|
if not fs.exists(destp) then
|
||||||
|
terminal.write("\27[91mError: " .. destp .. ": No such file or directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not fs.isDirectory(destp) then
|
||||||
|
terminal.write("\27[91mError: " .. destp .. ": Not a directory\27[0m\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
fs.rename(src, dest)
|
||||||
|
else
|
||||||
|
terminal.write("\27[91mUnknown error\27[0m\n")
|
||||||
end
|
end
|
||||||
fs.rename(fromFile, toFile)
|
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
-- TODO: make it somehow not depend on ESC s and ESC u
|
||||||
|
local profiler = require("profiler")
|
||||||
|
local PAL = {
|
||||||
|
{ fg = "\27[31m", bg = "\27[41m" },
|
||||||
|
{ fg = "\27[32m", bg = "\27[42m" },
|
||||||
|
{ fg = "\27[33m", bg = "\27[43m" },
|
||||||
|
{ fg = "\27[34m", bg = "\27[44m" },
|
||||||
|
{ fg = "\27[35m", bg = "\27[45m" },
|
||||||
|
{ fg = "\27[36m", bg = "\27[46m" },
|
||||||
|
{ fg = "\27[37m", bg = "\27[47m" }
|
||||||
|
}
|
||||||
|
local function pal(i) return PAL[((i - 1) % #PAL) + 1] end
|
||||||
|
|
||||||
|
local results = profiler.results()
|
||||||
|
if not results then
|
||||||
|
print("No profiling data")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local radius
|
||||||
|
local W = terminal.getResolution()
|
||||||
|
if (W == 160) then radius = 20
|
||||||
|
elseif (W == 80) then radius = 6
|
||||||
|
else radius = 0; PAL = {{fg = "", bg = ""}} end
|
||||||
|
|
||||||
|
local MIN_PC = math.min(3, 100 / (radius * 2))
|
||||||
|
|
||||||
|
local total = 0
|
||||||
|
for _, r in ipairs(results) do total = total + r.time end
|
||||||
|
|
||||||
|
local main = {}
|
||||||
|
local other = {}
|
||||||
|
local ot = 0
|
||||||
|
local on_ = 0
|
||||||
|
for _, r in ipairs(results) do
|
||||||
|
if r.time / total * 100 >= MIN_PC then
|
||||||
|
table.insert(main, r)
|
||||||
|
else
|
||||||
|
table.insert(other, r)
|
||||||
|
ot = ot + r.time;
|
||||||
|
on_ = on_ + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if on_ then
|
||||||
|
table.insert(main, { label = "other (" .. on_ .. ")", time = ot })
|
||||||
|
end
|
||||||
|
|
||||||
|
local START = -math.pi / 2
|
||||||
|
local slices = {}
|
||||||
|
local cur = START
|
||||||
|
for i, m in ipairs(main) do
|
||||||
|
local sw = m.time / total * 2 * math.pi
|
||||||
|
slices[i] = {
|
||||||
|
label = m.label,
|
||||||
|
time = m.time,
|
||||||
|
pc = ("%.1f%%"):format(m.time / total * 100),
|
||||||
|
color = pal(i),
|
||||||
|
sa = cur,
|
||||||
|
sw = sw
|
||||||
|
}
|
||||||
|
cur = cur + sw
|
||||||
|
end
|
||||||
|
if on_ then slices[#slices].color={fg = "\27[30m", bg = "\27[40m"} end
|
||||||
|
|
||||||
|
local ASP = 2
|
||||||
|
local cx = radius * ASP
|
||||||
|
local cy = radius
|
||||||
|
|
||||||
|
local function slice_at(sx, sy)
|
||||||
|
local dy = sy - cy
|
||||||
|
local dx = (sx - cx) / ASP
|
||||||
|
if dx * dx + dy * dy > radius * radius then return nil end
|
||||||
|
local a = math.atan2(dy, dx)
|
||||||
|
if a < START then a = a + 2 * math.pi end
|
||||||
|
for i, sl in ipairs(slices) do
|
||||||
|
if a >= sl.sa and a < sl.sa + sl.sw then return i end
|
||||||
|
end
|
||||||
|
return #slices
|
||||||
|
end
|
||||||
|
|
||||||
|
local SUB = {
|
||||||
|
{ dx = -0.25, dy = -0.375 },
|
||||||
|
{ dx = -0.25, dy = -0.125 },
|
||||||
|
{ dx = -0.25, dy = 0.125 },
|
||||||
|
{ dx = 0.25, dy = -0.375 },
|
||||||
|
{ dx = 0.25, dy = -0.125 },
|
||||||
|
{ dx = 0.25, dy = 0.125 },
|
||||||
|
{ dx = -0.25, dy = 0.375 },
|
||||||
|
{ dx = 0.25, dy = 0.375 },
|
||||||
|
}
|
||||||
|
|
||||||
|
for y = 0, radius * 2 do
|
||||||
|
local lx, rx = math.ceil(cx - radius * ASP), math.floor(cx + radius * ASP)
|
||||||
|
|
||||||
|
terminal.write(("\27[%dC"):format(lx))
|
||||||
|
for x = lx, rx do
|
||||||
|
local c = {}
|
||||||
|
local n = 0
|
||||||
|
for k = 1, 8 do
|
||||||
|
local s = slice_at(x + SUB[k].dx, y + SUB[k].dy)
|
||||||
|
c[k] = s
|
||||||
|
if s then n = n + 1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
if n == 0 then
|
||||||
|
terminal.write("\27[0m ")
|
||||||
|
else
|
||||||
|
local counts = {}
|
||||||
|
local order = {}
|
||||||
|
for k = 1, 8 do
|
||||||
|
if c[k] then
|
||||||
|
local key = c[k]
|
||||||
|
if not counts[key] then
|
||||||
|
counts[key] = 0
|
||||||
|
table.insert(order, key)
|
||||||
|
end
|
||||||
|
counts[key] = counts[key] + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(order, function(a, b) return counts[a] > counts[b] end)
|
||||||
|
local dom = order[1]
|
||||||
|
local sub = order[2]
|
||||||
|
|
||||||
|
if n == 8 then
|
||||||
|
terminal.write(slices[dom].color.bg)
|
||||||
|
if sub == nil then
|
||||||
|
terminal.write(" ")
|
||||||
|
else
|
||||||
|
local mask = 0
|
||||||
|
for k = 1, 8 do
|
||||||
|
if c[k] == sub then mask = mask + (1 << (k - 1)) end
|
||||||
|
end
|
||||||
|
terminal.write(slices[sub].color.fg)
|
||||||
|
terminal.write(utf8.char(0x2800 + mask))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local mask = 0
|
||||||
|
for k = 1, 8 do
|
||||||
|
if c[k] == dom then mask = mask + (1 << (k - 1)) end
|
||||||
|
end
|
||||||
|
terminal.write("\27[0m")
|
||||||
|
terminal.write(slices[dom].color.fg)
|
||||||
|
terminal.write(utf8.char(0x2800 + mask))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
terminal.write('\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
terminal.write("\27[" .. radius * 2 + 1 .. "A\27[s")
|
||||||
|
local function draw_text(col, row, s)
|
||||||
|
terminal.write("\27[u\27[" .. col .. "C\27[" .. row - 1 .. "B" .. s)
|
||||||
|
end
|
||||||
|
|
||||||
|
terminal.write("\27[0m")
|
||||||
|
if radius == 0 then goto tier1gpu end
|
||||||
|
for _, sl in ipairs(slices) do
|
||||||
|
local y = math.floor(cy + radius * 0.62 * math.sin(sl.sa + sl.sw / 2) + 0.5)
|
||||||
|
|
||||||
|
local function in_slice(x, row)
|
||||||
|
local a = math.atan2(row - cy, (x - cx) / ASP)
|
||||||
|
if a < START then
|
||||||
|
a = a + 2 * math.pi
|
||||||
|
end
|
||||||
|
return a >= sl.sa and a < sl.sa + sl.sw
|
||||||
|
end
|
||||||
|
local function centered_draw(row, text)
|
||||||
|
local dy = row - cy
|
||||||
|
local half_w = math.sqrt(radius * radius - dy * dy) * ASP
|
||||||
|
local lx, rx = math.ceil(cx - half_w), math.floor(cx + half_w)
|
||||||
|
while lx <= rx and not in_slice(lx, row) do
|
||||||
|
lx = lx + 1
|
||||||
|
end
|
||||||
|
while rx >= lx and not in_slice(rx, row) do
|
||||||
|
rx = rx - 1
|
||||||
|
end
|
||||||
|
local avail = rx - lx + 1
|
||||||
|
if avail < 3 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local t = #text > avail and text:sub(1, avail - 3) .. "..." or text
|
||||||
|
local start_x = lx + math.floor((avail - #t) / 2)
|
||||||
|
draw_text(start_x, row, sl.color.bg .. t)
|
||||||
|
end
|
||||||
|
centered_draw(y, sl.label)
|
||||||
|
centered_draw(y + 1, sl.pc)
|
||||||
|
end
|
||||||
|
::tier1gpu::
|
||||||
|
|
||||||
|
local max_w = 0
|
||||||
|
for _, sl in pairs(slices) do
|
||||||
|
max_w = math.max(#sl.label + 1, max_w)
|
||||||
|
end
|
||||||
|
for _, sl in pairs(other) do
|
||||||
|
max_w = math.max(#sl.label + 3, max_w)
|
||||||
|
end
|
||||||
|
local x = radius * 2 * ASP + 2
|
||||||
|
if radius == 0 then x = 0 end
|
||||||
|
local cw = W - x - 1
|
||||||
|
local suffix_w = 18
|
||||||
|
local max_lbl = math.max(4, cw - suffix_w)
|
||||||
|
terminal.write("\27[u\27[" .. x .. "C" .. ("\27[0m%" .. max_w .. "s %9s %6s"):format("label", "time", "share"))
|
||||||
|
terminal.write("\n")
|
||||||
|
for _, sl in ipairs(slices) do
|
||||||
|
local lbl = sl.label
|
||||||
|
if #lbl > max_lbl then
|
||||||
|
lbl = sl.label:sub(1, max_lbl - 1) .. "…"
|
||||||
|
end
|
||||||
|
terminal.write("\n\27[" .. x .. "C" .. ("%s%" .. max_w .. "s\27[0m %9.4fs %6s"):format(sl.color.bg, lbl, sl.time, sl.pc))
|
||||||
|
end
|
||||||
|
for _, sl in ipairs(other) do
|
||||||
|
local lbl = sl.label
|
||||||
|
if #lbl > max_lbl - 2 then
|
||||||
|
lbl = sl.label:sub(1, max_lbl - 3) .. "…"
|
||||||
|
end
|
||||||
|
terminal.write("\n\27[" .. x .. "C" .. ("%s%" .. max_w .. "s\27[0m %9.4fs %6s"):format(slices[#slices].color.bg, lbl, sl.time, ("%.1f%%"):format(sl.time / total * 100)))
|
||||||
|
end
|
||||||
|
|
||||||
|
if radius * 2 + 2 > #slices + #other then
|
||||||
|
terminal.write("\27[" .. radius * 2 + 2 .. "B")
|
||||||
|
end
|
||||||
|
terminal.write("\n")
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
local component = require("component")
|
||||||
|
local gpu = component.gpu
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
local maxX, maxY = gpu.maxResolution()
|
||||||
|
local curX, curY = gpu.getResolution()
|
||||||
|
|
||||||
|
local function setRes()
|
||||||
|
if not(args[1] == "-x" or args[1] == "-y") then
|
||||||
|
print("\x1b[91mUnknown argument. \x1b[0mTry running \x1b[92m\"help res\"\x1b[0m")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local lastarg = ""
|
||||||
|
local x, y
|
||||||
|
for i = 1, 3, 2 do
|
||||||
|
if args[i] == "-x" then
|
||||||
|
if lastarg ~= "x" then
|
||||||
|
x = tonumber(args[i + 1])
|
||||||
|
lastarg = "x"
|
||||||
|
else
|
||||||
|
print("\x1b[91mValue \"x\" was set more than once. \x1b[0mTry running \x1b[92m\"help res\"\x1b[0m")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
elseif args[i] == "-y" then
|
||||||
|
if lastarg ~= "y" then
|
||||||
|
y = tonumber(args[i + 1])
|
||||||
|
lastarg = "y"
|
||||||
|
else
|
||||||
|
print("\x1b[91mValue \"y\" was set more than once. \x1b[0mTry running \x1b[92m\"help res\"\x1b[0m")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if x then
|
||||||
|
if x > maxX then
|
||||||
|
print("\x1b[91mGPU does not support x higher than " .. maxX .. "\x1b[0m.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if y then
|
||||||
|
if y > maxY then
|
||||||
|
print("\x1b[91mGPU does not support y higher than " .. maxY .. "\x1b[0m.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if x and not(y) then
|
||||||
|
gpu.setResolution(x, curY)
|
||||||
|
print("Successfully set X resolution from \x1b[93m" .. curX .. "\x1b[0m to \x1b[92m" .. x .. "\x1b[0m.")
|
||||||
|
return
|
||||||
|
elseif not(x) and y then
|
||||||
|
gpu.setResolution(curX, y)
|
||||||
|
print("Successfully set Y resolution from \x1b[93m" .. curY .. "\x1b[0m to \x1b[92m" .. y .. "\x1b[0m.")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
gpu.setResolution(x, y)
|
||||||
|
print("Successfully set resolution from \x1b[93m" .. curX .. "x" .. curY .. "\x1b[0m to \x1b[92m" .. x .. "x" .. y .. "\x1b[0m.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getRes(val)
|
||||||
|
if val == "x" then
|
||||||
|
print("Current X resolution: \x1b[93m" .. curX .. "\x1b[0m")
|
||||||
|
print("Maximum supported X resolution: \x1b[92m" .. maxX .. "\x1b[0m")
|
||||||
|
elseif val == "y" then
|
||||||
|
print("Current Y resolution: \x1b[93m" .. curY .. "\x1b[0m")
|
||||||
|
print("Maximum supported Y resolution: \x1b[92m" .. maxY .. "\x1b[0m")
|
||||||
|
else
|
||||||
|
print("Current resolution: \x1b[93m" .. curX .. "x" .. curY .. "\x1b[0m")
|
||||||
|
print("Maximum supported resolution: \x1b[92m" .. maxX .. "x" .. maxY .. "\x1b[0m")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #args == 0 then
|
||||||
|
getRes()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not(#args == 1) then
|
||||||
|
setRes()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local axis = args[1]
|
||||||
|
if axis == "-x" then
|
||||||
|
getRes("x")
|
||||||
|
elseif axis == "-y" then
|
||||||
|
getRes("y")
|
||||||
|
else
|
||||||
|
print("\x1b[91mUnknown argument. \x1b[0mTry running \x1b[92m\"help res\"\x1b[0m")
|
||||||
|
end
|
||||||
+13
-11
@@ -1,15 +1,17 @@
|
|||||||
local file = ...
|
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
if not file then
|
local args = {...}
|
||||||
shell.run("help rm")
|
|
||||||
return
|
if not args[1] then
|
||||||
|
return shell.run("help rm")
|
||||||
end
|
end
|
||||||
if file:sub(1, 1) ~= "/" then
|
|
||||||
file = fs.concat(shell.workingDirectory, file)
|
for _, file in pairs(args) do
|
||||||
|
file = shell.resolvePath(file)
|
||||||
|
|
||||||
|
local result = fs.remove(file)
|
||||||
|
if result == false then
|
||||||
|
terminal.write("\27[91mError: cannot delete " .. file .. "\27[0m\n")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if not fs.exists(file) then
|
|
||||||
print("\27[91mFile does not exist.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
fs.remove(file)
|
|
||||||
|
|||||||
@@ -88,4 +88,4 @@ end
|
|||||||
end ]]
|
end ]]
|
||||||
|
|
||||||
raster.free()
|
raster.free()
|
||||||
termlib.cursorPosY=1
|
terminal.clear()
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- TODO: Rename this to something else (while making an alias from the original command).
|
||||||
|
-- Touch seems kind of a silly name for a command to make a file.
|
||||||
|
-- Maybe something like mkfile would be better?
|
||||||
|
local fs = require("filesystem")
|
||||||
|
local shell = require("shell")
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
if not args[1] then
|
||||||
|
return shell.run("help touch")
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, file in pairs(args) do
|
||||||
|
file = shell.resolvePath(file)
|
||||||
|
|
||||||
|
local handle, err = fs.open(file, "a")
|
||||||
|
if err ~= nil then
|
||||||
|
terminal.write("\27[91mError: " .. err .. "\27[0m\n")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
handle:close()
|
||||||
|
::continue::
|
||||||
|
end
|
||||||
@@ -1 +1 @@
|
|||||||
{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls","ps":"lscor","poweroff":"shutdown","restart":"reboot"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ %s\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"}
|
{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls","ps":"lscor","poweroff":"shutdown","restart":"reboot","resolution":"res"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ %s\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"palette":{"dark":{"0":"171421","1":"c01c28","2":"26a269","3":"a2734c","4":"12488b","5":"a347ba","6":"2aa1b3","7":"d0cfcc"},"bright":{"0":"5e5c64","1":"f66151","2":"33d17a","3":"e9ad0c","4":"2a7bde","5":"c061cb","6":"33c7de","7":"ffffff"}}}
|
||||||
@@ -1 +1 @@
|
|||||||
{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls","ps":"lscor","poweroff":"shutdown","restart":"reboot","lsblk":"lsdrv"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!","Now i% more secure!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ %s\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"}
|
{"prompt":"\u001b[92m%s > \u001b[0m","aliases":{"move":"mv","copy":"cp","ag":"argentum","rename":"mv","..":"cd ..","man":"help","del":"rm","delete":"rm","ren":"mv","remove":"rm","list":"ls","wget":"download","dir":"ls","ps":"lstsk","poweroff":"shutdown","restart":"reboot","lsblk":"lsdrv","lscor":"lstsk"},"splashMessages":["Made by John Haly- I mean Cerulean Blue.","Welcome! Type \"help\" to get started.","Also try KOCOS!","Welcome back, Commander. We have no idea what we're doing.","99.9% bug-free. The remaining 0.1% are features.","0 days since last error.","Everything is fine. The fire is decorative.","Please don't feed the background processes.","Also has fetch!","Anything red is no man's land. Trust me.","Machine...","Abort, Retry, Fail?","What's the deal with /argentum/store?","So cutting-edge you can't hold it in your hand.","Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.","Shoutout to Ponali!","Now i% more secure!"],"path":["/halyde/apps/"],"startupMessage":"\n │\n │ %s\n │ %s\n │\n ","defaultWorkingDirectory":"/home/"}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
["/halyde/shell/shell.lua"]
|
["/halyde/scripts/login.lua"]
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"palette":{"dark":{"0":"171421","1":"c01c28","2":"26a269","3":"a2734c","4":"12488b","5":"a347ba","6":"2aa1b3","7":"d0cfcc"},"bright":{"0":"5e5c64","1":"f66151","2":"33d17a","3":"e9ad0c","4":"2a7bde","5":"c061cb","6":"33c7de","7":"ffffff"}}}
|
||||||
+46
-30
@@ -1,44 +1,57 @@
|
|||||||
local loadfile = ...
|
local loadfile = ...
|
||||||
local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile))
|
local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile))
|
||||||
_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
|
_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
|
||||||
_G._OSLOGO = ""
|
|
||||||
_G._PUBLIC = {}
|
_G._PUBLIC = {}
|
||||||
local ocelot = component.proxy(component.list("ocelot")())
|
_G._PUBLIC.unicode = assert(loadfile("/lib/unicode.lua")(loadfile))
|
||||||
|
local component = assert(loadfile("/lib/component.lua")(loadfile))
|
||||||
|
local gpu = component.gpu
|
||||||
|
local screenAddress = component.list("screen")()
|
||||||
|
|
||||||
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
gpu.bind(screenAddress)
|
||||||
repeat
|
gpu.setResolution(gpu.maxResolution())
|
||||||
tmpdata = handle:read(math.huge)
|
|
||||||
_OSLOGO = _OSLOGO .. (tmpdata or "")
|
|
||||||
until not tmpdata
|
|
||||||
|
|
||||||
_G.package = {["preloaded"] = {}}
|
local log = assert(loadfile("/lib/log.lua")(loadfile))
|
||||||
|
_G.profiler = assert(loadfile("/lib/profiler.lua")())
|
||||||
|
|
||||||
loadfile("/halyde/kernel/modules/datatools.lua")()
|
log.kernel.info("Bound GPU to screen " .. tostring(screenAddress))
|
||||||
|
|
||||||
function _G.require(module, ...)
|
_G.package = { ["preloaded"] = {} }
|
||||||
ocelot.log("Requiring " .. module)
|
|
||||||
|
function _G.reqgen(load)
|
||||||
|
return function(module, ...)
|
||||||
local args = table.pack(...)
|
local args = table.pack(...)
|
||||||
if package.preloaded[module] then
|
if package.preloaded[module] then
|
||||||
return package.preloaded[module]
|
return package.preloaded[module]
|
||||||
end
|
end
|
||||||
local modulepath
|
local modulepath
|
||||||
if filesystem.exists(module) then
|
if filesystem.exists(module) and not filesystem.isDirectory(module) then
|
||||||
modulepath = module
|
modulepath = module
|
||||||
elseif filesystem.exists("/lib/" .. module .. ".lua") then
|
elseif
|
||||||
|
filesystem.exists("/lib/" .. module .. ".lua") and not filesystem.isDirectory("/lib/" .. module .. ".lua")
|
||||||
|
then
|
||||||
modulepath = "/lib/" .. module .. ".lua"
|
modulepath = "/lib/" .. module .. ".lua"
|
||||||
elseif shell and shell.workingDirectory and filesystem.exists(filesystem.concat(shell.workingDirectory, module .. ".lua")) then
|
elseif
|
||||||
|
shell
|
||||||
|
and shell.workingDirectory
|
||||||
|
and filesystem.exists(filesystem.concat(shell.workingDirectory, module .. ".lua"))
|
||||||
|
and not filesystem.isDirectory(filesystem.concat(shell.workingDirectory, module .. ".lua"))
|
||||||
|
then
|
||||||
modulepath = shell.workingDirectory .. module .. ".lua"
|
modulepath = shell.workingDirectory .. module .. ".lua"
|
||||||
end
|
end
|
||||||
assert(modulepath, "Module not found\nPossible locations:\n/lib/" .. module .. ".lua")
|
assert(modulepath, "Module not found\nPossible locations:\n/lib/" .. module .. ".lua") -- FIXME: When providing an absolute path, this spits out some weird stuff.
|
||||||
local handle, data, tmpdata = filesystem.open(modulepath), "", nil
|
local handle, data, tmpdata = filesystem.open(modulepath), "", nil
|
||||||
repeat
|
repeat
|
||||||
tmpdata = handle:read(math.huge or math.maxinteger)
|
tmpdata = handle:read(math.huge or math.maxinteger)
|
||||||
data = data .. (tmpdata or "")
|
data = data .. (tmpdata or "")
|
||||||
until not tmpdata
|
until not tmpdata
|
||||||
handle:close()
|
handle:close()
|
||||||
return(assert(load(data, "="..modulepath))(table.unpack(args)))
|
return (assert(load(data, "=" .. modulepath))(table.unpack(args)))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
_G.require = reqgen(_G.load)
|
||||||
|
log.kernel.info("Generated userland require function")
|
||||||
|
|
||||||
function _G.package.preload(module)
|
function _G.package.preload(module)
|
||||||
local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil
|
local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil
|
||||||
repeat
|
repeat
|
||||||
@@ -46,28 +59,31 @@ function _G.package.preload(module)
|
|||||||
data = data .. (tmpdata or "")
|
data = data .. (tmpdata or "")
|
||||||
until not tmpdata
|
until not tmpdata
|
||||||
handle:close()
|
handle:close()
|
||||||
package.preloaded[module] = assert(load(data, "="..module))()
|
package.preloaded[module] = assert(load(data, "=" .. module))()
|
||||||
_G[module] = nil
|
_G[module] = nil
|
||||||
|
log.kernel.info(string.format("Pre-loaded /lib/%s.lua", module))
|
||||||
end
|
end
|
||||||
|
|
||||||
require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools.
|
require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. TODO: When VFS is implemented, make the pre-VFS loading of filesystem load a more basic version. And remove this.
|
||||||
|
log.kernel.info("Loading modules")
|
||||||
require("/halyde/kernel/modload.lua")
|
require("/halyde/kernel/modload.lua")
|
||||||
|
|
||||||
package.preload("component")
|
local toPreload = { "component", "computer", "log", "event" }
|
||||||
package.preload("computer")
|
for _, p in pairs(toPreload) do
|
||||||
|
profiler.profile("pre-loading " .. p, package.preload, p)
|
||||||
local component = require("component")
|
|
||||||
local gpu = component.gpu
|
|
||||||
local screenAddress = component.list("screen")()
|
|
||||||
|
|
||||||
gpu.bind(screenAddress)
|
|
||||||
gpu.setResolution(gpu.maxResolution())
|
|
||||||
|
|
||||||
if not filesystem.exists("/halyde/config/shell.json") then -- Auto-generate configs
|
|
||||||
filesystem.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local computer = require("computer")
|
||||||
|
function wait(seconds)
|
||||||
|
local oldTime = computer.uptime()
|
||||||
|
while computer.uptime() < oldTime + seconds do
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if not filesystem.exists("/halyde/config/startupapps.json") then
|
if not filesystem.exists("/halyde/config/startupapps.json") then
|
||||||
filesystem.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json")
|
filesystem.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
log.kernel.info("Starting tsched")
|
||||||
require("/halyde/kernel/tsched.lua")
|
require("/halyde/kernel/tsched.lua")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ local conversionTables = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function table.find(tab, item)
|
function table.find(tab, item)
|
||||||
|
checkArg(1,tab,"table")
|
||||||
for k, v in pairs(tab) do
|
for k, v in pairs(tab) do
|
||||||
if v == item then
|
if v == item then
|
||||||
return k
|
return k
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
_G.evmgr = {}
|
|
||||||
_G.evmgr.eventQueue = {}
|
|
||||||
local maxEventQueueLength = 10 -- increase if events start getting dropped
|
|
||||||
|
|
||||||
local computer = require("computer")
|
|
||||||
|
|
||||||
_G._PUBLIC.keyboard.ctrlDown = false
|
|
||||||
_G._PUBLIC.keyboard.altDown = false
|
|
||||||
_G._PUBLIC.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 _PUBLIC.keyboard then
|
|
||||||
if args[2] == "key_down" then
|
|
||||||
local keycode = args[5]
|
|
||||||
local key = _PUBLIC.keyboard.keys[keycode]
|
|
||||||
if key == "lcontrol" then
|
|
||||||
_PUBLIC.keyboard.ctrlDown = true
|
|
||||||
elseif key == "lmenu" then
|
|
||||||
_PUBLIC.keyboard.altDown = true
|
|
||||||
elseif key == "lshift" then
|
|
||||||
_PUBLIC.keyboard.shiftDown = true
|
|
||||||
elseif key == "c" and _PUBLIC.keyboard.ctrlDown and _PUBLIC.keyboard.altDown then
|
|
||||||
if print then
|
|
||||||
print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.")
|
|
||||||
end
|
|
||||||
tsched.tasks[#tsched.tasks] = nil
|
|
||||||
end
|
|
||||||
elseif args[2] == "key_up" then
|
|
||||||
local keycode = args[5]
|
|
||||||
local key = _PUBLIC.keyboard.keys[keycode]
|
|
||||||
if key == "lcontrol" then
|
|
||||||
_PUBLIC.keyboard.ctrlDown = false
|
|
||||||
elseif key == "lmenu" then
|
|
||||||
_PUBLIC.keyboard.altDown = false
|
|
||||||
elseif key == "lshift" then
|
|
||||||
_PUBLIC.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
|
|
||||||
+156
-17
@@ -1,24 +1,58 @@
|
|||||||
|
local log = require("log")
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
local ocelot = require("component").ocelot
|
|
||||||
|
|
||||||
local modulePath = "/halyde/kernel/modules"
|
local modulePath = "/halyde/kernel/modules"
|
||||||
|
|
||||||
local modules = fs.list(modulePath)
|
if not (fs.exists(modulePath) or fs.isDirectory(modulePath)) then
|
||||||
|
return log.kernel.warn(
|
||||||
|
string.format("Module directory (%s) does not exist and/or has been detected as a file - skipping", modulePath)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
local moduleList, err = fs.list(modulePath)
|
||||||
|
if not moduleList then
|
||||||
|
return log.kernel.warn(
|
||||||
|
string.format("Could not get list of modules (from %s): %s", modulePath, tostring(err or "unknown error"))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
local modules = {}
|
||||||
local moduleTypes = {}
|
local moduleTypes = {}
|
||||||
|
local modulesLoaded = {}
|
||||||
|
|
||||||
local function loadModule(modName)
|
local function loadModule(modName)
|
||||||
ocelot.log("Checking module " .. modName)
|
local stop = profiler.start("loadModule(" .. tostring(modName) .. ")")
|
||||||
local moduleData = require(fs.concat(modulePath, modName))
|
if table.find(modulesLoaded, modName) then
|
||||||
table.remove(modules, table.find(modules, modName))
|
log.kernel.warn(string.format("[modload: %s] Module was already loaded - skipping", modName))
|
||||||
if not moduleData.check() then
|
stop()
|
||||||
return
|
return true
|
||||||
end
|
end
|
||||||
ocelot.log("Loading module " .. modName)
|
|
||||||
if moduleData.dependencies then
|
local moduleData = modules[modName]
|
||||||
|
if not moduleData then
|
||||||
|
log.kernel.warn(string.format("[modload: %s] Could not find module data.", modName))
|
||||||
|
table.remove(moduleList, table.find(moduleList, modName))
|
||||||
|
stop()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local ready = false
|
||||||
|
local status, err = xpcall(function()
|
||||||
|
ready = moduleData.check()
|
||||||
|
end, debug.traceback)
|
||||||
|
if not status then
|
||||||
|
ready = false
|
||||||
|
log.kernel.error(
|
||||||
|
string.format("[modload: %s] Could not check if module was ready: %s", modName, tostring(err or "unknown error"))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if not ready then
|
||||||
|
log.kernel.info(string.format("[modload: %s] Module not ready - skipping", modName))
|
||||||
|
stop()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if type(moduleData.dependencies) == "table" then
|
||||||
for _, dependency in pairs(moduleData.dependencies) do
|
for _, dependency in pairs(moduleData.dependencies) do
|
||||||
if table.find(modules, dependency) then
|
if table.find(moduleList, dependency) then
|
||||||
loadModule(dependency)
|
loadModule(dependency)
|
||||||
elseif table.find(modules, dependency .. ".lua") then
|
elseif table.find(moduleList, dependency .. ".lua") then
|
||||||
loadModule(dependency .. ".lua")
|
loadModule(dependency .. ".lua")
|
||||||
else
|
else
|
||||||
for typeLookupDrvName, typeLookupDrvType in pairs(moduleTypes) do
|
for typeLookupDrvName, typeLookupDrvType in pairs(moduleTypes) do
|
||||||
@@ -31,23 +65,128 @@ local function loadModule(modName)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
--print(modName)
|
--print(modName)
|
||||||
|
log.kernel.info(string.format("[modload: %s] Loading module", modName))
|
||||||
if moduleData.init then -- I have no idea why this would not exist, but it's a failsafe
|
if moduleData.init then -- I have no idea why this would not exist, but it's a failsafe
|
||||||
|
local status, err = xpcall(function()
|
||||||
moduleData.init()
|
moduleData.init()
|
||||||
|
end, debug.traceback)
|
||||||
|
if not status then
|
||||||
|
log.kernel.error(
|
||||||
|
string.format(
|
||||||
|
"[modload: %s] An error has occured while initiating this module: %s",
|
||||||
|
modName,
|
||||||
|
tostring(err or "unknown error")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stop()
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
table.insert(modulesLoaded, modName)
|
||||||
|
table.remove(moduleList, table.find(moduleList, modName))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
stop()
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, modName in pairs(modules) do -- Get all the module types
|
for _, modName in pairs(moduleList) do -- Get all the module types
|
||||||
local moduleData = require(fs.concat(modulePath, modName))
|
local stop = profiler.start("getting module " .. modName .. ")")
|
||||||
|
log.kernel.info(string.format("[modload: %s] Getting data from module", modName))
|
||||||
|
local moduleData
|
||||||
|
local status, err = pcall(function()
|
||||||
|
moduleData = require(fs.concat(modulePath, modName))
|
||||||
|
end)
|
||||||
|
if not status then
|
||||||
|
log.kernel.error(
|
||||||
|
string.format(
|
||||||
|
"[modload: %s] Module returned error while getting data: %s",
|
||||||
|
modName,
|
||||||
|
tostring(err or "unknown error")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
if type(moduleData) ~= "table" then
|
||||||
|
log.kernel.error(
|
||||||
|
string.format("[modload: %s] Module returned invalid type (%s) - skipping", modName, type(moduleData))
|
||||||
|
)
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
if type(moduleData.check) ~= "function" then
|
||||||
|
log.kernel.error(string.format('[modload: %s] Module doesn\'t contain a "check" function', modName))
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
if type(moduleData.init) ~= "function" then
|
||||||
|
log.kernel.error(string.format('[modload: %s] Module doesn\'t contain an "init" function', modName))
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
if type(moduleData.exit) ~= "function" then
|
||||||
|
log.kernel.error(string.format('[modload: %s] Module doesn\'t contain an "exit" function', modName))
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
modules[modName] = moduleData
|
||||||
if moduleData.type then
|
if moduleData.type then
|
||||||
--print(moduleData.type)
|
--print(moduleData.type)
|
||||||
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
|
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
|
||||||
end
|
end
|
||||||
|
::continue::
|
||||||
|
stop()
|
||||||
end
|
end
|
||||||
|
|
||||||
while modules[1] do
|
local function loadAllModules() -- attempt at loading all modules, unless if they're not ready
|
||||||
if modules[1]:sub(-1, -1) ~= "/" then -- Check if it's not a directory. If it is, it might be module config
|
local notReadyModules = {}
|
||||||
loadModule(modules[1])
|
while moduleList[1] do
|
||||||
|
if moduleList[1]:sub(-1, -1) ~= "/" then -- Check if it's not a directory. If it is, it might be module config
|
||||||
|
local ready = loadModule(moduleList[1])
|
||||||
|
if not ready then
|
||||||
|
table.insert(notReadyModules, table.remove(moduleList, 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
moduleList = notReadyModules
|
||||||
|
-- log.kernel.info("debug: modload finished attempting loading modules. remaining: " .. table.concat(moduleList, ","))
|
||||||
|
end
|
||||||
|
|
||||||
|
loadAllModules()
|
||||||
|
|
||||||
|
local function checkModules()
|
||||||
|
log.kernel.info("[modload] Updating module availability.")
|
||||||
|
loadAllModules() -- load modules that haven't returned true before
|
||||||
|
-- exit modules that haven't returned false before (check if this is right first)
|
||||||
|
for _, v in pairs(table.copy(modulesLoaded)) do
|
||||||
|
local ready = false
|
||||||
|
local status, err = xpcall(function()
|
||||||
|
ready = modules[v].check()
|
||||||
|
end, debug.traceback)
|
||||||
|
if not status then
|
||||||
|
ready = false
|
||||||
|
log.kernel.error(
|
||||||
|
string.format(
|
||||||
|
"[modload: %s] Could not check if module was ready: %s",
|
||||||
|
modName,
|
||||||
|
tostring(err or "unknown error")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if not ready then
|
||||||
|
log.kernel.info(string.format("[modload: %s] Module is no longer ready: exiting", v))
|
||||||
|
local status, err = xpcall(function()
|
||||||
|
modules[v].exit()
|
||||||
|
end, debug.traceback)
|
||||||
|
if not status then
|
||||||
|
log.kernel.error(string.format("[modload: %s] Could not exit module: %s", v, tostring(err or "unknown error")))
|
||||||
|
end
|
||||||
|
table.insert(moduleList, table.remove(modulesLoaded, table.find(modulesLoaded, v)))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ocelot.log("Finished loading modules!")
|
if _PUBLIC.tsched then
|
||||||
|
_PUBLIC.tsched.addTask(function()
|
||||||
|
local event = require("event")
|
||||||
|
while true do
|
||||||
|
event.pull("component_added", "component_removed") -- wait until a component gets added or removed
|
||||||
|
checkModules()
|
||||||
|
end
|
||||||
|
end, "modload")
|
||||||
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
module.dependencies = {"terminal"}
|
module.dependencies = { "terminal" }
|
||||||
|
|
||||||
function module.check()
|
function module.check()
|
||||||
return true -- This module should always be loaded
|
return true -- This module should always be loaded
|
||||||
@@ -9,7 +9,6 @@ end
|
|||||||
function module.init()
|
function module.init()
|
||||||
local publicTable = {
|
local publicTable = {
|
||||||
"print",
|
"print",
|
||||||
"require",
|
|
||||||
"_VERSION",
|
"_VERSION",
|
||||||
"_OSVERSION",
|
"_OSVERSION",
|
||||||
"assert",
|
"assert",
|
||||||
@@ -39,7 +38,8 @@ function module.init()
|
|||||||
"table",
|
"table",
|
||||||
"checkArg",
|
"checkArg",
|
||||||
"utf8",
|
"utf8",
|
||||||
"convert"
|
"convert",
|
||||||
|
"wait"
|
||||||
}
|
}
|
||||||
for _, value in ipairs(publicTable) do
|
for _, value in ipairs(publicTable) do
|
||||||
_G._PUBLIC[value] = table.copy(_G[value])
|
_G._PUBLIC[value] = table.copy(_G[value])
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
local module = {}
|
||||||
|
|
||||||
|
module.dependencies = { "tsched", "keyboard" }
|
||||||
|
|
||||||
|
function module.check()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local process
|
||||||
|
|
||||||
|
function module.init()
|
||||||
|
_G.evmgr = {}
|
||||||
|
_G.evmgr.eventQueue = { kernel = {} }
|
||||||
|
local maxEventQueueLength = 10 -- increase if events start getting dropped
|
||||||
|
|
||||||
|
local computer = require("computer")
|
||||||
|
|
||||||
|
local ctrlDown = false
|
||||||
|
local altDown = false
|
||||||
|
local shiftDown = false
|
||||||
|
|
||||||
|
function _G._PUBLIC.keyboard.getCtrlDown()
|
||||||
|
return ctrlDown
|
||||||
|
end
|
||||||
|
function _G._PUBLIC.keyboard.getAltDown()
|
||||||
|
return altDown
|
||||||
|
end
|
||||||
|
function _G._PUBLIC.keyboard.getShiftDown()
|
||||||
|
return shiftDown
|
||||||
|
end
|
||||||
|
|
||||||
|
_, process = _PUBLIC.tsched.addTask(function()
|
||||||
|
while true do
|
||||||
|
-- check for events
|
||||||
|
local args
|
||||||
|
repeat
|
||||||
|
args = { computer.uptime(), computer.pullSignal(0) }
|
||||||
|
if args and args[2] then
|
||||||
|
for pid in pairs(evmgr.eventQueue) do
|
||||||
|
table.insert(evmgr.eventQueue[pid], args)
|
||||||
|
end
|
||||||
|
if _PUBLIC.keyboard then
|
||||||
|
if args[2] == "key_down" then
|
||||||
|
local keycode = args[5]
|
||||||
|
local key = _PUBLIC.keyboard.keys[keycode]
|
||||||
|
if key == "lcontrol" then
|
||||||
|
ctrlDown = true
|
||||||
|
elseif key == "lmenu" then
|
||||||
|
altDown = true
|
||||||
|
elseif key == "lshift" then
|
||||||
|
shiftDown = true
|
||||||
|
elseif key == "c" and ctrlDown and altDown then
|
||||||
|
if print then
|
||||||
|
print("\n\27[91mCoroutine " .. tostring(#tsched.tasks) .. " killed.")
|
||||||
|
end
|
||||||
|
table.remove(tsched.tasks, #tsched.tasks)
|
||||||
|
end
|
||||||
|
elseif args[2] == "key_up" then
|
||||||
|
local keycode = args[5]
|
||||||
|
local key = _PUBLIC.keyboard.keys[keycode]
|
||||||
|
if key == "lcontrol" then
|
||||||
|
ctrlDown = false
|
||||||
|
elseif key == "lmenu" then
|
||||||
|
altDown = false
|
||||||
|
elseif key == "lshift" then
|
||||||
|
shiftDown = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for pid in pairs(evmgr.eventQueue) do
|
||||||
|
while #evmgr.eventQueue[pid] > maxEventQueueLength do
|
||||||
|
--ocelot.log("Queue length breach, removing first signal")
|
||||||
|
table.remove(evmgr.eventQueue[pid], 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
until not args or not args[1]
|
||||||
|
-- TODO: check for processes that have ended
|
||||||
|
-- run other tasks
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end, "evmgr")
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.exit()
|
||||||
|
_G.evmgr = nil
|
||||||
|
_PUBLIC.tsched.removeTask(process.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
return module
|
||||||
@@ -1,15 +1,219 @@
|
|||||||
local module = {}
|
local module = {}
|
||||||
|
module.dependencies = { "tsched" }
|
||||||
|
|
||||||
function module.check()
|
function module.check()
|
||||||
return true -- This module should always be loaded
|
return true -- IPC should always be loaded
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local checkProcess
|
||||||
function module.init()
|
function module.init()
|
||||||
|
_G.ipc = {}
|
||||||
|
_G.ipc.shared = {}
|
||||||
|
_PUBLIC.ipc = {}
|
||||||
|
|
||||||
|
function _PUBLIC.ipc.shareWithAll()
|
||||||
|
local shareTable = {}
|
||||||
|
setmetatable(shareTable, {
|
||||||
|
["__newindex"] = function(_, key, value)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
_G.ipc.shared[currentPID] = {}
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == "all" then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
globalTable = { ["sharedWith"] = "all" }
|
||||||
|
table.insert(_G.ipc.shared[currentPID], globalTable)
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
globalTable.vars = {}
|
||||||
|
end
|
||||||
|
globalTable.vars[key] = value
|
||||||
|
end,
|
||||||
|
["__index"] = function(_, key)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == "all" then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return globalTable.vars[key]
|
||||||
|
end,
|
||||||
|
["__pairs"] = function()
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
return pairs({})
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == pid then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
return pairs({})
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
return pairs({})
|
||||||
|
end
|
||||||
|
|
||||||
|
return pairs(table.copy(globalTable.vars))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
return shareTable
|
||||||
|
end
|
||||||
|
|
||||||
|
function _PUBLIC.ipc.shareWith(pid)
|
||||||
|
checkArg(1, pid, "number")
|
||||||
|
local shareTable = {}
|
||||||
|
setmetatable(shareTable, {
|
||||||
|
["__newindex"] = function(_, key, value)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
_G.ipc.shared[currentPID] = {}
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == "all" then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
globalTable = { ["sharedWith"] = pid }
|
||||||
|
table.insert(_G.ipc.shared[currentPID], globalTable)
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
globalTable.vars = {}
|
||||||
|
end
|
||||||
|
globalTable.vars[key] = value
|
||||||
|
end,
|
||||||
|
["__index"] = function(_, key)
|
||||||
|
print(_G.ipc.shared)
|
||||||
|
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == pid then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return globalTable.vars[key]
|
||||||
|
end,
|
||||||
|
["__pairs"] = function()
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
return pairs({})
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == pid then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
return pairs({})
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
return pairs({})
|
||||||
|
end
|
||||||
|
|
||||||
|
return pairs(table.copy(globalTable.vars))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- check if the reverse is also available
|
||||||
|
--[[ if not _G.ipc.shared[pid] then
|
||||||
|
_G.ipc.shared[pid]={}
|
||||||
|
end
|
||||||
|
for _, tab in pairs(_G.ipc.shared[pid]) do
|
||||||
|
if tab.sharedWith == currentPID then
|
||||||
|
return -- it's already added
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local reverseTable = {}
|
||||||
|
reverseTable.vars = globalTable.vars
|
||||||
|
reverseTable.sharedWith = currentPID
|
||||||
|
table.insert(_G.ipc.shared[pid],reverseTable) ]]
|
||||||
|
|
||||||
|
return shareTable
|
||||||
|
end
|
||||||
|
|
||||||
|
_PUBLIC.ipc.shared = {}
|
||||||
|
setmetatable(_PUBLIC.ipc.shared, {
|
||||||
|
["__index"] = function(_, pid)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
local returnTable = {}
|
||||||
|
for _, shareTable in pairs(ipc.shared[pid] or {}) do
|
||||||
|
if shareTable.sharedWith == currentPID then
|
||||||
|
for key, value in pairs(shareTable.vars) do
|
||||||
|
returnTable[key] = table.copy(value)
|
||||||
|
end
|
||||||
|
elseif shareTable.sharedWith == "all" then
|
||||||
|
for key, value in pairs(shareTable.vars) do
|
||||||
|
if not returnTable[key] then
|
||||||
|
returnTable[key] = table.copy(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return returnTable
|
||||||
|
end,
|
||||||
|
["__pairs"] = function()
|
||||||
|
local ftbl = {}
|
||||||
|
for i in pairs(_G.ipc.shared) do
|
||||||
|
ftbl[i] = _PUBLIC.ipc.shared[i]
|
||||||
|
end
|
||||||
|
return pairs(ftbl)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
_, checkProcess = _PUBLIC.tsched.addTask(function()
|
||||||
|
while true do
|
||||||
|
-- get all PIDs that exists
|
||||||
|
local tasks = _PUBLIC.tsched.getTasks()
|
||||||
|
local pids = {}
|
||||||
|
for _, v in pairs(tasks) do
|
||||||
|
table.insert(pids, v.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- get all shares from unexistant processes and delete them
|
||||||
|
for i in pairs(_G.ipc.shared) do
|
||||||
|
if not table.find(pids, i) then
|
||||||
|
_G.ipc.shared[i] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- let the other processes run
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end, "ipc")
|
||||||
end
|
end
|
||||||
|
|
||||||
function module.exit()
|
function module.exit()
|
||||||
|
_G.ipc = nil
|
||||||
|
_PUBLIC.ipc = nil
|
||||||
|
_PUBLIC.tsched.removeTask(checkProcess.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|||||||
@@ -136,6 +136,53 @@ function module.init()
|
|||||||
_PUBLIC.keyboard.keys.numpadenter = 0x9C
|
_PUBLIC.keyboard.keys.numpadenter = 0x9C
|
||||||
_PUBLIC.keyboard.keys.numpadequals = 0x8D
|
_PUBLIC.keyboard.keys.numpadequals = 0x8D
|
||||||
|
|
||||||
|
-- Separate list for special keys
|
||||||
|
_PUBLIC.keyboard.keys.special = {}
|
||||||
|
_PUBLIC.keyboard.keys.special.back = 0x0E -- backspace
|
||||||
|
_PUBLIC.keyboard.keys.special.capital = 0x3A -- capslock
|
||||||
|
_PUBLIC.keyboard.keys.special.enter = 0x1C
|
||||||
|
_PUBLIC.keyboard.keys.special.lcontrol = 0x1D
|
||||||
|
_PUBLIC.keyboard.keys.special.lmenu = 0x38 -- left Alt
|
||||||
|
_PUBLIC.keyboard.keys.special.lshift = 0x2A
|
||||||
|
_PUBLIC.keyboard.keys.special.rcontrol = 0x9D
|
||||||
|
_PUBLIC.keyboard.keys.special.rmenu = 0xB8 -- right Alt
|
||||||
|
_PUBLIC.keyboard.keys.special.rshift = 0x36
|
||||||
|
_PUBLIC.keyboard.keys.special.scroll = 0x46 -- Scroll Lock
|
||||||
|
_PUBLIC.keyboard.keys.special.stop = 0x95
|
||||||
|
|
||||||
|
_PUBLIC.keyboard.keys.special.up = 0xC8
|
||||||
|
_PUBLIC.keyboard.keys.special.down = 0xD0
|
||||||
|
_PUBLIC.keyboard.keys.special.left = 0xCB
|
||||||
|
_PUBLIC.keyboard.keys.special.right = 0xCD
|
||||||
|
_PUBLIC.keyboard.keys.special.home = 0xC7
|
||||||
|
_PUBLIC.keyboard.keys.special["end"] = 0xCF
|
||||||
|
_PUBLIC.keyboard.keys.special.pageUp = 0xC9
|
||||||
|
_PUBLIC.keyboard.keys.special.pageDown = 0xD1
|
||||||
|
_PUBLIC.keyboard.keys.special.insert = 0xD2
|
||||||
|
_PUBLIC.keyboard.keys.special.delete = 0xD3
|
||||||
|
|
||||||
|
_PUBLIC.keyboard.keys.special.f1 = 0x3B
|
||||||
|
_PUBLIC.keyboard.keys.special.f2 = 0x3C
|
||||||
|
_PUBLIC.keyboard.keys.special.f3 = 0x3D
|
||||||
|
_PUBLIC.keyboard.keys.special.f4 = 0x3E
|
||||||
|
_PUBLIC.keyboard.keys.special.f5 = 0x3F
|
||||||
|
_PUBLIC.keyboard.keys.special.f6 = 0x40
|
||||||
|
_PUBLIC.keyboard.keys.special.f7 = 0x41
|
||||||
|
_PUBLIC.keyboard.keys.special.f8 = 0x42
|
||||||
|
_PUBLIC.keyboard.keys.special.f9 = 0x43
|
||||||
|
_PUBLIC.keyboard.keys.special.f10 = 0x44
|
||||||
|
_PUBLIC.keyboard.keys.special.f11 = 0x57
|
||||||
|
_PUBLIC.keyboard.keys.special.f12 = 0x58
|
||||||
|
_PUBLIC.keyboard.keys.special.f13 = 0x64
|
||||||
|
_PUBLIC.keyboard.keys.special.f14 = 0x65
|
||||||
|
_PUBLIC.keyboard.keys.special.f15 = 0x66
|
||||||
|
_PUBLIC.keyboard.keys.special.f16 = 0x67
|
||||||
|
_PUBLIC.keyboard.keys.special.f17 = 0x68
|
||||||
|
_PUBLIC.keyboard.keys.special.f18 = 0x69
|
||||||
|
_PUBLIC.keyboard.keys.special.f19 = 0x71
|
||||||
|
|
||||||
|
_PUBLIC.keyboard.keys.special.numpadenter = 0x9C
|
||||||
|
|
||||||
-- Create inverse mapping for name lookup.
|
-- Create inverse mapping for name lookup.
|
||||||
setmetatable(_PUBLIC.keyboard.keys,
|
setmetatable(_PUBLIC.keyboard.keys,
|
||||||
{
|
{
|
||||||
@@ -148,6 +195,18 @@ function module.init()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setmetatable(_PUBLIC.keyboard.keys.special,
|
||||||
|
{
|
||||||
|
__index = function(tbl, k)
|
||||||
|
if type(k) ~= "number" then return end
|
||||||
|
for name,value in pairs(tbl) do
|
||||||
|
if value == k then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function module.exit()
|
function module.exit()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user