149 Commits

Author SHA1 Message Date
mcplayer3 8aa08814a1 Apparently I left in some unused variables that were supposed to be removed by Tema 2026-06-20 15:40:58 +03:00
mcplayer3 eaae852961 Started to add custom colour palettes
I have literally no idea why it wont work but if anyone picks this up you'll know it works when the old Halyde colours show up
2026-06-20 15:40:51 +03:00
tema5002 93c632ed6e unsuccessfull attempt at renaming terminal to io... 2026-06-20 14:30:26 +03:00
tema5002 ab48b57e1b Implement profiler 2026-06-20 14:25:40 +03:00
WahPlus 45a09284c2 bedit: Fixed addition of weird DC3 character when saving 2026-06-20 11:27:04 +03:00
mcplayer3 8fc249433b Added saving functionality to bedit
(The text field for the save path needs improving though.)
2026-06-20 17:14:21 +10:00
WahPlus 69a033f9a2 Added Gitea migration warning 2026-06-20 10:12:47 +03:00
WahPlus 11dea2b9e8 Changed README shield to say DokuWiki 2026-06-20 10:12:42 +03:00
WahPlus 393802b34e Added DokuWiki docs to README 2026-06-20 10:11:50 +03:00
mcplayer3 a3e0ec64ae cat now inserts a newline at the end of the file if there isn't one already 2026-06-19 15:03:45 +10:00
tema5002 9b9c005194 Fucking terminal 2026-06-18 16:52:17 +03:00
tema5002 81e832ef5d Merge branch 'unfinished-ag2' into Pre-Alpha-3.0.0 2026-06-18 16:38:51 +03:00
tema5002 6c356c7a13 Make the terminal suck less. 2026-06-17 21:44:52 +03:00
mcplayer3 14b25d59fc Added text editing functionality to bedit 2026-06-17 13:59:27 +10:00
mcplayer3 afe27f2b41 bedit: oops 2026-06-17 10:39:04 +10:00
WahPlus 317c0df9e8 component: Fixed #33 2026-06-15 19:37:48 +03:00
WahPlus b139e2da01 component: Fixed #34 2026-06-15 19:31:46 +03:00
WahPlus af61b8661a terminal: Fixed #73 2026-06-15 19:14:19 +03:00
WahPlus cb0f663f94 init: Fixed #71 2026-06-15 19:07:31 +03:00
mcplayer3 364dda8850 Copied special keys to a new table in the keyboard library 2026-06-09 14:36:37 +10:00
mcplayer3 d091dcad18 bedit: Prevented cursor moving past end of line 2026-06-08 18:01:33 +10:00
WahPlus 7453215c91 bedit: Cursor can now scroll 2026-06-08 10:23:10 +03:00
WahPlus 95befaa72b bedit: Cursor is now movable 2026-06-07 17:57:39 +03:00
WahPlus 399dd37b2d bedit: Added a cursor
Currently you can't move it
2026-06-07 13:15:02 +03:00
tema5002 0c197d758a Update .gitignore 2026-06-07 12:38:55 +03:00
tema5002 ac1e58abcf log.lua: Shouldn't assert on failed fs.open because this way it doesn't run on read only filesystem and really doesn't matter if it fails 2026-06-06 21:49:05 +03:00
tema5002 08af85f3b4 terminal.lua: Make 1st tier and 2nd tier GPU (or 2nd tier APU and 3rd tier APU) not suck 2026-06-06 21:38:32 +03:00
tema5002 4d6dbadc32 Make shit less ass fuck shit fuck ass shit ass bruh what is this code 2026-06-06 19:00:37 +03:00
WahPlus b756bc516e bedit: Added scrolling around the screen and basic event handling 2026-06-06 18:17:00 +03:00
WahPlus 16214c253d bedit: Added a little hotkey tooltip UI at the bottom 2026-06-06 17:51:36 +03:00
WahPlus 35e3a2313f bedit: Made it use VRAM buffer, added support for a custom offset 2026-06-06 17:35:25 +03:00
mcplayer3 f81e9089d3 Started making a better version of edit 2026-06-07 00:12:25 +10:00
mcplayer3 8c33ee0eb9 loadthething returns 2026-06-06 02:15:25 +10:00
WahPlus 202f6d42ac solvitdb: I am incredibly stupid 2026-05-31 09:44:21 +03:00
WahPlus 2b897106c5 solvitdb: Improved sanitize() function 2026-05-31 09:38:25 +03:00
Ponali cd5b71c110 solvit: made it run coroutine.yield() every 0.1s 2026-05-10 17:40:54 +02:00
Ponali e3464a920e solvit: added resolving code for different constant AVS conflict where the dependency is already installed 2026-05-10 16:50:49 +02:00
Ponali 137f8645fd solvit: added different constant AVS conflict error where the dependency is already installed
this time though there ACTUALLY needs resolving code here
2026-05-10 11:05:46 +02:00
Ponali 44f391253c solvit: made it return another error when trying to resolve different constant AVS conflict 2026-05-09 16:54:21 +02:00
Ponali 477d1de809 add different constant AVS conflict error
no resolving code yet though
2026-05-09 08:35:47 +02:00
WahPlus bf541b8b9d Finished modifying of packages 2026-05-06 21:15:40 +03:00
WahPlus 2bff0e749a Fixed SolvitDB's insert() function
It uses a temporary file like remove() now.
2026-05-06 19:10:30 +03:00
Ponali 60283fc40e solvit: added some support for constant versions 2026-05-03 19:06:06 +02:00
WahPlus f275247b00 Added versions to SolvitDB 2026-05-03 19:12:19 +03:00
WahPlus d84324c707 Added encoding package data to a string to solvitDB 2026-05-03 19:06:04 +03:00
Ponali 8dda210eb3 solvit: removing a reverse dependency from package removal now checks for that package's dependencies instead of every package 2026-05-03 17:46:11 +02:00
WahPlus 95b1c56d65 Made the list returned by solvitdb.list() iterable 2026-05-03 18:31:48 +03:00
WahPlus 56a849c1a8 Added solvitdb.list() 2026-05-03 18:29:26 +03:00
Ponali 233ad0598d solvit: added handling cascading when removing packages 2026-05-03 15:51:18 +02:00
Ponali 442e83c8e9 solvit: change solvitdb calls to account for file path API change 2026-05-03 15:19:08 +02:00
Ponali 5ea263e0bc solvit: added storing package removal 2026-05-03 15:05:42 +02:00
WahPlus e001c1b17e ACTUALLY added overwriting package data if it is the same length. Whoops. 2026-05-03 15:55:58 +03:00
WahPlus 4bc3a64a8c Added appending packages and overwriting package data if it is the same length 2026-05-03 15:51:21 +03:00
Ponali 82fc244209 Merge branch 'unfinished-ag2' of https://github.com/Team-Cerulean-Blue/Halyde into unfinished-ag2 2026-05-03 14:13:15 +02:00
Ponali 7bb4923bf0 solvit: implemented solving package removal (no reverse dependency conflict yet) 2026-05-03 14:10:01 +02:00
WahPlus 568b4d0b2c Small change to the filesystem library to allow using handle:seek() with no arguments to get the current position 2026-05-03 11:46:31 +03:00
Ponali 26a61c6e6c solvit: made version serializing reduce ranges that behave as one single version
it is possible that a range that gets generated could have the same exact version on both ends. if that happens, this small code will reduce it to one
2026-05-02 19:45:29 +02:00
Ponali b6cdae3408 solvit: added making and storing reverse dependencies to database 2026-05-02 19:31:58 +02:00
Ponali e8b6714b9a solvit can now do simple dependency solving for installing 2026-05-02 16:12:16 +02:00
Ponali 6f377c2bd5 solvit json substitution for db 2026-05-01 17:07:46 +02:00
WahPlus 4e837fc928 SolvitDB: added .svt file reading 2026-04-30 21:20:02 +03:00
Ponali 6688bbcaaf current and very unfinished state of solvit rn 2026-04-30 17:05:46 +02:00
WahPlus eb2e6b9596 Added functional package removal 2026-04-17 19:32:29 +03:00
WahPlus 2173713694 Added package deduplication and fixed a previously unnoticed bug with extending the package table mid-loop
See comments for more details
2026-03-28 06:50:26 +02:00
WahPlus c5b330ac9d Added commas to the packages that will be installed list 2026-03-27 19:25:23 +02:00
WahPlus 2d6dbe41a1 Made installing virtual packages actually work 2026-03-27 19:24:50 +02:00
WahPlus 65facb89f7 Added more test packages and removed test files from repo 2026-03-27 19:11:11 +02:00
WahPlus 647854b1da Added installing vpackages to Ag2
This was written entirely on my phone in Termux lol
2026-03-27 15:28:34 +02:00
WahPlus a7809384d9 Added group support when installing I guess 2026-03-22 19:58:21 +02:00
WahPlus 88f2a55ca0 Added support for dependency cascading, virtual packages, and groups when removing packages
IT'S NOT SPAGHETTI GUYS TRUST ME
2026-03-22 18:37:39 +02:00
WahPlus 3ab72fe1dd Added a check for if a package is already installed
Installing packages is now fully functional (aside from specific
versions)
2026-03-04 18:19:56 +02:00
WahPlus 1e9ba6c01a Made Argentum 2 create tracking files in /ag2/pkg
These files describe the package's name, version, files, directories,
config files, dependencies, conflicts and whether it is auto-installed
as a dependency or not.
2026-03-04 18:03:44 +02:00
WahPlus bca8830ead Added Kate swap files to gitignore 2026-03-04 17:45:11 +02:00
WahPlus 5feed553af I fucking can't anymore 2026-01-18 17:31:58 +02:00
WahPlus d24e00c308 Bugfix in terminal.lua
terminal.read() used to crash if no options were provided.
2025-11-01 08:42:04 +02:00
Ponali f5fcc84903 fixed the "user" kernel module getting the wrong IDs when creating tasks
when the user kernel module creates a task, it used to count the amount
of processes in the system, which can lead to some processes having the
same IDs as another, which causes havoc. this has been fixed by using
the ID counter in the tsched kernel module.
2025-10-30 17:48:16 +01:00
WahPlus 86f825d14b Add login script 2025-10-30 16:03:09 +02:00
WahPlus 3c99c26ea3 Remove useless GPU import in tsched 2025-10-30 16:02:40 +02:00
WahPlus fa1ef3926b Hey, Vsauce! Michael here. 2025-10-30 15:29:42 +02:00
WahPlus bef22740f6 Minor punctuation change in halyde/kernel/modules/user.lua 2025-10-30 15:20:19 +02:00
WahPlus 3e3e35860c Add text censoring to terminal.read() 2025-10-30 15:02:52 +02:00
WahPlus ad7596efee Removed unused get() function in halyde/kernel/modules/terminal.lua terminal.read() 2025-10-30 14:24:09 +02:00
WahPlus c4b6445c23 Improve variable naming in halyde/kernel/modules/terminal.lua terminal.read() 2025-10-30 14:21:02 +02:00
WahPlus ead5a09747 Comment on require() function in halyde/kernel/boot.lua
This is a pretty old bug by now.
2025-10-30 14:13:18 +02:00
WahPlus be2ddf1dd4 Make terminal.read() use a table for options
Also change all apps to work with this
2025-10-30 13:29:13 +02:00
WahPlus ca5d1114d2 Comment on halyde/apps/touch.lua 2025-10-30 13:28:06 +02:00
WahPlus c5418be165 Remove empty halyde/apps/resolution.lua 2025-10-30 13:25:20 +02:00
WahPlus f0c0acfcdc Comment on maindrv
Why does it exist?!
2025-10-30 13:24:41 +02:00
WahPlus ae1652b1b9 Rename /halyde/shell to /halyde/scripts
The reason is because there will have to be a place to put scripts that
are not apps.
2025-10-30 13:15:04 +02:00
WahPlus c1c6a50b09 Added user system.
Default users are `admin` (password `admin`, UID 1) and `user` (password
`user`, UID 2).
2025-10-28 19:15:20 +02:00
WahPlus 51124da54b Added wait() function. 2025-10-28 19:14:16 +02:00
WahPlus 8144d44deb Renamed lscor to lstsk.
Also added an alias from lscor to lstsk.
2025-10-28 19:13:54 +02:00
WahPlus 337f8af1df Made LuaLS ignore missing fields diagnostic.
LuaLS was complaining about the `package` table in `boot.lua` missing
certain fields. However, this is irrelevant for Halyde.
2025-10-28 17:06:28 +02:00
WahPlus 30b38ee0d9 Added MD5 library 2025-10-28 16:58:12 +02:00
mcplayer3 8548855d7f Fix log tool not printing some log entries 2025-10-21 20:34:06 +11:00
Ponali f1d69b51b2 added a keybind to the crash screen that reboots when the user presses enter/return
wow lazyvim likes reformatting everything
2025-10-20 18:37:42 +02:00
Ponali c9883c2c64 made all logs with multiple lines show up correctly
before this commit, all logs with multiple lines show up as one whole
string, where normally when a line would end and another would start, it
displays as two wide characters showing "[LF][HT]".
2025-10-20 18:17:01 +02:00
Ponali 668ed93491 made modload catch all errors emitted by modules 2025-10-20 17:38:43 +02:00
Ponali 8ab525b9ac made the lua app return the actual syntax error instead of "assertion failed!" 2025-10-20 13:32:05 +02:00
Ponali 245b6a524d made modload check for modules again when a component gets added or removed 2025-10-20 12:11:01 +02:00
Ponali 883f20f269 made events specific to processes
there also needs pending events for the kernel just in case if we ever
need them, but now i'm not sure if it's required
2025-10-18 16:56:46 +02:00
Ponali 61eea92fe0 the lua shell now catches errors dealt by libraries, and puts them on a log file
there's also lazyvim formatting everything, as usual
2025-10-18 11:25:38 +02:00
Ponali 26c1f055d8 made all logs from tsched start with [tsched]
i also converted some stuff to use string.format, and lazyvim also
reformatted them again
2025-10-15 19:03:49 +02:00
Ponali d771a1fe39 added a cleanup routine to IPC
there's also lazyvim reformatting everything, like usual
2025-10-15 18:34:33 +02:00
Ponali a020229a69 turned evmgr into a module
modules that require getting events will need to have "evmgr" as a
dependency
2025-10-15 13:52:28 +02:00
Ponali e1270d7bd7 fixed a bug in modload that lets modules get loaded twice through dependencies
if two modules contain a dependency to the same module, that dependency
will load *twice*, which shouldn't normally happen
2025-10-15 13:49:38 +02:00
Ponali f1877f6338 process crashes now output error logs 2025-10-12 10:05:39 +02:00
Ponali 61a7e3d139 TSCHED IS NOW A MODULE!!!!!!!!!!!! YIPEEEEEEEEEEEE 2025-10-12 09:02:40 +02:00
Ponali 8296127266 refactored tsched.lua with checkArgs and fail-safes 2025-10-11 18:51:42 +02:00
Ponali 62a2466c5e made modload more failsafe 2025-10-11 10:31:31 +02:00
Ponali 1798d63864 fixed filesystem erroring out when seeking while not buffered 2025-10-11 10:22:31 +02:00
Ponali 33f2573eb6 refactoring of halyde/kernel/boot.lua boot process 2025-10-11 09:14:02 +02:00
Your Name ea074a8f87 Add log tool
adds log tool for viewing logs
2025-10-06 21:43:03 +11:00
Your Name 4a9683a256 Added log tool 2025-10-06 17:48:22 +11:00
Ponali 296aba9a2f made fetch get the logo, instead of getting preloaded when booting 2025-10-05 08:09:14 +02:00
WahPlus 1d49683d3c Made the spacing a little nicer for the registry file. 2025-10-04 20:23:29 +03:00
WahPlus e0b6feb98c Made some formatting changes to lib/log.lua and disabled buffering when trimming the log.
The reason for this is that log files can get really large, and
buffering loads the whole file into the buffer. We devised an algorithm
to not use too much memory when trimming log files by NOT loading
everything into RAM, but buffering nullified it. It has now been
disabled.
2025-10-04 20:14:36 +03:00
Ponali d63941814f fix tsched crashing when a process gets removed
when a process removes another process, the amount of processes tsched
has decrements, but the for loop doesn't update. a check has been
implemented to check for when the task that's getting looked up doesn't
exist.
2025-10-04 18:36:57 +02:00
Ponali db01a8d741 added the touch app 2025-10-04 14:08:36 +02:00
Ponali a89953056b fix shell not appending current directory to PATH 2025-10-04 12:55:13 +02:00
Ponali 2c47a6df59 add the beep app 2025-10-04 08:40:31 +02:00
WahPlus 943f1020fa Added the new registry.json in preparation for Argentum 2 2025-09-30 21:22:09 +03:00
WahPlus 3d9ec665b9 Added component.isAvailable()
The function checks if a component of a specified type exists.
2025-09-30 21:15:19 +03:00
WahPlus 9c0e33c116 Removed .editorconfig from .gitignore 2025-09-30 20:29:50 +03:00
WahPlus cd3dd80c23 Made event.pull() with a timeout of 0 not yield.
This makes sense because if the timeout is 0, the app calling it
obviously just wants to fetch any pending events and not wait.
2025-09-30 15:26:35 +03:00
WahPlus 58c8ce3f2d Modified gitignore
Modified gitignore to ignore .editorconfig files
2025-09-28 17:55:41 +03:00
WahPlus de5d779d9a Patched a bug with require
If there was a folder in root with the same name as a library, requiring
that library would cause the require function to error. This has now
been fixed.
2025-09-28 16:04:25 +03:00
Ponali 0ca8cfeeeb made halyde crashes make a log entry
it also shows when it can't make said log entry
2025-09-27 13:37:46 +02:00
Ponali 0c604a5870 added horizontal scrolling
yeah, this re-renders all the lines, but it gets the job done
2025-09-26 19:19:17 +02:00
WahPlus c83fe8a7f4 ACTUALLY fix the issue 2025-09-25 08:48:31 +03:00
WahPlus f28812205e Made log.lua make the halyde/logs directory if it's not present 2025-09-25 08:37:52 +03:00
Ponali 2f512b5e99 added vertical scrolling 2025-09-25 06:52:14 +02:00
Ponali 732f747347 fix error text peeking through the scroll text
lazyvim also changed the indentation of everything for some reason
i don't know what's the name for "scroll text"
2025-09-25 06:52:14 +02:00
WahPlus 99725b43ba Added CLI parser library
This library can easily process flags, arguments, and flags with
arguments.
2025-09-24 21:29:34 +03:00
mcplayer3 ad0f2197a3 Add resolution command (#40) 2025-09-23 12:34:00 +03:00
Ponali cf26f610b4 made stuff more verbose
and also fixed modload using an outdated variant of the log library
2025-09-21 18:41:41 +02:00
WahPlus 39897457f9 Added log printing on the screen on startup.
The log library now prints all the logs on startup.
2025-09-17 20:54:56 +03:00
Ponali 87d0e6bbcb made the lua app preload libraries and indicate how much time was spent loading them
the lua shell (or lua app) before this update was loading all the system
libraries for every command, which makes them slower to actually start
running (about 1.5s of delay). in this update, lua starts loading all
the libraries when the shell starts.
2025-09-16 19:24:02 +02:00
WahPlus 8b51217324 Made filesystem seeking more failsafe and added better log trimming.
- Trying to seek before the start of a file stream now does not cause an
error
- Logs are now trimmed between log entries
2025-09-16 19:36:41 +03:00
Ponali 894641734f FUUUUCK I FORGOT TO PUSH THE SHELL LIBRARY 2025-09-15 17:38:08 +02:00
WahPlus 90252f83f1 Set Git to ignore logs
Added the /halyde/logs/ directory to .gitignore.
2025-09-15 16:17:49 +03:00
WahPlus 0b2745ab9c Merge branch 'Pre-Alpha-3.0.0' of https://github.com/Team-Cerulean-Blue/Halyde into Pre-Alpha-3.0.0 2025-09-15 08:14:39 +03:00
WahPlus 099fbee8c6 Added logging system, fixed filesystem read handle buffering and added read handle seeking. 2025-09-15 08:10:50 +03:00
Ponali 66783e455c ported apps lscor, mv, and rm
there's partially rtest too, if you count that
2025-09-15 07:08:19 +02:00
Ponali ff04e730f9 ported apps download/wget, fetch, label, and lscor/ps
for the fetch app to fully work, defenv has been edited to share _OSLOGO.
2025-09-14 18:46:26 +02:00
Ponali 3c087aaddf added handling invalid invoke functions and ported a couple of apps
stopped component.invoke from throwing a cryptic error, and ported over cat, cd, clear, cp, edit, ls, lsdrv, and mkdir
2025-09-14 17:45:36 +02:00
Ponali 8244f1590c added feature for checking if a component is virtual, and updated apps argentum and boot to comply with Halyde v3 2025-09-14 16:28:15 +02:00
Ponali d3d5f21ab1 lots and LOTS of stuff
i lost track sorry
2025-09-14 13:37:41 +02:00
WahPlus ef0ffa1886 ALPHA 3.0.0 - Added Inter-Process Communication and fixed the bug where the shell would continue taking in input when a command was still running. 2025-08-21 21:03:17 +03:00
121 changed files with 5736 additions and 1433 deletions
+3
View File
@@ -0,0 +1,3 @@
[*.lua]
indent_style = space
indent_size = 2
+5
View File
@@ -0,0 +1,5 @@
.stfolder
.idea
home/*
halyde/logs/*
*.kate-swp
+2 -1
View File
@@ -14,7 +14,8 @@
"diagnostics": {
"disable": [
"undefined-global",
"lowercase-global"
"lowercase-global",
"missing-fields"
],
"globals": [
"_G",
+5 -3
View File
@@ -1,4 +1,6 @@
# 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.
<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>
<a href="https://ocdoc.cil.li/">
<img src="https://img.shields.io/badge/Made_for-OpenComputers-yellow?style=plastic" /></a>
<a href="https://cerulean-blue.gitbook.io/halyde-docs">
<img src="https://img.shields.io/badge/Documented_on-GitBook-green?style=plastic&logo=gitbook" /></a>
<a href="https://wiki.sting.lt/">
<img src="https://img.shields.io/badge/Documented_on-DokuWiki-green?style=plastic" /></a>
</p>
## 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`
## 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/).
+9
View File
@@ -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/"
}
+5 -1
View File
@@ -1,3 +1,4 @@
local agregistry = {
["halyde"] = "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/",
["utape"] = "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
+520
View File
@@ -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
View File
@@ -1,6 +1,6 @@
local packages = {...}
local command = packages[1]
table.remove(packages, 1)
local command = table.remove(packages,1)
local shell = require("shell")
local fs = require("filesystem")
local component = require("component")
local agReg = require("/argentum/registry.cfg")
@@ -9,7 +9,7 @@ if not command then
return
end
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
end
local internet = component.internet
@@ -69,12 +69,12 @@ local function getAgConfig(package, source)
source = source or agReg[package]
local data, errorMessage = getFile(source .. "argentum.cfg")
if not data or data == "" then
print("\27[91mCould not fetch Ag config: " .. (errorMessage or "returned nil data"))
print("\27[91mCould not fetch Ag config: " .. (errorMessage or "returned nil data") .. "\27[0m")
return false
end
local func, errorMessage = load(data, "=argentum.cfg", "bt", {})
if not func then
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.\27[0m")
return false
end
local agcfg
@@ -82,22 +82,22 @@ local function getAgConfig(package, source)
agcfg = func()
end)
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
end
if not agcfg[package] or not agcfg[package].maindir or not agcfg[package].directories or not agcfg[package].files or not agcfg[package].version then
local response = ("\27[91mAg config of " .. package .. " is improperly configured.\nPlease contact the package owner.")
local response = "\27[91mAg config of " .. package .. " is improperly configured.\nPlease contact the package owner.\27[0m"
end
return agcfg
end
local function doChecks(package)
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
end
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
end
agcfg = getAgConfig(package, source)
@@ -107,7 +107,7 @@ local function doChecks(package)
if agcfg[package].dependencies then
for _, dependency in ipairs(agcfg[package].dependencies) do
if not agReg[dependency] and not agcfg[dependency] then
local response = read(nil, "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]")
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
fs.remove("/argentum/store/" .. package)
return false
@@ -132,24 +132,21 @@ local function lpad(str, len, char)
return string.rep(char, len - #str) .. str
end
local gpu = component.gpu
local width,height = gpu.getResolution()
local function progress(package,progress)
local info = string.format("%s %s%%",package,lpad(math.floor(progress*100),2))
local width, height = terminal.getResolution()
info=info..string.rep(" ",width-#info)
local progX = math.floor(progress*width)
gpu.setBackground(0x00FF00)
gpu.setForeground(0x000000)
gpu.set(1,height,info:sub(1,progX))
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.set(progX+1,height,info:sub(progX+1))
local function progress(package, progress)
terminal.write("\x1b[s")
local info = string.format("%s %s%%", package, lpad(math.floor(progress * 100), 2))
info = info .. string.rep(" ", width - #info)
local progX = math.floor(progress * width)
terminal.write("\x1b[42m\x1b[30m" .. info:sub(1, progX) .. "\x1b[40m\x1b[37m" .. info:sub(progX + 1) .. "\x1b[0m")
terminal.write("\x1b[u")
end
local function clearProgress()
gpu.setBackground(0x000000)
gpu.fill(1,height,width,1," ")
terminal.write("\x1b[s")
terminal.write("\r\x1b[40m" .. string.rep(" ", width) .. "\x1b[0m\r")
terminal.write("\x1b[u")
end
local function installPackage(package, overwriteFlag)
@@ -166,7 +163,7 @@ local function installPackage(package, overwriteFlag)
if agcfg[package].dependencies then
for _, dependency in ipairs(agcfg[package].dependencies) do
if not agReg[dependency] and not agcfg[dependency] then
local response = read(nil, "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]")
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
fs.remove("/argentum/store/" .. package)
return false
@@ -199,7 +196,7 @@ local function installPackage(package, overwriteFlag)
local data, errorMessage = getFile(source .. agcfg[package].maindir .. file)
if not data then
clearProgress()
local response = read(nil, "\27[91mCould not fetch " .. file .. ": " .. errorMessage .. "\n\27[0m[a - Abort/R - Retry/s - Skip]")
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
fs.remove("/argentum/store/" .. package)
return false
@@ -218,7 +215,7 @@ local function installPackage(package, overwriteFlag)
else
packageStore = packageStore .. "\nA" .. file
end
local handle = fs.open(file, "w")
local handle, err = fs.open(file, "w")
handle:write(data)
handle:close()
::skip::
@@ -234,7 +231,7 @@ end
local function removePackage(package)
print("Removing " .. package .. "...")
if not fs.exists("/argentum/store/" .. package .. "/package.cfg") then
print("\27[91mLocal Ag config of " .. package .. " does not exist.")
print("\27[91mLocal Ag config of " .. package .. " does not exist.\27[0m")
return false
end
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))
if not result then
clearProgress()
local response = read(nil, "\27[91mFailed to remove " .. line:sub(2) .. ": " .. errorMessage .. "\n\27[0m[a - Abort/r - Retry/S - Skip]")
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
return false
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
if not handle then
clearProgress()
local response = read(nil, "\27[91mFailed to revert " .. line:sub(2) .. ": " .. data .. "\n\27[0m[a - Abort/R - Retry/s - Skip]") -- this is pretty stupid but i think the error message would get pushed to data
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
return false
elseif response:lower() == "s" then
@@ -344,7 +341,7 @@ if command == "install" then
handle:write(newRegistry)
handle:close()
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
agReg = require("/argentum/registry.cfg")
while true do
@@ -360,7 +357,7 @@ if command == "install" then
local answer
if #fails == 0 then
print("Packages that will be installed: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
if terminal.read({prefix = "Would you like to proceed? [Y/n] "}):lower() == "n" then
return
end
elseif #packageList == 0 then
@@ -370,7 +367,7 @@ if command == "install" then
print("Some packages cannot be installed.")
print("Packages that will be installed: " .. table.concat(packageList, ", "))
print("Packages that cannot be installed: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
if terminal.read({prefix = "Would you like to proceed? [y/N] "}):lower() ~= "y" then
return
end
end
@@ -402,19 +399,19 @@ elseif command == "remove" then
end
while true do
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.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
elseif packages[i] == "halyde" then -- yes, this stuff is hard-coded.
print("\27[91mFor obvious reasons, you can't uninstall Halyde.")
print("\27[91mFor obvious reasons, you can't uninstall Halyde.\27[0m")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
elseif packages[i] == "argentum" then
print("\27[91mFor obvious reasons, you can't uninstall Argentum.")
print("\27[91mFor obvious reasons, you can't uninstall Argentum.\27[0m")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
@@ -452,7 +449,7 @@ elseif command == "remove" then
local answer
if #fails == 0 then
print("Packages that will be removed: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
if terminal.read({prefix = "Would you like to proceed? [Y/n] "}):lower() == "n" then
return
end
elseif #packageList == 0 then
@@ -462,7 +459,7 @@ elseif command == "remove" then
print("Some packages cannot be removed.")
print("Packages that will be removed: " .. table.concat(packageList, ", "))
print("Packages that cannot be removed: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
if terminal.read({prefix = "Would you like to proceed? [y/N] "}):lower() ~= "y" then
return
end
end
@@ -495,7 +492,7 @@ elseif command == "update" then
handle:write(newRegistry)
handle:close()
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
agReg = require("/argentum/registry.cfg")
if not packages[1] then
@@ -541,7 +538,7 @@ elseif command == "update" then
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
else
print(packages[i].." is out of date [\x1b[93m"..version.."\x1b[39m < \x1b[92m"..agcfg[packages[i]].version.."\x1b[39m]")
print(packages[i].." is out of date [\x1b[93m"..version.."\x1b[0m < \x1b[92m"..agcfg[packages[i]].version.."\x1b[0m")
end
end
i = i + 1
@@ -560,14 +557,14 @@ elseif command == "update" then
end
elseif #fails == 0 then
print("Packages that will be updated: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
if terminal.read({prefix = "Would you like to proceed? [Y/n] "}):lower() == "n" then
return
end
else
print("Some packages cannot be updated.")
print("Packages that will be updated: " .. table.concat(packageList, ", "))
print("Packages that cannot be updated: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
if terminal.read({prefix = "Would you like to proceed? [y/N] "}):lower() ~= "y" then
return
end
end
@@ -630,7 +627,7 @@ elseif command == "info" then
handle:write(newRegistry)
handle:close()
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
agReg = require("/argentum/registry.cfg")
if not agReg[packages[1]] and not source then
@@ -677,7 +674,7 @@ elseif command == "list" then
handle:write(newRegistry)
handle:close()
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
agReg = require("/argentum/registry.cfg")
local sortedPackages = {}
+334
View File
@@ -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()
+19
View File
@@ -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)
+7 -7
View File
@@ -34,27 +34,27 @@ if type(args[1])=="string" then
local compID,err = getComponentID(args[1])
if not compID then
print("\x1b[91mCould not get component ID from '"..args[1].."'.")
if type(err)=="string" then print("\x1b[91m"..err) end
if type(err)=="string" then print("\x1b[91m"..err.."\x1b[0m") end
return
end
if not force then
if componentlib.additions[compID] then
return print("\x1b[91mThis component is virtual and cannot be booted from directly.\nID: "..compID)
if component.virtual.check(compID) then
return print("\x1b[91mThis component is virtual and cannot be booted from directly.\nID: "..compID.."\x1b[0m")
end
local type = component.type(compID)
if type~="filesystem" and type~="drive" then
return print("\x1b[91mThis component is not a storage medium.\nID: "..compID)
return print("\x1b[91mThis component is not a storage medium.\nID: "..compID.."\x1b[0m")
end
if type=="filesystem" and not fileExists(compID,"/init.lua") then
return print("\x1b[91mThis storage medium doesn't have an \"init.lua\" file.\nID: "..compID)
return print("\x1b[91mThis storage medium doesn't have an \"init.lua\" file.\nID: "..compID.."\x1b[0m")
end
end
computer.setBootAddress(compID)
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
computer.shutdown(true)
else
shell.run("help boot")
require("shell").run("help boot")
end
+26 -16
View File
@@ -1,20 +1,30 @@
local files = {...}
local fs = require("filesystem")
if not files or not files[1] then
shell.run("help cat")
return
local shell = require("shell")
local args = {...}
if not args[1] then
return shell.run("help cat")
end
for _, file in ipairs(files) do
if file:sub(1, 1) ~= "/" then
file = fs.concat(shell.workingDirectory, file)
end
if not fs.exists(file) then
print("\27[91mFile does not exist.")
end
for _, file in pairs(args) do
file = shell.resolvePath(file)
local handle = fs.open(file, "r")
local data
repeat
data = handle:read(math.huge or math.maxinteger)
termlib.write(data)
until not data
if handle == nil then
terminal.write("\27[91mCan't open " .. file .. "\27[0m\n")
goto continue
end
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
+21 -9
View File
@@ -1,14 +1,26 @@
local directory = ...
local fs = require("filesystem")
local args = {...}
if not directory then
if args[2] then
terminal.write("\27[91mToo many arguments.\27[0m")
end
if not args[1] then
return
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
if fs.exists(directory) and fs.isDirectory(directory) then
shell.workingDirectory = fs.canonical(directory)
else
print("\27[91mNo such directory.")
if not fs.isDirectory(directory) then
terminal.write("\27[91mError: " .. directory .. ": Not a directory\27[0m\n")
return
end
shell.setWorkingDirectory(fs.canonical(directory))
+2 -1
View File
@@ -1,2 +1,3 @@
clear()
terminal.clear()
-- truly so much going on here
-- meow
+62 -18
View File
@@ -1,26 +1,70 @@
local fromFile, toFile = ...
local fs = require("filesystem")
local shell = require("shell")
if not fromFile or not toFile then
shell.run("help cp")
local args = {...}
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
end
if fromFile:sub(1, 1) ~= "/" then
fromFile = fs.concat(shell.workingDirectory, fromFile)
end
if toFile:sub(1, 1) ~= "/" then
toFile = fs.concat(shell.workingDirectory, toFile)
end
if fromFile == toFile then
print("\27[91mSource and destination are the same.")
local dest = shell.resolvePath(args[#args])
if fs.isFile(dest) then
if #args ~= 2 then
terminal.write("\27[91mError: Destination is not a directory\27[0m\n")
return
end
if not fs.exists(fromFile) then
print("\27[91mSource file does not exist.")
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.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.")
end
if fs.isDirectory(src) then
terminal.write("\27[91mError: Cannot write directory " .. src .. " to file " .. dest .. "\27[0m\n")
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
fs.copy(fromFile, toFile)
+7 -7
View File
@@ -4,13 +4,13 @@ local component = require("component")
local fs = require("filesystem")
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
end
if not url then
print("Please enter a URL to download from.")
shell.run("help download")
require("shell").run("help download")
return
end
@@ -26,11 +26,11 @@ local status, errorMessage = pcall(function()
request:finishConnect()
end)
if not status then
print("\27[91mDownload failed: " .. errorMessage)
print("\27[91mDownload failed: " .. errorMessage .. "\27[0m")
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
print("\27[91mDownload failed: " .. tostring(responseCode))
print("\27[91mDownload failed: " .. tostring(responseCode) .. "\27[0m")
end
repeat
tmpdata = request.read(math.huge)
@@ -39,11 +39,11 @@ until not tmpdata
local saveLocation
local saveLocationOK = false
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
print("\27[91mThe specified location is a directory.")
print("\27[91mThe specified location is a directory.\27[0m")
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
saveLocationOK = true
end
+12 -15
View File
@@ -3,6 +3,7 @@ local fs = require("filesystem")
local event = require("event")
local component = require("component")
local unicode = require("unicode")
local workingDirectory = require("shell").getWorkingDirectory()
local gpu = component.gpu
local width, height = gpu.getResolution()
local scrollPosX, scrollPosY = 1, 1
@@ -15,9 +16,7 @@ local tab = " "
--local ocelot = component.ocelot
local function rawset(x, y, text)
termlib.cursorPosX = x
termlib.cursorPosY = y
termlib.write(text, false)
terminal.write("\x1b[".. tostring(y) .. ";" .. tostring(x) .. "H" .. text)
end
local filestring, filepath, handle, data, tmpdata
@@ -25,7 +24,7 @@ if file then
if file:sub(1, 1) == "/" then
filepath = file
else
filepath = shell.workingDirectory .. file
filepath = workingDirectory .. file
end
handle, data, tmpdata = fs.open(filepath, "r"), "", nil
if fs.exists(filepath) then
@@ -44,7 +43,7 @@ if file then
tmpdata = {data}
end
else
filepath = shell.workingDirectory .. file
filepath = workingDirectory .. file
filestring = "[NEW FILE]"
tmpdata = {""}
end
@@ -55,7 +54,7 @@ else
end
local function render()
gpu.setActiveBuffer(renderBuffer)
clear()
terminal.clear()
--ocelot.log(tostring(scrollPosY))
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY + scrollPosY - 1]) - scrollPosX + 2)
if realCursorX < 1 then
@@ -152,7 +151,7 @@ local function processEvent(args)
if args[1] == "key_down" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if keyboard.ctrlDown then
if keyboard.getCtrlDown() then
return false, false, key
end
if key == "down" and cursorPosY < #tmpdata then
@@ -261,14 +260,13 @@ local function save()
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
gpu.set(1, height - 1, string.rep(" ", width))
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local savepath = read(nil, "\27[107m\27[30mSave location: ", filepath)
rawset(1, height - 1)
local savepath = terminal.read({prefix = "\27[107m\27[30mSave location: ", defaultText = filepath})
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
if fs.exists(savepath) then
gpu.set(1, height - 1, string.rep(" ", width))
local answer = read(nil, "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] ")
local answer = terminal.read({prefix = "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] "})
if answer:lower() == "n" then
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0)
@@ -301,15 +299,14 @@ while true do
renderFlag, cursorRenderFlag, specialKey = processEvent(args)
if specialKey == "x" then
if changesMade then
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local response = read(nil, "\27[107m\27[30mWould you like to save changes? [Y/n] ")
rawset(1, height - 1)
local response = terminal.read({prefix = "\27[107m\27[30mWould you like to save changes? [Y/n] "})
if response:lower() ~= "n" then
save()
end
end
gpu.freeAllBuffers()
clear()
terminal.clear()
return
end
if specialKey == "s" then
+50 -54
View File
@@ -1,70 +1,66 @@
local component = require("component")
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)
terminal.cursorPosX = 35
terminal.write(text .. "\n", false)
terminal.write("\27[35G" .. text .. "\n")
end
terminal.write(_OSLOGO, false)
terminal.cursorPosY = terminal.cursorPosY - 17
printstat("\27[92mOS\27[0m: ".._OSVERSION)
printstat("\27[92mArchitecture\27[0m: ".._VERSION)
local logo = ""
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
repeat
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
for _, _ in component.list() do
for _ in component.list() do
componentCounter = componentCounter + 1
end
printstat("\27[92mComponents\27[0m: "..tostring(componentCounter))
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[92mComponents\27[0m: " .. tostring(componentCounter))
printstat("\27[92mCoroutines\27[0m: " .. tostring(#tsched.getTasks()))
printstat("\27[92mBattery\27[0m: " .. tostring(math.floor(computer.energy() / computer.maxEnergy() * 1000 + 0.5) / 10) .. "%")
local totalMemory = computer.totalMemory()
local usedMemory = computer.totalMemory() - computer.freeMemory()
local totalMemoryString
if convert(totalMemory, "B", "GiB") >= 1 then
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(totalMemory, "B", "MiB") >= 1 then
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(totalMemory, "B", "KiB") >= 1 then
totalMemoryString = tostring(math.floor(convert(totalMemory, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
totalMemoryString = tostring(totalMemory) .. " B"
local function formatBytes(bytes)
if convert(bytes, "B", "GiB") >= 1 then
return tostring(math.floor(convert(bytes, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(bytes, "B", "MiB") >= 1 then
return tostring(math.floor(convert(bytes, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(bytes, "B", "KiB") >= 1 then
return tostring(math.floor(convert(bytes, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
return tostring(bytes) .. " B"
end
end
local usedMemoryString
if convert(usedMemory, "B", "GiB") >= 1 then
usedMemoryString = tostring(math.floor(convert(usedMemory, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(usedMemory, "B", "MiB") >= 1 then
usedMemoryString = tostring(math.floor(convert(usedMemory, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(usedMemory, "B", "KiB") >= 1 then
usedMemoryString = tostring(math.floor(convert(usedMemory, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
usedMemoryString = tostring(usedMemory) .. " B"
end
printstat("\27[92mMemory\27[0m: "..usedMemoryString.." / "..totalMemoryString)
printstat("\27[92mMemory\27[0m: " .. formatBytes(usedMemory) .. " / " .. formatBytes(totalMemory))
local totalDisk = component.invoke(computer.getBootAddress(), "spaceTotal")
local usedDisk = component.invoke(computer.getBootAddress(), "spaceUsed")
local totalDiskString
if convert(totalDisk, "B", "GiB") >= 1 then
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(totalDisk, "B", "MiB") >= 1 then
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(totalDisk, "B", "KiB") >= 1 then
totalDiskString = tostring(math.floor(convert(totalDisk, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
totalDiskString = tostring(totalDisk) .. " B"
end
local usedDiskString
if convert(usedDisk, "B", "GiB") >= 1 then
usedDiskString = tostring(math.floor(convert(usedDisk, "B", "GiB") * 100 + 0.5) / 100) .. " GiB"
elseif convert(usedDisk, "B", "MiB") >= 1 then
usedDiskString = tostring(math.floor(convert(usedDisk, "B", "MiB") * 100 + 0.5) / 100) .. " MiB"
elseif convert(usedDisk, "B", "KiB") >= 1 then
usedDiskString = tostring(math.floor(convert(usedDisk, "B", "KiB") * 100 + 0.5) / 100) .. " KiB"
else
usedDiskString = tostring(usedDisk) .. " B"
end
printstat("\27[92mDisk\27[0m: "..usedDiskString.." / "..totalDiskString)
local width, height = component.invoke(component.list("gpu")(), "getResolution")
printstat("\27[92mResolution\27[0m: "..tostring(width).."x"..tostring(height).."\n")
printstat("\27[92mDisk\27[0m: " .. formatBytes(usedDisk) .. " / " .. formatBytes(totalDisk))
local gpuComponent = component.list("gpu")()
local width, height = component.invoke(gpuComponent, "getResolution")
printstat("\27[92mResolution\27[0m: " .. tostring(width) .. "x" .. tostring(height) .. "\n")
printstat("\27[40m \27[41m \27[42m \27[43m \27[44m \27[45m \27[46m \27[47m ")
printstat("\27[100m \27[101m \27[102m \27[103m \27[104m \27[105m \27[106m \27[107m ")
terminal.cursorPosY = terminal.cursorPosY + 5
terminal.write("\27[5B\27[0m")
+261 -31
View File
@@ -1,38 +1,268 @@
local fs = require("filesystem")
local args = {...}
local command = args[1]
args = nil
if not command then
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/default.txt", "r"), "", nil
repeat
tmpdata = handle:read(math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
print(data)
local shell = require("shell")
local arg = ... or "default"
local what = arg
local aliases = shell.getAliases()
if aliases[what] then
what = aliases[what]
end
local path = "/halyde/apps/helpdb/" .. what
if not fs.exists(path) then
print("Could not find help file for: " .. arg .. ".")
return
end
if shell.aliases[command] then
command = shell.aliases[command]
if path == "/halyde/apps/helpdb/default" then
return shell.run("cat " .. path) -- smh
end
if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/" .. command .. ".txt", "r"), "", nil
repeat
tmpdata = handle:read(math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
print(data)
local aliases = table.copy(shell.aliases)
if table.find(aliases, command) then
local aliasIndex = table.find(aliases, command)
local aliasString = "Aliases:\n " .. aliasIndex
aliases[aliasIndex] = nil
while table.find(aliases, command) do
aliasIndex = table.find(aliases, command)
aliasString = aliasString .. ", " .. aliasIndex
aliases[aliasIndex] = nil
local handle = fs.open(path, "r")
local data = {
command = "",
usage = "",
description = "",
args = {},
examples = {}
}
while true do
local line = ""
while true do
local char = handle:read(1)
if not char then
if line == "" then
line = nil
break
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
else
print("Could not find help file for: " .. command .. ".")
end
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
+47
View File
@@ -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.
+29
View File
@@ -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.
-18
View File
@@ -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.
+8
View File
@@ -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.
+23
View File
@@ -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.
-15
View File
@@ -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.
+9
View File
@@ -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.
-8
View File
@@ -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.
+13
View File
@@ -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 ..".
-10
View File
@@ -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 ..".
+4
View File
@@ -0,0 +1,4 @@
COMMAND clear
DESCRIPTION Clears the screen.
EXAMPLE1 clear
EXAMPLE1DESCRIPTION Clears the screen.
-5
View File
@@ -1,5 +0,0 @@
Usage: clear
Clears the screen.
Examples:
clear Clears the screen.
+11
View File
@@ -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.
-11
View File
@@ -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.
+28
View File
@@ -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.
-25
View File
@@ -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.
+7
View File
@@ -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.
-7
View File
@@ -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.
+9
View File
@@ -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.
-8
View File
@@ -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.
+9
View File
@@ -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.
-8
View File
@@ -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.
+4
View File
@@ -0,0 +1,4 @@
COMMAND fetch
DESCRIPTION Displays system information including OS version, Lua version, memory, etc.
EXAMPLE1 fetch
EXAMPLE1DESCRIPTION Displays system information.
-5
View File
@@ -1,5 +0,0 @@
Usage: fetch
Displays system information including OS version, Lua version, memory, etc.
Examples:
fetch Displays system information.
+9
View File
@@ -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.
-8
View File
@@ -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.
+24
View File
@@ -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"
-16
View File
@@ -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"
+19
View File
@@ -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.
+11
View File
@@ -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 yellow, executable files are shown in green, 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.
-10
View File
@@ -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 yellow, executable files are shown in green, 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.
+4
View File
@@ -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.
-5
View File
@@ -1,5 +0,0 @@
Usage: lscor
Lists every active coroutine by ID and name.
Examples:
lscor Lists every active coroutine by ID and name.
+37
View File
@@ -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.
-27
View File
@@ -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.
+4
View File
@@ -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.
-5
View File
@@ -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.
+2
View File
@@ -0,0 +1,2 @@
COMMAND maindrv
DESCRIPTION Shows the entire ID of the drive where Halyde is installed to.
-2
View File
@@ -1,2 +0,0 @@
Usage: maindrv
Shows the entire ID of the drive where Halyde is installed to.
+7
View File
@@ -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.
-7
View File
@@ -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.
+11
View File
@@ -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.
-11
View File
@@ -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.
+4
View File
@@ -0,0 +1,4 @@
COMMAND reboot
DESCRIPTION Reboots the computer.
EXAMPLE1 reboot
EXAMPLE1DESCRIPTION Reboots the computer.
-5
View File
@@ -1,5 +0,0 @@
Usage: reboot
Reboots the computer.
Examples:
reboot Reboots the computer.
+11
View File
@@ -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.
+7
View File
@@ -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.
-7
View File
@@ -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.
+4
View File
@@ -0,0 +1,4 @@
COMMAND shutdown
DESCRIPTION Shuts down the computer.
EXAMPLE1 shutdown
EXAMPLE1DESCRIPTION Shuts down the computer.
-5
View File
@@ -1,5 +0,0 @@
Usage: shutdown
Shuts down the computer.
Examples:
shutdown Shuts down the computer.
+5
View File
@@ -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
View File
@@ -1,9 +1,9 @@
local component = require("component")
local computer = require("computer")
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
return shell.run("help label")
return require("shell").run("help label")
end
local inputID = args[1]
local comp
@@ -29,27 +29,27 @@ elseif inputID:sub(1,1)=="#" and tonumber(inputID:sub(2)) then
componentFromSlot(slotNum)
elseif #inputID>=3 then
local fullID = component.get(inputID)
if not fullID then return print("\x1b[91mCould not find entire component ID from \""..inputID.."\".") end
if not fullID then return print("\x1b[91mCould not find entire component ID from \""..inputID.."\".\x1b[0m") end
comp = component.proxy(fullID)
else
print("\x1b[91mAddress must have atleast 3 characters")
return shell.run("help label")
print("\x1b[91mAddress must have atleast 3 characters\x1b[0m")
return require("shell").run("help label")
end
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
local compID = comp.address
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
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
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
local function formatLabel(label)
@@ -67,7 +67,7 @@ if type(args[2])~="string" then
label = comp.getLabel()
end)
if success then
print("Label of "..formatID(compID)..((comp.type and comp.type~="filesystem") and " ("..comp.type..")" or "")..":\n \x1b[92m"..formatLabel(label).."\x1b[39m")
print("Label of "..formatID(compID)..((comp.type and comp.type~="filesystem") and " ("..comp.type..")" or "")..":\n \x1b[92m"..formatLabel(label).."\x1b[0m")
else
compError("getting",reason)
end
@@ -85,7 +85,7 @@ else
label = comp.setLabel(newLabel)
end)
if success then
print("Successfully set label of "..formatID(compID)..(comp.type and " ("..comp.type..")" or "").." to:\n \x1b[92m"..formatLabel(label).."\x1b[39m")
print("Successfully set label of "..formatID(compID)..(comp.type and " ("..comp.type..")" or "").." to:\n \x1b[92m"..formatLabel(label).."\x1b[0m")
else
compError("setting",reason)
end
+110
View File
@@ -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
View File
@@ -1,70 +1,58 @@
local args = {...}
local target = args[1]
args = nil
local fs = require("filesystem")
local unicode = require("unicode")
local maxLength = 0
local margin = 2 -- minimum space between filename and size
local dirTable = {}
local fileTable = {}
local shell = require("shell")
if target then
if target:sub(1, 1) ~= "/" then
target = fs.concat(shell.workingDirectory, target)
end
else
target = shell.workingDirectory
local function formatSize(size, isDir)
if isDir then return "[DIR]" end
if size >= 1024^3 then return string.format("%.1fGiB", size / 1024^3) end
if size >= 1024^2 then return string.format("%.1fMiB", size / 1024^2) end
if size >= 1024 then return string.format("%.1fKiB", size / 1024) end
return size.."B"
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
if file:sub(-1, -1) == "/" then
table.insert(dirTable, file)
file = file:sub(1, -2)
else
table.insert(fileTable, file)
local isDir = file:sub(-1) == "/"
local name = isDir and file:sub(1, -2) or file
local size = isDir and 0 or fs.size(fs.concat(path, file))
table.insert(fileList, {name = name, isDir = isDir, size = size})
end
if unicode.wlen(file) > maxLength then
maxLength = unicode.wlen(file)
end
end
table.sort(dirTable)
table.sort(fileTable)
files = {}
for _, v in ipairs(dirTable) do
table.insert(files, v)
end
for _, v in ipairs(fileTable) do
table.insert(files, v)
end
dirTable, fileTable = nil, nil
for _, file in ipairs(files) do
local dir = false
local filetext
if file:sub(-1, -1) == "/" then
dir = true
filetext = "\27[93m"..file:sub(1, -2)
elseif file:find(".") and file:match("[^.]+$") == "lua" then
filetext = "\27[92m"..file
end
filetext = (filetext or file)..string.rep(" ", maxLength - unicode.wlen(file) + margin)
if dir then
print(filetext.." \27[0m[DIR]")
else
local size = fs.size(fs.concat(target, file))
local sizeString
if convert(size, "B", "GiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "GiB") * 100 + 0.5) / 100).." GiB"
elseif convert(size, "B", "MiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "MiB") * 100 + 0.5) / 100).." MiB"
elseif convert(size, "B", "KiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "KiB") * 100 + 0.5) / 100).." KiB"
else
sizeString = tostring(size).." B"
end
print(filetext.."\27[0m"..sizeString)
-- directories first
-- then files
table.sort(fileList, function(a, b)
if a.isDir ~= b.isDir then return a.isDir end
return a.name < b.name
end)
local maxSizeLen = 0
for _, item in ipairs(fileList) do
maxSizeLen = math.max(maxSizeLen, #formatSize(item.size, item.isDir))
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
::continue::
end
-9
View File
@@ -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
View File
@@ -77,7 +77,7 @@ elseif outArgIdx then
if headers[word] then
addHeader(word)
else
print("\x1b[93mCategory \""..word.."\" doesn't exist\x1b[39m")
print("\x1b[93mCategory \""..word.."\" doesn't exist\x1b[0m")
end
end
end
@@ -106,7 +106,7 @@ local function formatSize(mem)
end
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
local function getBootCode(proxy)
@@ -140,24 +140,37 @@ local function handleComponent(id,type)
-- for i=1,#tableOut do table.insert(out,"unknown") end
local slot,capacity,managed,readOnly,mount,bootable,label
local virtual,vproc = component.virtual.check(id)
local cslot = component.slot(id)
if cslot==-1 then
slot="Virtual"
if virtual then
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
slot="EEPROM"
elseif cslot==5 or cslot==6 then
slot="HDD #"..(cslot-4)
elseif cslot==7 then
slot="Floppy"
else
slot="#"..(cslot+2)
end
managed="Yes"
managed="No"
readOnly="No"
if type=="drive" then
managed="No"
capacity=formatSize(proxy.getCapacity())
mount="/special/drive/"..id:sub(1,3)
elseif type=="filesystem" then
managed="Yes"
if proxy.spaceTotal then
capacity=formatSize(proxy.spaceTotal())
if proxy.isReadOnly() then
end
if not proxy.isReadOnly or proxy.isReadOnly() then
readOnly="Yes"
end
mount="/mnt/"..id:sub(1,3)
@@ -177,7 +190,7 @@ local function handleComponent(id,type)
if proxy.getLabel then
local clabel = proxy.getLabel()
label=clabel and serialize.string(clabel) or "None"
label=clabel and serialize(clabel) or "None"
else
label="Unsupported"
end
@@ -253,7 +266,7 @@ if not showAll then
if func then
filter(comps,func)
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
else
filter(comps,function(comp)
@@ -273,7 +286,7 @@ if sortArgIdx then
return (boolToNum(func(a)) or 0)<(boolToNum(func(b)) or 0)
end)
else
return print("\x1b[91mInvalid sort expression:\n\n"..tostring(err).."\x1b[39m")
return print("\x1b[91mInvalid sort expression:\n\n"..tostring(err).."\x1b[0m")
end
else
table.sort(comps,function(a,b)
+8
View File
@@ -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
View File
@@ -1,31 +1,83 @@
print("\27[44m".._VERSION.."\27[0m shell")
print('Type "exit" to exit.')
termlib.readHistory["lua"] = {""}
-- terminal.readHistory["lua"] = {""}
local fs = require("filesystem")
local computer = require("computer")
local log = require("log")
local loadedLibraries = ""
local libList = fs.list("halyde/lib")
local bootTime = computer.uptime()
local libList = fs.list("/lib/")
local failed = false
for _, lib in pairs(libList) do
local status, err = xpcall(function()
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
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
local command = read("lua", "\27[44mlua>\27[0m ")
local command = terminal.read({readHistoryType = "lua", prefix = "\27[44mlua>\27[0m "})
if command == "exit" then
coroutine.yield()
return
else
elseif command ~= "" then
local function runCommand()
local func = load(loadedLibraries.."return "..command,"=stdin") or load(loadedLibraries..command,"=stdin")
local res = {assert(func)()}
if res and (type(res[1])~="nil" or type(res[2])~="nil") then print(table.unpack(res)) end
local func, err = load("return " .. command, "=stdin")
local returns = true
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
local result, reason = xpcall(runCommand, function(errMsg)
return errMsg .. "\n\n" .. debug.traceback()
end)
if not result then
print("\27[91m" .. reason)
print("\27[91m" .. reason .. "\27[0m")
end
end
end
+3 -1
View File
@@ -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")
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
local address = computer.getBootAddress()
+19 -10
View File
@@ -1,14 +1,23 @@
local directory = ...
local fs = require("filesystem")
local shell = require("shell")
if not directory then
shell.run("help mkdir")
return
local args = {...}
if not args[1] then
return shell.run("help mkdir")
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
if fs.exists(directory) then
print("\27[91mAn object already exists at the specified path.")
end
fs.makeDirectory(directory)
+64 -18
View File
@@ -1,24 +1,70 @@
local fromFile, toFile = ...
local fs = require("filesystem")
local shell = require("shell")
if not fromFile or not toFile then
shell.run("help mv")
local args = {...}
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
end
if fromFile:sub(1, 1) ~= "/" then
fromFile = fs.concat(shell.workingDirectory, fromFile)
end
if toFile:sub(1, 1) ~= "/" then
toFile = fs.concat(shell.workingDirectory, toFile)
end
if fromFile == toFile then
print("\27[91mSource and destination are the same.")
end
if not fs.exists(fromFile) then
print("\27[91mSource file does not exist.")
end
if fs.exists(toFile) and not (table.find({...}, "-o") or table.find({...}, "--overwrite")) then
print("\27[91mDestination file already exists. Run this command again with -o to overwrite it.")
local dest = shell.resolvePath(args[#args])
if fs.isFile(dest) then
if #args ~= 2 then
terminal.write("\27[91mError: Destination is not a 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
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
fs.rename(fromFile, toFile)
+222
View File
@@ -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")
+96
View File
@@ -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
View File
+13 -11
View File
@@ -1,15 +1,17 @@
local file = ...
local fs = require("filesystem")
local shell = require("shell")
if not file then
shell.run("help rm")
return
local args = {...}
if not args[1] then
return shell.run("help rm")
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
if not fs.exists(file) then
print("\27[91mFile does not exist.")
return
end
fs.remove(file)
+1 -1
View File
@@ -88,4 +88,4 @@ end
end ]]
raster.free()
termlib.cursorPosY=1
terminal.clear()
+23
View File
@@ -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
View File
@@ -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/"}
+1
View File
@@ -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
View File
@@ -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
View File
@@ -1 +1 @@
["/halyde/shell/shell.lua"]
["/halyde/scripts/login.lua"]
+1
View File
@@ -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
View File
@@ -1,44 +1,57 @@
local loadfile = ...
local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile))
_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
_G._OSLOGO = ""
_G._PUBLIC = {}
local ocelot = component.proxy(component.list("ocelot")())
_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
repeat
tmpdata = handle:read(math.huge)
_OSLOGO = _OSLOGO .. (tmpdata or "")
until not tmpdata
gpu.bind(screenAddress)
gpu.setResolution(gpu.maxResolution())
_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, ...)
ocelot.log("Requiring " .. module)
_G.package = { ["preloaded"] = {} }
function _G.reqgen(load)
return function(module, ...)
local args = table.pack(...)
if package.preloaded[module] then
return package.preloaded[module]
end
local modulepath
if filesystem.exists(module) then
if filesystem.exists(module) and not filesystem.isDirectory(module) then
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"
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"
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
repeat
tmpdata = handle:read(math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
return(assert(load(data, "="..modulepath))(table.unpack(args)))
return (assert(load(data, "=" .. modulepath))(table.unpack(args)))
end
end
_G.require = reqgen(_G.load)
log.kernel.info("Generated userland require function")
function _G.package.preload(module)
local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil
repeat
@@ -46,28 +59,31 @@ function _G.package.preload(module)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
package.preloaded[module] = assert(load(data, "="..module))()
package.preloaded[module] = assert(load(data, "=" .. module))()
_G[module] = nil
log.kernel.info(string.format("Pre-loaded /lib/%s.lua", module))
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")
package.preload("component")
package.preload("computer")
local component = require("component")
local gpu = component.gpu
local screenAddress = component.list("screen")()
gpu.bind(screenAddress)
gpu.setResolution(gpu.maxResolution())
if not filesystem.exists("/halyde/config/shell.json") then -- Auto-generate configs
filesystem.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json")
local toPreload = { "component", "computer", "log", "event" }
for _, p in pairs(toPreload) do
profiler.profile("pre-loading " .. p, package.preload, p)
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
filesystem.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json")
end
log.kernel.info("Starting tsched")
require("/halyde/kernel/tsched.lua")
+1
View File
@@ -13,6 +13,7 @@ local conversionTables = {
}
function table.find(tab, item)
checkArg(1,tab,"table")
for k, v in pairs(tab) do
if v == item then
return k
-55
View File
@@ -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
View File
@@ -1,24 +1,58 @@
local log = require("log")
local fs = require("filesystem")
local ocelot = require("component").ocelot
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 modulesLoaded = {}
local function loadModule(modName)
ocelot.log("Checking module " .. modName)
local moduleData = require(fs.concat(modulePath, modName))
table.remove(modules, table.find(modules, modName))
if not moduleData.check() then
return
local stop = profiler.start("loadModule(" .. tostring(modName) .. ")")
if table.find(modulesLoaded, modName) then
log.kernel.warn(string.format("[modload: %s] Module was already loaded - skipping", modName))
stop()
return true
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
if table.find(modules, dependency) then
if table.find(moduleList, dependency) then
loadModule(dependency)
elseif table.find(modules, dependency .. ".lua") then
elseif table.find(moduleList, dependency .. ".lua") then
loadModule(dependency .. ".lua")
else
for typeLookupDrvName, typeLookupDrvType in pairs(moduleTypes) do
@@ -31,23 +65,128 @@ local function loadModule(modName)
end
end
--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
local status, err = xpcall(function()
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
stop()
return true
end
for _, modName in pairs(modules) do -- Get all the module types
local moduleData = require(fs.concat(modulePath, modName))
for _, modName in pairs(moduleList) do -- Get all the module types
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
--print(moduleData.type)
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
end
::continue::
stop()
end
while modules[1] do
if modules[1]:sub(-1, -1) ~= "/" then -- Check if it's not a directory. If it is, it might be module config
loadModule(modules[1])
local function loadAllModules() -- attempt at loading all modules, unless if they're not ready
local notReadyModules = {}
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
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
+3 -3
View File
@@ -1,6 +1,6 @@
local module = {}
module.dependencies = {"terminal"}
module.dependencies = { "terminal" }
function module.check()
return true -- This module should always be loaded
@@ -9,7 +9,6 @@ end
function module.init()
local publicTable = {
"print",
"require",
"_VERSION",
"_OSVERSION",
"assert",
@@ -39,7 +38,8 @@ function module.init()
"table",
"checkArg",
"utf8",
"convert"
"convert",
"wait"
}
for _, value in ipairs(publicTable) do
_G._PUBLIC[value] = table.copy(_G[value])
+90
View File
@@ -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
+206 -2
View File
@@ -1,15 +1,219 @@
local module = {}
module.dependencies = { "tsched" }
function module.check()
return true -- This module should always be loaded
return true -- IPC should always be loaded
end
local checkProcess
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
function module.exit()
_G.ipc = nil
_PUBLIC.ipc = nil
_PUBLIC.tsched.removeTask(checkProcess.id)
end
return module
+59
View File
@@ -136,6 +136,53 @@ function module.init()
_PUBLIC.keyboard.keys.numpadenter = 0x9C
_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.
setmetatable(_PUBLIC.keyboard.keys,
{
@@ -148,6 +195,18 @@ function module.init()
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
function module.exit()

Some files were not shown because too many files have changed in this diff Show More