v0.10.0 - Added text editor (which took me way too long) and too many other tweaks to name.

This commit is contained in:
TheWahlolly
2025-05-04 15:16:54 +03:00
parent 6b8bee249a
commit 673a0b4a75
19 changed files with 997 additions and 384 deletions
+1 -1
View File
@@ -24,6 +24,6 @@ else
if fs.exists(directory) and fs.isDirectory(directory) or fs.exists(shell.workingDirectory .. directory) and fs.isDirectory(shell.workingDirectory .. directory) then if fs.exists(directory) and fs.isDirectory(directory) or fs.exists(shell.workingDirectory .. directory) and fs.isDirectory(shell.workingDirectory .. directory) then
shell.workingDirectory = directory shell.workingDirectory = directory
else else
print("error: no such directory") print("\27[91mNo such directory.")
end end
end end
+321
View File
@@ -0,0 +1,321 @@
local args = {...}
local file = args[1]
args = nil
local fs = import("filesystem")
local event = import("event")
local gpu = component.proxy(component.list("gpu")())
local width, height = gpu.getResolution()
local scrollPosX, scrollPosY = 1, 1
local cursorPosX, cursorPosY = 1, 1
local cursorWhite = true
local changesMade = false
local renderBuffer = gpu.allocateBuffer()
local scrollSpeed = 5
--local ocelot = component.proxy(component.list("ocelot")())
local function rawset(x, y, text)
termlib.cursorPosX = x
termlib.cursorPosY = y
print(text, false, false)
end
local filestring, filepath, handle, data, tmpdata
if file then
if file:sub(1, 1) == "/" then
filepath = file
else
filepath = shell.workingDirectory .. file
end
handle, data, tmpdata = fs.open(filepath, "r"), "", nil
if fs.exists(filepath) then
filestring = filepath
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = {}
if data:gmatch("(.-)\n")() then
for line in data:gmatch("(.-)\n") do
local newLine = line:gsub("\r", "") -- this took me SO LONG TO FIGURE OUT AAAAAAAA I HATE CRLF I HATE CRLF I HATE CRLF
table.insert(tmpdata, newLine)
end
else
tmpdata = {data}
end
else
filepath = shell.workingDirectory .. file
filestring = "[NEW FILE]"
tmpdata = {""}
end
else
filepath = ""
filestring = "[NEW FILE]"
tmpdata = {""}
end
local function render()
gpu.setActiveBuffer(renderBuffer)
clear()
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
if realCursorX < 1 then
scrollPosX = scrollPosX + realCursorX - 1
cursorPosX = 1
realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
end
for i = scrollPosY, height + scrollPosY - 3 do
rawset(1, i - scrollPosY + 1, (tmpdata[i] or ""):sub(scrollPosX))
end
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
rawset(1, height, "\27[107m\27[30m^X\27[0m Exit \27[107m\27[30m^S\27[0m Save" .. string.rep(" ", width))
local char = gpu.get(realCursorX, cursorPosY)
if cursorWhite then
rawset(realCursorX, cursorPosY, "\27[107m\27[30m" .. char .. "\27[0m")
else
rawset(realCursorX, cursorPosY, char)
end
gpu.bitblt()
gpu.setActiveBuffer(0)
end
local renderFlag, cursorRenderFlag = false, false
local function scrollUp()
cursorPosY = cursorPosY - 1
cursorRenderFlag = true
cursorWhite = true
if cursorPosY < 1 then
renderFlag = true
scrollPosY = scrollPosY - 1
cursorPosY = 1
end
if scrollPosY < 1 then
renderFlag = false
scrollPosY = 1
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollDown()
cursorPosY = cursorPosY + 1
cursorRenderFlag = true
cursorWhite = true
if cursorPosY + scrollPosY - 1 > #tmpdata then
renderFlag = false
cursorPosY = #tmpdata - scrollPosY + 1
end
if cursorPosY > height - 2 then
renderFlag = true
scrollPosY = scrollPosY + 1
cursorPosY = height - 2
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollLeft()
cursorRenderFlag = true
cursorWhite = true
if cursorPosX > 1 then
if cursorPosX <= unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2 then
cursorPosX = cursorPosX - 1
elseif unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 1 > 1 then
cursorPosX = unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 1
end
elseif scrollPosX > 1 then
scrollPosX = scrollPosX - 1
renderFlag = true
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollRight()
cursorRenderFlag = true
cursorWhite = true
if cursorPosX <= unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 1 then
cursorPosX = cursorPosX + 1
end
if cursorPosX > width then
cursorPosX = width
scrollPosX = scrollPosX + 1
renderFlag = true
end
end
local function processEvent(args)
renderFlag, cursorRenderFlag = false, false
if args[1] == "key_down" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if keyboard.ctrlDown then
return false, false, key
end
if key == "down" and cursorPosY < #tmpdata then
scrollDown()
end
if key == "up" then
scrollUp()
end
if key == "left" then
scrollLeft()
end
if key == "right" then
scrollRight()
end
if key == "enter" then
changesMade = true
renderFlag = true
cursorWhite = true
table.insert(tmpdata, cursorPosY + 1, tmpdata[cursorPosY]:sub(cursorPosX))
tmpdata[cursorPosY] = tmpdata[cursorPosY]:sub(1, cursorPosX - 1)
cursorPosX = 1
cursorPosY = cursorPosY + 1
scrollPosX = 1
if cursorPosY > height - 2 then
scrollPosY = scrollPosY + 1
cursorPosY = height - 2
end
end
if key == "back" then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
if cursorPosY + scrollPosY - 1 > 1 then
cursorPosY = cursorPosY - 1
if cursorPosY < 1 then
scrollPosY = scrollPosY - 1
cursorPosY = 1
end
if scrollPosY < 1 then
scrollPosY = 1
end
cursorPosX = unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2
if cursorPosX > width then
scrollPosX = cursorPosX - width + 1
cursorPosX = width
end
tmpdata[cursorPosY] = tmpdata[cursorPosY] .. tmpdata[cursorPosY + 1]
table.remove(tmpdata, cursorPosY + 1)
renderFlag = true
else
tmpdata[cursorPosY] = tmpdata[cursorPosY]:sub(1, cursorPosX + scrollPosX - 3) .. tmpdata[cursorPosY]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = math.min(cursorPosX - 1, unicode.wlen(tmpdata[cursorPosY]) + 1)
if cursorPosX < 1 then
cursorPosX = 1
scrollPosX = scrollPosX - 1
renderFlag = true
else
rawset(1, cursorPosY - scrollPosY + 1, tmpdata[cursorPosY]:sub(scrollPosX) .. " ")
end
end
end
if args[3] >= 32 and args[3] <= 126 then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
tmpdata[cursorPosY] = tmpdata[cursorPosY]:sub(1, cursorPosX + scrollPosX - 2) .. unicode.char(args[3]) .. tmpdata[cursorPosY]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY])) + 1
--ocelot.log(tostring(cursorPosX))
if cursorPosX > width then
cursorPosX = width
scrollPosX = scrollPosX + 1
renderFlag = true
else
rawset(1, cursorPosY - scrollPosY + 1, tmpdata[cursorPosY]:sub(scrollPosX))
end
end
elseif args[1] == "scroll" then
if args[5] == 1 then
for i = 1, scrollSpeed do
scrollUp()
end
elseif args[5] == -1 and cursorPosY < #tmpdata then
for i = 1, scrollSpeed do
scrollDown()
end
end
end
return renderFlag, cursorRenderFlag
end
local function save()
rawset(1, height - 1, "\27[107m\27[30m" .. string.rep(" ", width))
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local savepath = read(nil, "\27[107m\27[30mSave location: ", filepath)
if fs.exists(savepath) then
rawset(1, height - 1, "\27[107m\27[30m" .. string.rep(" ", width))
local answer = read(nil, "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] ")
if answer:lower() == "n" then
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
return
end
end
local handle, errorMessage = fs.open(savepath, "w")
if handle then
handle:write(table.concat(tmpdata, "\n"))
handle:close()
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
else
rawset(1, height - 1, "\27[107m\27[30mERROR: " .. errorMessage:gsub("\n", "") .. string.rep(" ", width))
end
changesMade = false
end
render()
while true do
local args = {event.pull(0.5)}
local renderFlag, cursorRenderFlag, specialKey = false, false, nil
local previousCursorX, previousCursorY = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2), cursorPosY
if args and args[1] then
cursorWhite = true
renderFlag, cursorRenderFlag, specialKey = processEvent(args)
if specialKey == "x" then
if changesMade then
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local response = read(nil, "\27[107m\27[30mWould you like to save changes? [Y/n] ")
if response:lower() ~= "n" then
save()
end
end
gpu.freeAllBuffers()
clear()
return
end
if specialKey == "s" then
save()
end
repeat
args = {event.pull("key_down", 0)}
if args and args[1] then
processEvent(args)
end
until not args or not args[1]
else
cursorWhite = not cursorWhite
cursorRenderFlag = true
end
if cursorRenderFlag then
local char = gpu.get(previousCursorX, previousCursorY)
rawset(previousCursorX, previousCursorY, char)
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
if realCursorX < 1 then
scrollPosX = scrollPosX + realCursorX - 1
cursorPosX = 1
realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
end
local char = gpu.get(realCursorX, cursorPosY)
if cursorWhite then
rawset(realCursorX, cursorPosY, "\27[107m\27[30m" .. char .. "\27[0m")
else
rawset(realCursorX, cursorPosY, char)
end
end
if renderFlag then
render()
end
end
+12
View File
@@ -21,6 +21,18 @@ if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
data = data .. (tmpdata or "") data = data .. (tmpdata or "")
until not tmpdata until not tmpdata
print(data) print(data)
local aliases = table.copy(shell.aliases)
if table.find(aliases, command) then
local aliasIndex = table.find(aliases, command)
local aliasString = "Aliases:\n " .. aliasIndex
aliases[aliasIndex] = nil
while table.find(aliases, command) do
aliasIndex = table.find(aliases, command)
aliasString = aliasString .. ", " .. aliasIndex
aliases[aliasIndex] = nil
end
print(aliasString)
end
else else
print("Could not find help file for: " .. command .. ".") print("Could not find help file for: " .. command .. ".")
end end
+3
View File
@@ -13,3 +13,6 @@ All current Halyde shell commands:
You can get additional information on any app or command by running: You can get additional information on any app or command by running:
help [COMMAND] help [COMMAND]
In the help documentation, an asterisk (*) next to an argument means it is optional.
This is excluding flags, which are all optional.
+1 -1
View File
@@ -1,7 +1,7 @@
Usage: help [COMMAND] Usage: help [COMMAND]
Displays info on the command specified, or a list of commands if one is not specified. Displays info on the command specified, or a list of commands if one is not specified.
COMMAND Command to display information on. COMMAND* Command to display information on.
Examples: Examples:
help Displays a list of all default commands available. help Displays a list of all default commands available.
+1 -1
View File
@@ -2,7 +2,7 @@ Usage: ls [PATH]
Lists all files and directories in the specified path, or in the shell working directory if the path isn't specified. 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. 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. PATH* Path to the folder to list files and directories from.
Examples: Examples:
ls Lists all files and directories from the current shell working directory. ls Lists all files and directories from the current shell working directory.
+1 -1
View File
@@ -7,4 +7,4 @@ Removes files and directories.
Examples: Examples:
rm a.txt Removes a.txt in the current shell working directory. rm a.txt Removes a.txt in the current shell working directory.
rm -r -f /halyde/core/ Removes everything in /halyde/core forcedly and recursively. Note that trying this on a real machine will remove critical Halyde system files and cause it to stop working. rm -r -f /halyde/core/ Removes everything in /halyde/core/ forcedly and recursively.
+137
View File
@@ -0,0 +1,137 @@
local raster = import("raster")
local event = import("event")
-- Initialize the 3D renderer for a spinning cube
-- Using the raster library for drawing
-- Screen dimensions
local SCREEN_WIDTH, SCREEN_HEIGHT = component.invoke(component.list("gpu")(), "getResolution")
SCREEN_WIDTH, SCREEN_HEIGHT = SCREEN_WIDTH * 2, SCREEN_HEIGHT * 4
local CENTER_X = SCREEN_WIDTH / 2
local CENTER_Y = SCREEN_HEIGHT / 2
-- Cube properties
local CUBE_SIZE = 10
local increment = 0
local WHITE = 0xFFFFFF
local ROTATION_SPEED = 0.1
-- 3D cube vertices (centered at origin)
local vertices = {
{-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 0: left bottom back
{CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 1: right bottom back
{CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 2: right top back
{-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 3: left top back
{-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 4: left bottom front
{CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 5: right bottom front
{CUBE_SIZE, CUBE_SIZE, CUBE_SIZE}, -- 6: right top front
{-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE} -- 7: left top front
}
-- Cube edges defined by vertex indices
local edges = {
{0, 1}, {1, 2}, {2, 3}, {3, 0}, -- back face
{4, 5}, {5, 6}, {6, 7}, {7, 4}, -- front face
{0, 4}, {1, 5}, {2, 6}, {3, 7} -- connecting edges
}
-- Projection parameters
local FOV = 256 -- Field of view (distance from camera to screen)
local Z_OFFSET = 300 -- Distance from camera to cube center
-- Initialize rotation angles
local angleX, angleY, angleZ = 0, 0, 0
-- Matrix multiplication function (apply rotation to a 3D point)
local function rotatePoint(x, y, z)
-- Rotation around X axis
local cosX, sinX = math.cos(angleX), math.sin(angleX)
local y1 = y * cosX - z * sinX
local z1 = y * sinX + z * cosX
-- Rotation around Y axis
local cosY, sinY = math.cos(angleY), math.sin(angleY)
local x1 = x * cosY + z1 * sinY
local z2 = -x * sinY + z1 * cosY
-- Rotation around Z axis
local cosZ, sinZ = math.cos(angleZ), math.sin(angleZ)
local x2 = x1 * cosZ - y1 * sinZ
local y2 = x1 * sinZ + y1 * cosZ
return x2, y2, z2
end
-- Perspective projection function (3D to 2D)
local function projectPoint(x, y, z)
-- Apply perspective projection
local scale = FOV / (z + Z_OFFSET)
local x2d = x * scale + CENTER_X
local y2d = y * scale + CENTER_Y
return x2d, y2d
end
-- Render a single frame
local function renderFrame()
increment = increment + 0.05
CUBE_SIZE = (math.sin(increment) + 1) * 25
vertices = {
{-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 0: left bottom back
{CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 1: right bottom back
{CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 2: right top back
{-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 3: left top back
{-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 4: left bottom front
{CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 5: right bottom front
{CUBE_SIZE, CUBE_SIZE, CUBE_SIZE}, -- 6: right top front
{-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE} -- 7: left top front
}
-- Update rotation angles
raster.clear()
angleX = angleX + ROTATION_SPEED
angleY = angleY + ROTATION_SPEED * 0.7
angleZ = angleZ + ROTATION_SPEED * 0.5
-- Project all vertices
local projectedPoints = {}
for i, vertex in ipairs(vertices) do
-- Rotate the point
local x, y, z = rotatePoint(vertex[1], vertex[2], vertex[3])
-- Project the point to 2D
local x2d, y2d = projectPoint(x, y, z)
projectedPoints[i] = {x2d, y2d}
end
-- Draw all edges
for _, edge in ipairs(edges) do
local p1 = projectedPoints[edge[1] + 1] -- +1 because Lua indices start at 1
local p2 = projectedPoints[edge[2] + 1]
-- Draw the line
raster.drawLine(p1[1], p1[2], p2[1], p2[2], WHITE)
end
-- Render the frame
raster.update()
end
-- Main program
function main()
-- Initialize raster engine
raster.init()
-- Main loop (assume this is called repeatedly by the host environment)
while true do
renderFrame()
if event.pull("key_down", 0) then
raster.free()
break
end
end
-- Return a reference to renderFrame so it can be called for animation
return renderFrame
end
-- Start the program
return main()
+3
View File
@@ -9,8 +9,11 @@ local shellcfg = {
["rename"] = "mv", ["rename"] = "mv",
["ren"] = "mv", ["ren"] = "mv",
["dir"] = "ls", ["dir"] = "ls",
["list"] = "ls",
["man"] = "help", ["man"] = "help",
["del"] = "rm", ["del"] = "rm",
["delete"] = "rm",
["remove"] = "rm",
[".."] = "cd .." [".."] = "cd .."
}, ["defaultWorkingDirectory"] = "/home/" -- the working directory that gets set when halyde starts }, ["defaultWorkingDirectory"] = "/home/" -- the working directory that gets set when halyde starts
} }
+1 -1
View File
@@ -1,7 +1,7 @@
local loadfile = ... local loadfile = ...
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile) local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
_G._OSVERSION = "Halyde 0.9.0" _G._OSVERSION = "Halyde 0.10.0"
function _G.import(module, ...) function _G.import(module, ...)
local args = table.pack(...) local args = table.pack(...)
+24 -5
View File
@@ -4,10 +4,25 @@ _G.cormgr.corList = {}
--local ocelot = component.proxy(component.list("ocelot")()) --local ocelot = component.proxy(component.list("ocelot")())
local filesystem = import("filesystem") local filesystem = import("filesystem")
local gpu = component.proxy(component.list("gpu")())
function _G.cormgr.loadCoroutine(path) function _G.cormgr.loadCoroutine(path, ...)
local args = {...}
local cor = coroutine.create(function() local cor = coroutine.create(function()
import(path) local result, errorMessage = xpcall(function(...)
import(...)
end, function(errorMessage)
return errorMessage .. "\n \n" .. debug.traceback()
end, path, table.unpack(args))
if not result then
if print then
gpu.freeAllBuffers()
print("\n\27[91m" .. errorMessage)
else
error(errorMessage)
end
end
--import(path, table.unpack(args))
end) end)
table.insert(_G.cormgr.corList, cor) table.insert(_G.cormgr.corList, cor)
end end
@@ -22,17 +37,21 @@ end
local function runCoroutines() local function runCoroutines()
for i = 1, #_G.cormgr.corList do for i = 1, #_G.cormgr.corList do
local result, errorMessage = coroutine.resume(_G.cormgr.corList[i]) if cormgr.corList[i] then
local result, errorMessage = coroutine.resume(cormgr.corList[i])
if cormgr.corList[i] then
if not result then if not result then
handleError(errorMessage) handleError(errorMessage)
end end
if coroutine.status(_G.cormgr.corList[i]) == "dead" then if coroutine.status(cormgr.corList[i]) == "dead" then
table.remove(_G.cormgr.corList, i) table.remove(cormgr.corList, i)
i = i - 1 i = i - 1
end end
--computer.pullSignal(0) --computer.pullSignal(0)
--coroutine.yield() --coroutine.yield()
end end
end
end
end end
local handle = filesystem.open("/halyde/config/startupapps.cfg", "r") local handle = filesystem.open("/halyde/config/startupapps.cfg", "r")
+27
View File
@@ -2,6 +2,9 @@ _G.evmgr = {}
_G.evmgr.eventQueue = {} _G.evmgr.eventQueue = {}
local maxEventQueueLength = 10 -- increase if events start getting dropped local maxEventQueueLength = 10 -- increase if events start getting dropped
keyboard.ctrlDown = false
keyboard.altDown = false
--local ocelot = component.proxy(component.list("ocelot")()) --local ocelot = component.proxy(component.list("ocelot")())
while true do while true do
@@ -11,6 +14,30 @@ while true do
if args and args[1] then if args and args[1] then
--ocelot.log("Sending signal "..args..","..computer.uptime()) --ocelot.log("Sending signal "..args..","..computer.uptime())
table.insert(evmgr.eventQueue, args) table.insert(evmgr.eventQueue, args)
if keyboard then
if args[1] == "key_down" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if key == "lcontrol" then
keyboard.ctrlDown = true
elseif key == "lmenu" then
keyboard.altDown = true
elseif key == "c" and keyboard.ctrlDown and keyboard.altDown then
if print then
print("\n\27[91mCoroutine "..tostring(#cormgr.corList).." killed.")
end
cormgr.corList[#cormgr.corList] = nil
end
elseif args[1] == "key_up" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if key == "lcontrol" then
keyboard.ctrlDown = false
elseif key == "lmenu" then
keyboard.altDown = false
end
end
end
while #evmgr.eventQueue > maxEventQueueLength do while #evmgr.eventQueue > maxEventQueueLength do
--ocelot.log("Queue length breach, removing first signal") --ocelot.log("Queue length breach, removing first signal")
table.remove(evmgr.eventQueue, 1) table.remove(evmgr.eventQueue, 1)
+1 -2
View File
@@ -1,5 +1,4 @@
_G.keyboard = {pressedChars = {}, pressedCodes = {}} _G.keyboard = {["keys"] = {}}
_G.keyboard.keys = {}
keyboard.keys["1"] = 0x02 keyboard.keys["1"] = 0x02
keyboard.keys["2"] = 0x03 keyboard.keys["2"] = 0x03
+17 -13
View File
@@ -3,11 +3,22 @@ import("/halyde/core/termlib.lua")
local event = import("event") local event = import("event")
--local ocelot = component.proxy(component.list("ocelot")()) --local ocelot = component.proxy(component.list("ocelot")())
local filesystem = import("filesystem") local filesystem = import("filesystem")
local gpu = component.proxy(component.list("gpu")())
_G.shell = {} _G.shell = {}
_G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"] _G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"]
_G.shell.aliases = shellcfg["aliases"] _G.shell.aliases = shellcfg["aliases"]
local function runAsCoroutine(path, ...)
--ocelot.log("running " .. path .. " as coroutine")
cormgr.loadCoroutine(path, ...)
local corIndex = #cormgr.corList
local cor = cormgr.corList[#cormgr.corList]
repeat
coroutine.yield()
until cormgr.corList[corIndex] ~= cor
end
function _G.shell.run(command) function _G.shell.run(command)
checkArg(1, command, "string") checkArg(1, command, "string")
if shell.aliases[command:match("[^ ]+")] then if shell.aliases[command:match("[^ ]+")] then
@@ -48,14 +59,14 @@ function _G.shell.run(command)
foundfile = true foundfile = true
local path = args[1] local path = args[1]
table.remove(args, 1) table.remove(args, 1)
import(path, table.unpack(args)) runAsCoroutine(path, table.unpack(args))
else else
for _, item in pairs(shellcfg["path"]) do for _, item in pairs(shellcfg["path"]) do
if filesystem.exists(item..args[1]) then if filesystem.exists(item..args[1]) then
foundfile = true foundfile = true
local path = item..args[1] local path = item..args[1]
table.remove(args, 1) table.remove(args, 1)
import(path, table.unpack(args)) runAsCoroutine(path, table.unpack(args))
break break
else -- try to look for it without the file extension else -- try to look for it without the file extension
local files = filesystem.list(item) local files = filesystem.list(item)
@@ -63,15 +74,7 @@ function _G.shell.run(command)
if args[1] == file:match("(.+)%.[^%.]+$") then if args[1] == file:match("(.+)%.[^%.]+$") then
foundfile = true foundfile = true
table.remove(args, 1) table.remove(args, 1)
local function runCommand() runAsCoroutine(item..file, table.unpack(args))
import(item..file, table.unpack(args))
end
local result, reason = xpcall(runCommand, function(errMsg)
return errMsg .. "\n\n" .. debug.traceback()
end)
if not result then
print("\27[91m" .. reason)
end
break break
end end
end end
@@ -87,9 +90,10 @@ print(shellcfg["startupMessage"])
while true do while true do
coroutine.yield() coroutine.yield()
-- print(shell.workingDirectory .. " >") -- print(shell.workingDirectory .. " >")
print(shellcfg["prompt"]:format(shell.workingDirectory),false) --print(shellcfg["prompt"]:format(shell.workingDirectory),false)
-- termlib.cursorPosX = #(shell.workingDirectory .. " > ") -- termlib.cursorPosX = #(shell.workingDirectory .. " > ")
-- termlib.cursorPosY = termlib.cursorPosY - 1 -- termlib.cursorPosY = termlib.cursorPosY - 1
local shellCommand = read("shell") local shellCommand = read("shell", shellcfg["prompt"]:format(shell.workingDirectory))
shell.run(shellCommand) shell.run(shellCommand)
gpu.freeAllBuffers()
end end
+37 -26
View File
@@ -1,6 +1,7 @@
local event = import("event") local event = import("event")
--local keyboard = import("keyboard") --local keyboard = import("keyboard")
--local ocelot = component.proxy(component.list("ocelot")())
local gpu = component.proxy(component.list("gpu")()) -- replace with component.gpu once implemented local gpu = component.proxy(component.list("gpu")()) -- replace with component.gpu once implemented
_G.termlib = {} _G.termlib = {}
termlib.cursorPosX = 1 termlib.cursorPosX = 1
@@ -41,7 +42,7 @@ gpu.setForeground(defaultForegroundColor)
gpu.setBackground(defaultBackgroundColor) gpu.setBackground(defaultBackgroundColor)
local function scrollDown() local function scrollDown()
if gpu.copy(0,1,width,height,0,-1) then if gpu.copy(1,1,width,height,0,-1) then
local prevForeground = gpu.getForeground() local prevForeground = gpu.getForeground()
local prevBackground = gpu.getBackground() local prevBackground = gpu.getBackground()
gpu.setForeground(defaultForegroundColor) gpu.setForeground(defaultForegroundColor)
@@ -61,7 +62,7 @@ local function newLine()
end end
end end
function parseCodeNumbers(code) local function parseCodeNumbers(code)
o = {} o = {}
for num in code:sub(3,-2):gmatch("[^;]+") do for num in code:sub(3,-2):gmatch("[^;]+") do
table.insert(o,tonumber(num)) table.insert(o,tonumber(num))
@@ -69,13 +70,16 @@ function parseCodeNumbers(code)
return o return o
end end
function _G.print(text,endNewLine) function _G.print(text, endNewLine, wordWrap)
-- you don't know how tiring this was just for ANSI escape code support -- you don't know how tiring this was just for ANSI escape code support
if endNewLine==nil then if endNewLine == nil then
endNewLine = true endNewLine = true
end end
if wordWrap == nil then
wordWrap = true
end
if not text or not tostring(text) then if not text or not tostring(text) then
return return
@@ -93,7 +97,7 @@ function _G.print(text,endNewLine)
end end
gpu.set(termlib.cursorPosX,termlib.cursorPosY,section) gpu.set(termlib.cursorPosX,termlib.cursorPosY,section)
termlib.cursorPosX = termlib.cursorPosX+unicode.wlen(section) termlib.cursorPosX = termlib.cursorPosX+unicode.wlen(section)
if termlib.cursorPosX>width then if termlib.cursorPosX>width and wordWrap then
newLine() newLine()
end end
section="" section=""
@@ -162,13 +166,18 @@ end
function _G.clear() function _G.clear()
local xRes, yRes = gpu.getResolution() local xRes, yRes = gpu.getResolution()
gpu.setForeground(defaultForegroundColor)
gpu.setBackground(defaultBackgroundColor)
gpu.fill(1,1,xRes,yRes," ") gpu.fill(1,1,xRes,yRes," ")
termlib.cursorPosX, termlib.cursorPosY = 1, 1 termlib.cursorPosX, termlib.cursorPosY = 1, 1
end end
function _G.read(readHistoryType) function _G.read(readHistoryType, prefix, defaultText)
checkArg(1, readHistoryType, "string", "nil") checkArg(1, readHistoryType, "string", "nil")
local curtext = "" checkArg(2, prefix, "string", "nil")
checkArg(3, defaultText, "string", "nil")
local curtext = defaultText or ""
local prefix = prefix or ""
local RHIndex local RHIndex
if readHistoryType then if readHistoryType then
if not termlib.readHistory[readHistoryType] then if not termlib.readHistory[readHistoryType] then
@@ -179,13 +188,10 @@ function _G.read(readHistoryType)
RHIndex = #termlib.readHistory[readHistoryType] -- read history index RHIndex = #termlib.readHistory[readHistoryType] -- read history index
end end
local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY
print(prefix .. curtext .. "\27[107m ", false)
local cursorWhite = true local cursorWhite = true
while true do while true do
if cursorWhite then --ocelot.log(curtext)
print("\27[107m ", false)
else
print(" ", false)
end
termlib.cursorPosX = termlib.cursorPosX - 1 termlib.cursorPosX = termlib.cursorPosX - 1
local args = {event.pull("key_down", 0.5)} local args = {event.pull("key_down", 0.5)}
if args[4] then if args[4] then
@@ -194,39 +200,34 @@ function _G.read(readHistoryType)
local key = keyboard.keys[keycode] local key = keyboard.keys[keycode]
if key == "up" and readHistoryType then if key == "up" and readHistoryType then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext .. " ", false) print(prefix .. curtext .. " ", false)
RHIndex = RHIndex - 1 RHIndex = RHIndex - 1
if RHIndex <= 0 then if RHIndex <= 0 then
RHIndex = 1 RHIndex = 1
end end
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false) print(prefix .. termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false)
curtext = termlib.readHistory[readHistoryType][RHIndex] curtext = termlib.readHistory[readHistoryType][RHIndex]
end end
if key == "down" and readHistoryType then if key == "down" and readHistoryType then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext .. " ", false) print(prefix .. curtext .. " ", false)
RHIndex = RHIndex + 1 RHIndex = RHIndex + 1
if RHIndex > #termlib.readHistory[readHistoryType] then if RHIndex > #termlib.readHistory[readHistoryType] then
RHIndex = #termlib.readHistory[readHistoryType] RHIndex = #termlib.readHistory[readHistoryType]
end end
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false) print(prefix .. termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false)
curtext = termlib.readHistory[readHistoryType][RHIndex] curtext = termlib.readHistory[readHistoryType][RHIndex]
end end
if args[3] >= 32 and args[3] <= 126 then
curtext = curtext .. (unicode.char(args[3]) or "")
if readHistoryType then
termlib.readHistory[readHistoryType][RHIndex] = curtext
end
else
if key == "back" then if key == "back" then
curtext = curtext:sub(1, #curtext-1) curtext = curtext:sub(1, #curtext-1)
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext.." ", false) print(prefix .. curtext.." ", false)
elseif key == "enter" then end
if key == "enter" then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext .. " ") print(prefix .. curtext .. " ")
if readHistoryType then if readHistoryType then
while #termlib.readHistory[readHistoryType] > 50 do while #termlib.readHistory[readHistoryType] > 50 do
table.remove(termlib.readHistory[readHistoryType], 1) table.remove(termlib.readHistory[readHistoryType], 1)
@@ -234,11 +235,21 @@ function _G.read(readHistoryType)
end end
return curtext return curtext
end end
if args[3] >= 32 and args[3] <= 126 then
curtext = curtext .. (unicode.char(args[3]) or "")
if readHistoryType then
termlib.readHistory[readHistoryType][RHIndex] = curtext
end
end end
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext, false) print(prefix .. curtext, false)
else else
cursorWhite = not cursorWhite cursorWhite = not cursorWhite
end end
if cursorWhite then
print("\27[107m ", false)
else
print(" ", false)
end
end end
end end
+6 -1
View File
@@ -48,7 +48,12 @@ function filesystem.open(path, mode) -- opens a file and returns its handle
return nil, "invalid handle type" return nil, "invalid handle type"
end end
local address, absPath = filesystem.processPath(path) local address, absPath = filesystem.processPath(path)
local handle = component.invoke(address, "open", absPath, mode) local handleArgs = {component.invoke(address, "open", absPath, mode)}
local handle = handleArgs[1]
if not handle then
return table.unpack(handleArgs)
end
handleArgs = nil
local properHandle = {} local properHandle = {}
properHandle.handle = handle properHandle.handle = handle
properHandle.address = address properHandle.address = address
+10 -5
View File
@@ -41,11 +41,8 @@ function raster.init(width, height, bgcolor)
width, height = raster.units.charToBraille(width, height) width, height = raster.units.charToBraille(width, height)
bgcolor = bgcolor or raster.defaultBackgroundColor; bgcolor = bgcolor or raster.defaultBackgroundColor
for i = 1, width*height do
display[i] = bgcolor
end
raster.displayWidth = width raster.displayWidth = width
raster.displayHeight = height raster.displayHeight = height
@@ -145,10 +142,10 @@ function raster.update()
raster.get(x,y), raster.get(x,y),
raster.get(x,y+1), raster.get(x,y+1),
raster.get(x,y+2), raster.get(x,y+2),
raster.get(x,y+3),
raster.get(x+1,y), raster.get(x+1,y),
raster.get(x+1,y+1), raster.get(x+1,y+1),
raster.get(x+1,y+2), raster.get(x+1,y+2),
raster.get(x,y+3),
raster.get(x+1,y+3) raster.get(x+1,y+3)
} }
local colorA = nil local colorA = nil
@@ -170,6 +167,14 @@ function raster.update()
end end
end end
function raster.clear()
if renderBuffer~=nil then
gpu.setActiveBuffer(renderBuffer)
end
clear()
display = {}
end
function raster.free() function raster.free()
if renderBuffer==nil then if renderBuffer==nil then
return true return true
+67
View File
@@ -0,0 +1,67 @@
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line!
This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line!
This is a short line!
This is a short line!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This is the last line!