From fb4c80f3a0fbb9ea024f9371702735dc163aa9c9 Mon Sep 17 00:00:00 2001 From: TheWahlolly Date: Wed, 2 Jul 2025 12:34:14 +0300 Subject: [PATCH] v1.14.0 - Added the download command (Halyde equivalent of wget) and clipboard pasting support. --- argentum.cfg | 4 +- halyde/apps/download.lua | 57 ++++++ halyde/apps/helpdb/default.txt | 1 + halyde/apps/helpdb/download.txt | 7 + halyde/core/boot.lua | 2 +- halyde/core/termlib.lua | 334 ++++++++++++++++---------------- 6 files changed, 241 insertions(+), 164 deletions(-) create mode 100644 halyde/apps/download.lua create mode 100644 halyde/apps/helpdb/download.txt diff --git a/argentum.cfg b/argentum.cfg index 6482e62..0ec17b8 100644 --- a/argentum.cfg +++ b/argentum.cfg @@ -1,7 +1,7 @@ local agcfg = { ["halyde"] = { ["maindir"] = "", - ["version"] = "1.13.0", + ["version"] = "1.14.0", ["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.", ["directories"] = { "halyde/apps", @@ -20,6 +20,7 @@ local agcfg = { "halyde/apps/helpdb/clear.txt", "halyde/apps/helpdb/cp.txt", "halyde/apps/helpdb/default.txt", + "halyde/apps/helpdb/download.txt", "halyde/apps/helpdb/echo.txt", "halyde/apps/helpdb/fetch.txt", "halyde/apps/helpdb/help.txt", @@ -34,6 +35,7 @@ local agcfg = { "halyde/apps/cd.lua", "halyde/apps/clear.lua", "halyde/apps/cp.lua", + "halyde/apps/download.lua", "halyde/apps/echo.lua", "halyde/apps/fetch.lua", "halyde/apps/help.lua", diff --git a/halyde/apps/download.lua b/halyde/apps/download.lua new file mode 100644 index 0000000..96fdd5b --- /dev/null +++ b/halyde/apps/download.lua @@ -0,0 +1,57 @@ +local url = ... + +local component = import("component") +local fs = import("filesystem") + +if not component.list("internet")() then + print("\27[91mThis program requires an internet card to run.") + return +end + +if not url then + print("Please enter a URL to download from.") + shell.run("help download") + return +end + +if url:sub(-1, -1) == "/" then + url = url:sub(1, -2) +end + +local internet = component.internet + +local request, data, tmpdata = nil, "", nil +local status, errorMessage = pcall(function() + request = internet.request(url) + request:finishConnect() +end) +if not status then + print("\27[91mDownload failed: " .. errorMessage) +end +local responseCode = request:response() +if responseCode and responseCode ~= 200 then + print("\27[91mDownload failed: " .. tostring(responseCode)) +end +repeat + tmpdata = request.read(math.huge) + data = data .. (tmpdata or "") +until not tmpdata +local saveLocation +local saveLocationOK = false +repeat + saveLocation = read(nil, "File save location: ", fs.concat(shell.workingDirectory, url:match("/([^/]+)$"))) + if fs.isDirectory(saveLocation) then + print("\27[91mThe specified location is a directory.") + elseif fs.exists(saveLocation) then + local answer = read(nil, "\27[91mThere is already a file at the specified directory. Overwrite it? [Y/n]") + if answer:lower() ~= "n" then + saveLocationOK = true + end + else + saveLocationOK = true + end +until saveLocationOK +local handle = fs.open(saveLocation, "w") +handle:write(data) +handle:close() +print("File downloaded successfully.") diff --git a/halyde/apps/helpdb/default.txt b/halyde/apps/helpdb/default.txt index dd84751..875935e 100644 --- a/halyde/apps/helpdb/default.txt +++ b/halyde/apps/helpdb/default.txt @@ -4,6 +4,7 @@ All default Halyde shell commands: 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. diff --git a/halyde/apps/helpdb/download.txt b/halyde/apps/helpdb/download.txt new file mode 100644 index 0000000..a870bb6 --- /dev/null +++ b/halyde/apps/helpdb/download.txt @@ -0,0 +1,7 @@ +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. diff --git a/halyde/core/boot.lua b/halyde/core/boot.lua index 3011208..5bee363 100644 --- a/halyde/core/boot.lua +++ b/halyde/core/boot.lua @@ -1,7 +1,7 @@ local loadfile = ... local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile) -_G._OSVERSION = "Halyde 1.13.0" +_G._OSVERSION = "Halyde 1.14.0" _G._OSLOGO = "" local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil repeat diff --git a/halyde/core/termlib.lua b/halyde/core/termlib.lua index e595496..052b339 100644 --- a/halyde/core/termlib.lua +++ b/halyde/core/termlib.lua @@ -188,192 +188,202 @@ function _G.clear() end -- god i hope this silly claude code works first try +-- Fluxdrive caught vibe coding??? function _G.read(readHistoryType, prefix, defaultText) -checkArg(1, readHistoryType, "string", "nil") -checkArg(2, prefix, "string", "nil") -checkArg(3, defaultText, "string", "nil") -local curtext = defaultText or "" -local prefix = prefix or "" -local textCursorPos = unicode.wlen(curtext) + 1 -- Position within the text (1-based) + checkArg(1, readHistoryType, "string", "nil") + checkArg(2, prefix, "string", "nil") + checkArg(3, defaultText, "string", "nil") + local curtext = defaultText or "" + local prefix = prefix or "" + local textCursorPos = unicode.wlen(curtext) + 1 -- Position within the text (1-based) -local RHIndex -if readHistoryType then - if not termlib.readHistory[readHistoryType] then - termlib.readHistory[readHistoryType] = {curtext} + local RHIndex + if readHistoryType then + if not termlib.readHistory[readHistoryType] then + termlib.readHistory[readHistoryType] = {curtext} elseif termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType]] ~= "" then table.insert(termlib.readHistory[readHistoryType], curtext) end RHIndex = #termlib.readHistory[readHistoryType] + end + + local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY + + -- Track maximum text length to ensure proper clearing across wrapped lines + local maxTextLength = unicode.wlen(prefix .. curtext) + + -- Function to calculate how many lines text will occupy + local function calculateLines(text) + local totalWidth = unicode.wlen(prefix .. text) + local width = gpu.getResolution() + return math.ceil(totalWidth / width) + end + + -- Track maximum lines used + local maxLinesUsed = calculateLines(curtext) + + -- Function to redraw the input line with cursor + local function redrawLine() + local startX, startY = cursorPosX, cursorPosY + + -- Calculate current and max lines needed + local currentLines = calculateLines(curtext) + local linesToClear = math.max(maxLinesUsed, currentLines) + + -- Clear all potentially used lines + for i = 0, linesToClear - 1 do + termlib.cursorPosX, termlib.cursorPosY = 1, startY + i + if startY + i <= height then + local width = gpu.getResolution() + termlib.write(string.rep(" ", width)) end + end - local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY + -- Reset cursor to start position + termlib.cursorPosX, termlib.cursorPosY = startX, startY - -- Track maximum text length to ensure proper clearing across wrapped lines - local maxTextLength = unicode.wlen(prefix .. curtext) + -- Update tracking variables + maxTextLength = math.max(maxTextLength, unicode.wlen(prefix .. curtext)) + maxLinesUsed = math.max(maxLinesUsed, currentLines) - -- Function to calculate how many lines text will occupy - local function calculateLines(text) - local totalWidth = unicode.wlen(prefix .. text) - local width = gpu.getResolution() - return math.ceil(totalWidth / width) - end + -- Draw text with cursor positioned correctly + local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) + local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) - -- Track maximum lines used - local maxLinesUsed = calculateLines(curtext) + termlib.write(prefix .. beforeCursor) + termlib.write("\27[30m\27[107m" .. (afterCursor:sub(1, 1) ~= "" and afterCursor:sub(1, 1) or " ") .. "\27[0m") -- HUGE SHOUTOUT TO WAH FOR MAKING THE ESCAPE CODES WORK YEAAAAAAA + termlib.write(afterCursor:sub(2)) + end - -- Function to redraw the input line with cursor - local function redrawLine() - local startX, startY = cursorPosX, cursorPosY + redrawLine() + local cursorWhite = true - -- Calculate current and max lines needed - local currentLines = calculateLines(curtext) - local linesToClear = math.max(maxLinesUsed, currentLines) + while true do + local args = {event.pull("key_down", "clipboard", 0.5)} - -- Clear all potentially used lines - for i = 0, linesToClear - 1 do - termlib.cursorPosX, termlib.cursorPosY = 1, startY + i - if startY + i <= height then - local width = gpu.getResolution() - termlib.write(string.rep(" ", width)) + if args[1] == "key_down" and args[4] then + cursorWhite = true + local keycode = args[4] + local key = keyboard.keys[keycode] + + -- Handle arrow keys + if key == "up" and readHistoryType then + RHIndex = RHIndex - 1 + if RHIndex <= 0 then + RHIndex = 1 end + curtext = termlib.readHistory[readHistoryType][RHIndex] + textCursorPos = unicode.wlen(curtext) + 1 + redrawLine() + + elseif key == "down" and readHistoryType then + RHIndex = RHIndex + 1 + if RHIndex > #termlib.readHistory[readHistoryType] then + RHIndex = #termlib.readHistory[readHistoryType] + end + curtext = termlib.readHistory[readHistoryType][RHIndex] + textCursorPos = unicode.wlen(curtext) + 1 + redrawLine() + + elseif key == "left" then + -- Move cursor left + if textCursorPos > 1 then + textCursorPos = textCursorPos - 1 + redrawLine() end - -- Reset cursor to start position - termlib.cursorPosX, termlib.cursorPosY = startX, startY + elseif key == "right" then + -- Move cursor right + if textCursorPos <= unicode.wlen(curtext) then + textCursorPos = textCursorPos + 1 + redrawLine() + end - -- Update tracking variables - maxTextLength = math.max(maxTextLength, unicode.wlen(prefix .. curtext)) - maxLinesUsed = math.max(maxLinesUsed, currentLines) + elseif key == "home" then + -- Move to beginning of line + textCursorPos = 1 + redrawLine() - -- Draw text with cursor positioned correctly + elseif key == "end" then + -- Move to end of line + textCursorPos = unicode.wlen(curtext) + 1 + redrawLine() + + elseif key == "back" then + -- Backspace - delete character before cursor + if textCursorPos > 1 then + local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos - 1) - 1 or 0) + local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) + curtext = beforeCursor .. afterCursor + textCursorPos = textCursorPos - 1 + if readHistoryType then + termlib.readHistory[readHistoryType][RHIndex] = curtext + end + redrawLine() + end + + elseif key == "delete" then + -- Delete - delete character at cursor + if textCursorPos <= unicode.wlen(curtext) then + local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) + local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos + 1) or (#curtext + 1)) + curtext = beforeCursor .. afterCursor + if readHistoryType then + termlib.readHistory[readHistoryType][RHIndex] = curtext + end + redrawLine() + end + + elseif key == "enter" then + termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY + print(prefix .. curtext .. " ") + if readHistoryType then + while #termlib.readHistory[readHistoryType] > 50 do + table.remove(termlib.readHistory[readHistoryType], 1) + end + end + return curtext + + + elseif args[3] >= 32 and args[3] <= 126 then + -- Insert character at cursor position + local char = unicode.char(args[3]) or "" local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) - - termlib.write(prefix .. beforeCursor) - termlib.write("\27[30m\27[107m" .. (afterCursor:sub(1, 1) ~= "" and afterCursor:sub(1, 1) or " ") .. "\27[0m") -- HUGE SHOUTOUT TO WAH FOR MAKING THE ESCAPE CODES WORK YEAAAAAAA - termlib.write(afterCursor:sub(2)) + curtext = beforeCursor .. char .. afterCursor + textCursorPos = textCursorPos + 1 + if readHistoryType then + termlib.readHistory[readHistoryType][RHIndex] = curtext end - redrawLine() - local cursorWhite = true + end - while true do - local args = {event.pull("key_down", "clipboard", 0.5)} + elseif args[1] == "clipboard" then + -- Handle clipboard paste + local text = args[3] or "" + local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) + local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) + curtext = beforeCursor .. text .. afterCursor + textCursorPos = textCursorPos + #text + if readHistoryType then + termlib.readHistory[readHistoryType][RHIndex] = curtext + end + redrawLine() - if args[1] == "key_down" and args[4] then - cursorWhite = true - local keycode = args[4] - local key = keyboard.keys[keycode] - - -- Handle arrow keys - if key == "up" and readHistoryType then - RHIndex = RHIndex - 1 - if RHIndex <= 0 then - RHIndex = 1 - end - curtext = termlib.readHistory[readHistoryType][RHIndex] - textCursorPos = unicode.wlen(curtext) + 1 - redrawLine() - - elseif key == "down" and readHistoryType then - RHIndex = RHIndex + 1 - if RHIndex > #termlib.readHistory[readHistoryType] then - RHIndex = #termlib.readHistory[readHistoryType] - end - curtext = termlib.readHistory[readHistoryType][RHIndex] - textCursorPos = unicode.wlen(curtext) + 1 - redrawLine() - - elseif key == "left" then - -- Move cursor left - if textCursorPos > 1 then - textCursorPos = textCursorPos - 1 - redrawLine() - end - - elseif key == "right" then - -- Move cursor right - if textCursorPos <= unicode.wlen(curtext) then - textCursorPos = textCursorPos + 1 - redrawLine() - end - - elseif key == "home" then - -- Move to beginning of line - textCursorPos = 1 - redrawLine() - - elseif key == "end" then - -- Move to end of line - textCursorPos = unicode.wlen(curtext) + 1 - redrawLine() - - elseif key == "back" then - -- Backspace - delete character before cursor - if textCursorPos > 1 then - local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos - 1) - 1 or 0) - local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) - curtext = beforeCursor .. afterCursor - textCursorPos = textCursorPos - 1 - if readHistoryType then - termlib.readHistory[readHistoryType][RHIndex] = curtext - end - redrawLine() - end - - elseif key == "delete" then - -- Delete - delete character at cursor - if textCursorPos <= unicode.wlen(curtext) then - local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) - local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos + 1) or (#curtext + 1)) - curtext = beforeCursor .. afterCursor - if readHistoryType then - termlib.readHistory[readHistoryType][RHIndex] = curtext - end - redrawLine() - end - - elseif key == "enter" then - termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY - print(prefix .. curtext .. " ") - if readHistoryType then - while #termlib.readHistory[readHistoryType] > 50 do - table.remove(termlib.readHistory[readHistoryType], 1) - end - end - return curtext - - - elseif args[3] >= 32 and args[3] <= 126 then - -- Insert character at cursor position - local char = unicode.char(args[3]) or "" - local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) - local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) - curtext = beforeCursor .. char .. afterCursor - textCursorPos = textCursorPos + 1 - if readHistoryType then - termlib.readHistory[readHistoryType][RHIndex] = curtext - end - redrawLine() - end - - elseif args[1] == "clipboard" then - -- Handle clipboard paste here if needed - - else - -- Cursor blink timing - cursorWhite = not cursorWhite - if cursorWhite then - redrawLine() - else - -- Show cursor as normal character or space - termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY - local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) - local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) - termlib.write(prefix .. beforeCursor) - termlib.write(afterCursor:sub(1, 1) ~= "" and afterCursor:sub(1, 1) or " ") - termlib.write(afterCursor:sub(2)) - end - end + else + -- Cursor blink timing + cursorWhite = not cursorWhite + if cursorWhite then + redrawLine() + else + -- Show cursor as normal character or space + termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY + local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0) + local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1)) + termlib.write(prefix .. beforeCursor) + termlib.write(afterCursor:sub(1, 1) ~= "" and afterCursor:sub(1, 1) or " ") + termlib.write(afterCursor:sub(2)) + end + end end end