v0.7.0 - Added basic CLI tools: ls, cd, cp, mv, rm, lua

This commit is contained in:
TheWahlolly
2025-04-27 10:13:12 +03:00
parent 64a761fdde
commit 109c0beffb
19 changed files with 347 additions and 16 deletions
+17
View File
@@ -0,0 +1,17 @@
local args = {...}
local file = args[1]
args = nil
local fs = import("filesystem")
if file:sub(1, 1) ~= "/" then
file = shell.workingDirectory .. file
end
if not fs.exists(file) then
print("\27[91mFile does not exist.")
end
local handle = fs.open(file, "r")
local data
repeat
data = handle:read(math.huge or math.maxinteger)
print(data, false)
until not data
+26
View File
@@ -0,0 +1,26 @@
local args = {...}
local directory = args[1]
args = nil
local fs = import("filesystem")
if directory == ".." then
local backDirectory = shell.workingDirectory:match("(.+)/.-/")
if backDirectory then
backDirectory = backDirectory .. "/"
else
backDirectory = "/"
end
shell.workingDirectory = backDirectory
else
if directory:sub(-1, -1) ~= "/" then
directory = directory .. "/"
end
if directory:sub(1, 1) ~= "/" then
directory = shell.workingDirectory .. directory
end
if fs.exists(directory) and fs.isDirectory(directory) or fs.exists(shell.workingDirectory .. directory) and fs.isDirectory(shell.workingDirectory .. directory) then
shell.workingDirectory = directory
else
print("error: no such directory")
end
end
+2
View File
@@ -0,0 +1,2 @@
clear()
-- truly so much going on here
+25
View File
@@ -0,0 +1,25 @@
local args = {...}
local fromFile, toFile = args[1], args[2]
args = nil
local fs = import("filesystem")
if fromFile:sub(1, 1) ~= "/" then
fromFile = shell.workingDirectory .. fromFile
end
if toFile:sub(1, 1) ~= "/" then
toFile = 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) then
print("Destination file already exists. Overwrite it? [Y/n] ", false)
if read():lower() == "n" then
print("Aborted.")
return
end
end
fs.copy(fromFile, toFile)
+1
View File
@@ -0,0 +1 @@
print("\27[40m \27[41m \27[42m \27[43m \27[44m \27[45m \27[46m \27[47m \n\27[100m \27[101m \27[102m \27[103m \27[104m \27[105m \27[106m \27[107m ")
+1
View File
@@ -0,0 +1 @@
+70
View File
@@ -0,0 +1,70 @@
local args = {...}
local target = args[1]
args = nil
local fs = import("filesystem")
local maxLength = 0
local margin = 2 -- minimum space between filename and size
local dirTable = {}
local fileTable = {}
if target then
if target:sub(1, 1) ~= "/" then
target = shell.workingDirectory .. target
end
if target:sub(-1, -1) ~= "/" then
target = target .. "/"
end
else
target = shell.workingDirectory
end
local files = fs.list(target)
for _, file in pairs(files) do
if file:sub(-1, -1) == "/" then
table.insert(dirTable, file)
file = file:sub(1, -2)
else
table.insert(fileTable, file)
end
if unicode.wlen(file) > maxLength then
maxLength = unicode.wlen(file)
end
end
table.sort(dirTable)
table.sort(fileTable)
files = {}
for _, v in ipairs(dirTable) do
table.insert(files, v)
end
for _, v in ipairs(fileTable) do
table.insert(files, v)
end
dirTable, fileTable = nil, nil
for _, file in ipairs(files) do
local dir = false
local filetext
if file:sub(-1, -1) == "/" then -- i think this is a more efficient way to check if it's a directory
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(target .. file)
local sizeString
if convert(size, "B", "GiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "GiB") * 100 + 0.5) / 100).." GiB"
elseif convert(size, "B", "MiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "MiB") * 100 + 0.5) / 100).." MiB"
elseif convert(size, "B", "KiB") >= 1 then
sizeString = tostring(math.floor(convert(size, "B", "KiB") * 100 + 0.5) / 100).." KiB"
else
sizeString = tostring(size).." B"
end
print(filetext.."\27[0m"..sizeString)
end
end
+19
View File
@@ -0,0 +1,19 @@
print("\27[44m".._VERSION.."\27[0m shell")
print('Type "exit" to exit.')
while true do
print("\27[44mlua>\27[0m ", false)
local command = read()
if command == "exit" then
return
else
local function runCommand()
assert(load(command))()
end
local result, reason = xpcall(runCommand, function(errMsg)
return errMsg .. "\n\n" .. debug.traceback()
end)
if not result then
print("\27[91m" .. reason)
end
end
end
+25
View File
@@ -0,0 +1,25 @@
local args = {...}
local fromFile, toFile = args[1], args[2]
args = nil
local fs = import("filesystem")
if fromFile:sub(1, 1) ~= "/" then
fromFile = shell.workingDirectory .. fromFile
end
if toFile:sub(1, 1) ~= "/" then
toFile = 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) then
print("Destination file already exists. Overwrite it? [Y/n] ", false)
if read():lower() == "n" then
print("Aborted.")
return
end
end
fs.rename(fromFile, toFile)
+12
View File
@@ -0,0 +1,12 @@
local args = {...}
local file = args[1]
args = nil
local fs = import("filesystem")
if file:sub(1, 1) ~= "/" then
file = shell.workingDirectory .. file
end
if not fs.exists(file) then
print("\27[91mFile does not exist.")
end
fs.remove(file)
+11 -1
View File
@@ -2,7 +2,17 @@ local shellcfg = {
["startupMessage"] = "\n │\n │ ".._OSVERSION.." running on ".._VERSION..'\n │ Welcome! Type "help" to get started.\n │\n ', -- message shown on startup
["prompt"] = "\x1b[92m%s > \x1b[0m", -- shell prompt, %s will be replaced with working directory. example: "%s > " turns to "/current/working/directory > "
["path"] = { -- default locations where programs will be run from
"/halyde/apps/"}
"/halyde/apps/"
}, ["aliases"] = { -- shell command aliases
["copy"] = "cp",
["move"] = "mv",
["rename"] = "mv",
["ren"] = "mv",
["dir"] = "ls",
["man"] = "help",
["del"] = "rm",
[".."] = "cd .."
}, ["defaultWorkingDirectory"] = "/home/" -- the working directory that gets set when halyde starts
}
return shellcfg
+1 -1
View File
@@ -1,7 +1,7 @@
local loadfile = ...
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
_G._OSVERSION = "Halyde 0.6.0"
_G._OSVERSION = "Halyde 0.7.0"
function _G.import(module, ...)
local args = table.pack(...)
+1 -1
View File
@@ -28,7 +28,7 @@ local function runCoroutines()
end
if coroutine.status(_G.cormgr.corList[i]) == "dead" then
table.remove(_G.cormgr.corList, i)
break
i = i - 1
end
--computer.pullSignal(0)
--coroutine.yield()
+24 -1
View File
@@ -1,7 +1,21 @@
local conversionTables = {
["bytes"] = {
["B"] = 1,
["KB"] = 1000,
["MB"] = 1000000,
["GB"] = 1000000000
}, ["bibytes"] = {
["B"] = 1,
["KiB"] = 1024,
["MiB"] = 1048576,
["GiB"] = 1073741824
}
}
function table.find(table, item)
for k, v in pairs(table) do
if v == item then
return(v)
return k
end
end
end
@@ -20,3 +34,12 @@ function table.copy(orig)
end
return copy
end
function convert(amount, fromUnit, toUnit)
for _, convTable in pairs(conversionTables) do
if convTable[toUnit] then
return amount / convTable[toUnit] * convTable[fromUnit]
end
end
return false, "unit does not exist"
end
+10 -7
View File
@@ -1,15 +1,19 @@
local shellcfg = import("/halyde/config/shell.cfg")
import("termlib")
import("/halyde/core/termlib.lua")
local event = import("event")
local ocelot = component.proxy(component.list("ocelot")())
--local ocelot = component.proxy(component.list("ocelot")())
local filesystem = import("filesystem")
_G.shell = {}
_G.shell.workingDirectory = "/"
_G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"]
_G.shell.aliases = shellcfg["aliases"]
local function parseCommand(command)
checkArg(1, command, "string")
local gm, result, args, trimmedCommand = command:gmatch('[^ ]+'), nil, {}, command
if shell.aliases[command:match("[^ ]+")] then
local _, cmdend = command:find("[^ ]+")
command = shell.aliases[command:match("[^ ]+")] .. command:sub(cmdend + 1)
end
local gm, result, args, trimmedCommand = command:gmatch("[^ ]+"), nil, {}, command
while true do
result = gm()
if not result then
@@ -63,7 +67,7 @@ local function parseCommand(command)
end
end
if not foundfile then
print("no such file or command: "..args[1])
print("No such file or command: "..args[1])
end
end
@@ -75,6 +79,5 @@ while true do
-- termlib.cursorPosX = #(shell.workingDirectory .. " > ")
-- termlib.cursorPosY = termlib.cursorPosY - 1
local shellCommand = read()
ocelot.log("parsing "..shellCommand)
parseCommand(shellCommand)
end
@@ -73,6 +73,7 @@ function _G.print(text,endNewLine)
if not text or not tostring(text) then
return
end
text = "\27[0m" .. text:gsub("\t", " ")
text = tostring(text)
readBreak = 0
-- readBreak is for when, inside the for loop, there normally would have been an increase in the "i" variable because it has read more than one character.
+7 -2
View File
@@ -1,4 +1,9 @@
local componentlib = {}
local componentlib
if table.copy then
componentlib = table.copy(component)
else
componentlib = {}
end
function componentlib.get(address)
checkArg(1, address, "string")
@@ -14,4 +19,4 @@ end
componentlib.invoke = component.invoke
return(componentlib)
return(componentlib)
+93 -2
View File
@@ -3,7 +3,7 @@ local component
if loadfile then
component = loadfile("/halyde/lib/component.lua")(loadfile)
else
elseif import then
component = import("component")
end
@@ -67,11 +67,102 @@ function filesystem.open(path, mode) -- opens a file and returns its handle
end
function filesystem.list(path)
checkArg(1, path, "string")
if path == "/mnt/" then
-- list drives
local returnTable = {}
for address, _ in component.list("filesystem") do
table.insert(returnTable, address:sub(1, 3) .. "/")
end
return returnTable
else
local address, absPath = filesystem.processPath(path)
if not address then
return false
end
return component.invoke(address, "list", absPath)
end
end
function filesystem.size(path)
checkArg(1, path, "string")
local address, absPath = filesystem.processPath(path)
if not address then
return false
end
return component.invoke(address, "list", absPath)
return component.invoke(address, "size", absPath)
end
function filesystem.isDirectory(path)
checkArg(1, path, "string")
local address, absPath = filesystem.processPath(path)
if not address then
return false
end
return component.invoke(address, "isDirectory", absPath)
end
function filesystem.rename(fromPath, toPath)
checkArg(1, fromPath, "string")
checkArg(2, toPath, "string")
local fromAddress, fromAbsPath = filesystem.processPath(fromPath)
local toAddress, toAbsPath = filesystem.processPath(toPath)
if not fromAddress or not toAddress then
return false
end
if fromAddress == toAddress then
return component.invoke(fromAddress, "rename", fromAbsPath, toAbsPath)
else
local handle = component.invoke(fromAddress, "open", fromAbsPath, "r")
local data, tmpdata
repeat
tmpdata = component.invoke(fromAddress, "read", handle, math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = component.invoke(fromAddress, "close", handle)
local handle = component.invoke(toAddress, "open", toAbsPath, "w")
component.invoke(toAddress, "write", handle, data)
component.invoke(toAddress, "close", handle)
component.invoke(fromAddress, "remove", fromAbsPath)
end
end
function filesystem.copy(fromPath, toPath)
checkArg(1, fromPath, "string")
checkArg(2, toPath, "string")
local fromAddress, fromAbsPath = filesystem.processPath(fromPath)
local toAddress, toAbsPath = filesystem.processPath(toPath)
if not fromAddress or not toAddress then
return false
end
local handle = component.invoke(fromAddress, "open", fromAbsPath, "r")
local data, tmpdata = "", nil
repeat
tmpdata = component.invoke(fromAddress, "read", handle, math.huge or math.maxinteger)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = component.invoke(fromAddress, "close", handle)
local handle = component.invoke(toAddress, "open", toAbsPath, "w")
component.invoke(toAddress, "write", handle, data)
component.invoke(toAddress, "close", handle)
end
function filesystem.isDirectory(path)
checkArg(1, path, "string")
local address, absPath = filesystem.processPath(path)
if not address then
return false
end
return component.invoke(address, "isDirectory", absPath)
end
function filesystem.remove(path)
checkArg(1, path, "string")
local address, absPath = filesystem.processPath(path)
if not address then
return false
end
return component.invoke(address, "remove", absPath)
end
return(filesystem)