v2.0.0 - Overhauled the 'read' function in the terminal library, added a new Unicode library, and various functions added to the filesystem library.
In older versions, the 'read' function in the terminal library (termlib.lua) was most likely vibecoded by Fluxdrive, and was basically very inefficient. The new Unicode library includes functions for getting a code point from a character, and iterating Unicode characters from a string or an iterator function that returns every byte. It is now possible, in the filesystem library, to make virtual 'read streams' (filesystem.makeReadStream), which does the same thing as opening a file with some specific content. There are some new functions in read streams, which allows you to loop through bytes (open(...):iterateBytes), and loop through Unicode characters (open(...):iterateUnicodeChars). The edit app will be updated to v1.2.1 for importing the new Unicode library.
This commit is contained in:
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
local agcfg = {
|
local agcfg = {
|
||||||
["halyde"] = {
|
["halyde"] = {
|
||||||
["maindir"] = "",
|
["maindir"] = "",
|
||||||
["version"] = "1.15.0",
|
["version"] = "2.0.0",
|
||||||
["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.",
|
["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.",
|
||||||
["directories"] = {
|
["directories"] = {
|
||||||
"halyde/apps",
|
"halyde/apps",
|
||||||
@@ -82,7 +82,7 @@ local agcfg = {
|
|||||||
},
|
},
|
||||||
["edit"] = {
|
["edit"] = {
|
||||||
["maindir"] = "",
|
["maindir"] = "",
|
||||||
["version"] = "1.2.0",
|
["version"] = "1.2.1",
|
||||||
["description"] = "The default text editor for Halyde.",
|
["description"] = "The default text editor for Halyde.",
|
||||||
["files"] = {
|
["files"] = {
|
||||||
"halyde/apps/edit.lua",
|
"halyde/apps/edit.lua",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ local file = ...
|
|||||||
local fs = import("filesystem")
|
local fs = import("filesystem")
|
||||||
local event = import("event")
|
local event = import("event")
|
||||||
local component = import("component")
|
local component = import("component")
|
||||||
|
local unicode = import("unicode")
|
||||||
local gpu = component.gpu
|
local gpu = component.gpu
|
||||||
local width, height = gpu.getResolution()
|
local width, height = gpu.getResolution()
|
||||||
local scrollPosX, scrollPosY = 1, 1
|
local scrollPosX, scrollPosY = 1, 1
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ local args = {...}
|
|||||||
local target = args[1]
|
local target = args[1]
|
||||||
args = nil
|
args = nil
|
||||||
local fs = import("filesystem")
|
local fs = import("filesystem")
|
||||||
|
local unicode = import("unicode")
|
||||||
local maxLength = 0
|
local maxLength = 0
|
||||||
local margin = 2 -- minimum space between filename and size
|
local margin = 2 -- minimum space between filename and size
|
||||||
local dirTable = {}
|
local dirTable = {}
|
||||||
|
|||||||
@@ -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 1.15.0"
|
_G._OSVERSION = "Halyde 2.0.0"
|
||||||
_G._OSLOGO = ""
|
_G._OSLOGO = ""
|
||||||
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
||||||
repeat
|
repeat
|
||||||
|
|||||||
+153
-178
@@ -1,3 +1,4 @@
|
|||||||
|
local unicode = import("unicode")
|
||||||
local event = import("event")
|
local event = import("event")
|
||||||
--local keyboard = import("keyboard")
|
--local keyboard = import("keyboard")
|
||||||
|
|
||||||
@@ -86,8 +87,8 @@ function termlib.write(text, textWrap)
|
|||||||
if text:find("\a") then
|
if text:find("\a") then
|
||||||
computer.beep()
|
computer.beep()
|
||||||
end
|
end
|
||||||
text = "\27[0m" .. text:gsub("\t", " ")
|
|
||||||
text = tostring(text)
|
text = tostring(text)
|
||||||
|
text = "\27[0m" .. text:gsub("\t", " ")
|
||||||
readBreak = 0
|
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.
|
-- 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.
|
||||||
-- unfortunately, changing the "i" variable would have unpredictable effects, so to not risk anything, this workaround was done.
|
-- unfortunately, changing the "i" variable would have unpredictable effects, so to not risk anything, this workaround was done.
|
||||||
@@ -187,203 +188,177 @@ function _G.clear()
|
|||||||
termlib.cursorPosX, termlib.cursorPosY = 1, 1
|
termlib.cursorPosX, termlib.cursorPosY = 1, 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- god i hope this silly claude code works first try
|
function _G.read(readHistoryType, prefix, defaultText, maxChars)
|
||||||
-- Fluxdrive caught vibe coding???
|
|
||||||
function _G.read(readHistoryType, prefix, defaultText)
|
|
||||||
checkArg(1, readHistoryType, "string", "nil")
|
checkArg(1, readHistoryType, "string", "nil")
|
||||||
checkArg(2, prefix, "string", "nil")
|
checkArg(2, prefix, "string", "nil")
|
||||||
checkArg(3, defaultText, "string", "nil")
|
checkArg(3, defaultText, "string", "nil")
|
||||||
local curtext = defaultText or ""
|
checkArg(4, maxChars, "number", "nil")
|
||||||
local prefix = prefix or ""
|
maxChars = maxChars or math.huge
|
||||||
local textCursorPos = unicode.wlen(curtext) + 1 -- Position within the text (1-based)
|
|
||||||
|
|
||||||
local RHIndex
|
local text = defaultText or ""
|
||||||
|
|
||||||
|
local historyIdx
|
||||||
if readHistoryType then
|
if readHistoryType then
|
||||||
if not termlib.readHistory[readHistoryType] then
|
if not termlib.readHistory[readHistoryType] then
|
||||||
termlib.readHistory[readHistoryType] = {curtext}
|
termlib.readHistory[readHistoryType] = {text}
|
||||||
elseif termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType]] ~= "" then
|
elseif termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType] ] ~= "" then
|
||||||
table.insert(termlib.readHistory[readHistoryType], curtext)
|
table.insert(termlib.readHistory[readHistoryType], text)
|
||||||
end
|
end
|
||||||
RHIndex = #termlib.readHistory[readHistoryType]
|
historyIdx = #termlib.readHistory[readHistoryType]
|
||||||
end
|
end
|
||||||
|
|
||||||
local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY
|
local cur = unicode.len(text)+1
|
||||||
|
if prefix then termlib.write(prefix) end
|
||||||
-- Track maximum text length to ensure proper clearing across wrapped lines
|
local startX, startY = termlib.cursorPosX, termlib.cursorPosY
|
||||||
local maxTextLength = unicode.wlen(prefix .. curtext)
|
local fg, bg = gpu.getForeground(), gpu.getBackground()
|
||||||
|
local cursorBlink = true
|
||||||
-- Function to calculate how many lines text will occupy
|
local function get(idx)
|
||||||
local function calculateLines(text)
|
idx=startX+idx-1
|
||||||
local totalWidth = unicode.wlen(prefix .. text)
|
return gpu.get(idx%width,startY+(idx//width))
|
||||||
local width = gpu.getResolution()
|
|
||||||
return math.ceil(totalWidth / width)
|
|
||||||
end
|
end
|
||||||
|
local function checkScroll(y)
|
||||||
-- Track maximum lines used
|
for i=1,y-height do
|
||||||
local maxLinesUsed = calculateLines(curtext)
|
scrollDown()
|
||||||
|
startY=startY-1
|
||||||
-- Function to redraw the input line with cursor
|
end
|
||||||
local function redrawLine()
|
return math.min(y,height)
|
||||||
local startX, startY = cursorPosX, cursorPosY
|
end
|
||||||
|
local function set(idx,chr,rev)
|
||||||
-- Calculate current and max lines needed
|
if chr==nil or chr=="" then return end
|
||||||
local currentLines = calculateLines(curtext)
|
if rev then
|
||||||
local linesToClear = math.max(maxLinesUsed, currentLines)
|
gpu.setForeground(bg)
|
||||||
|
gpu.setBackground(fg)
|
||||||
-- Clear all potentially used lines
|
else
|
||||||
for i = 0, linesToClear - 1 do
|
gpu.setForeground(fg)
|
||||||
termlib.cursorPosX, termlib.cursorPosY = 1, startY + i
|
gpu.setBackground(bg)
|
||||||
if startY + i <= height then
|
end
|
||||||
local width = gpu.getResolution()
|
idx=startX+idx-1
|
||||||
termlib.write(string.rep(" ", width))
|
local setX, setY = (idx-1)%width+1, startY+((idx-1)//width+1)-1
|
||||||
|
setY = checkScroll(setY)
|
||||||
|
gpu.set(setX,setY,unicode.sub(chr,1,width-setX+1))
|
||||||
|
for i=1,math.ceil((#chr+setX-1)/width)+1 do
|
||||||
|
gpu.set(1,setY+i,unicode.sub(chr,2-setX+i*width,width+i*width-setX))
|
||||||
|
setY = checkScroll(setY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local function strDef(a,b)
|
||||||
-- Reset cursor to start position
|
if #a==0 then return b end
|
||||||
termlib.cursorPosX, termlib.cursorPosY = startX, startY
|
return a
|
||||||
|
|
||||||
-- Update tracking variables
|
|
||||||
maxTextLength = math.max(maxTextLength, unicode.wlen(prefix .. curtext))
|
|
||||||
maxLinesUsed = math.max(maxLinesUsed, currentLines)
|
|
||||||
|
|
||||||
-- 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))
|
|
||||||
|
|
||||||
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
|
end
|
||||||
|
local function curPos(cur)
|
||||||
|
-- component.ocelot.log(table.concat({cur,unicode.wlen(unicode.sub(text,1,cur)),unicode.len(text)}," "))
|
||||||
|
return unicode.wlen(unicode.sub(text,1,cur-1))+1
|
||||||
|
end
|
||||||
|
local function add(chr)
|
||||||
|
if type(chr)~="string" or #chr==0 then return end
|
||||||
|
if unicode.len(text)>=maxChars then return end
|
||||||
|
if maxChars<math.huge then
|
||||||
|
chr=unicode.sub(chr,1,maxChars-unicode.len(text))
|
||||||
|
end
|
||||||
|
text=unicode.sub(text,1,cur-1)..chr..unicode.sub(text,cur)
|
||||||
|
set(curPos(cur),chr,false)
|
||||||
|
cur=math.min(cur+unicode.len(chr),maxChars+1)
|
||||||
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
|
||||||
|
cursorBlink = true
|
||||||
|
set(curPos(cur+1),unicode.sub(text,cur+1),false)
|
||||||
|
end
|
||||||
|
local function moveCur(dir)
|
||||||
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
|
||||||
|
cur=math.max(math.min(cur+dir,unicode.len(text)+1),1)
|
||||||
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
|
||||||
|
cursorBlink = true
|
||||||
|
end
|
||||||
|
local function isLine(chr)
|
||||||
|
return chr=="\n" or chr=="\r"
|
||||||
|
end
|
||||||
|
--[[ gpu.set(startX,startY,unicode.sub(text,1,width-startX))
|
||||||
|
for i=1,(#text+startX)//width-1 do
|
||||||
|
gpu.set(startX,startY+i,unicode.sub(text,1+i*width,width-startX+i*width))
|
||||||
|
end ]]
|
||||||
|
set(1,text,false)
|
||||||
|
set(curPos(cur)," ",true)
|
||||||
|
|
||||||
redrawLine()
|
local function reprint(new)
|
||||||
local cursorWhite = true
|
set(1,new..string.rep(" ",unicode.wlen(text)-unicode.wlen(new)+1),false)
|
||||||
|
cur=unicode.len(new)+1
|
||||||
|
text=new
|
||||||
|
set(curPos(cur)," ",true)
|
||||||
|
end
|
||||||
|
local function updateHistory()
|
||||||
|
if not readHistoryType then return end
|
||||||
|
termlib.readHistory[readHistoryType][historyIdx]=text
|
||||||
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local args = {event.pull("key_down", "clipboard", 0.5)}
|
local args = {event.pull("key_down", "clipboard", 0.5)}
|
||||||
|
if args and args[1] == "key_down" and args[4] then
|
||||||
if args[1] == "key_down" and args[4] then
|
local key = keyboard.keys[args[4]]
|
||||||
cursorWhite = true
|
if key=="up" and readHistoryType then
|
||||||
local keycode = args[4]
|
historyIdx=math.max(historyIdx-1,1)
|
||||||
local key = keyboard.keys[keycode]
|
reprint(termlib.readHistory[readHistoryType][historyIdx])
|
||||||
|
elseif key=="down" and readHistoryType then
|
||||||
-- Handle arrow keys
|
historyIdx=math.min(historyIdx+1,#termlib.readHistory[readHistoryType])
|
||||||
if key == "up" and readHistoryType then
|
reprint(termlib.readHistory[readHistoryType][historyIdx])
|
||||||
RHIndex = RHIndex - 1
|
elseif key=="left" then
|
||||||
if RHIndex <= 0 then
|
moveCur(-1)
|
||||||
RHIndex = 1
|
elseif key=="right" then
|
||||||
|
moveCur(1)
|
||||||
|
elseif key=="home" then
|
||||||
|
moveCur(-math.huge)
|
||||||
|
elseif key=="end" then
|
||||||
|
moveCur(math.huge)
|
||||||
|
elseif key=="back" and cur>1 then
|
||||||
|
text=unicode.sub(text,1,cur-2)..unicode.sub(text,cur)
|
||||||
|
cur=cur-1
|
||||||
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
|
||||||
|
cursorBlink = true
|
||||||
|
set(curPos(cur)+1,unicode.sub(text,cur+1).." ",false)
|
||||||
|
updateHistory()
|
||||||
|
elseif key=="delete" then
|
||||||
|
text = unicode.sub(text,1,cur-1)..unicode.sub(text,cur+1)
|
||||||
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),true)
|
||||||
|
cursorBlink = true
|
||||||
|
if cur<=unicode.len(text) then
|
||||||
|
set(curPos(cur+1),unicode.sub(text,cur+1).." ",false)
|
||||||
end
|
end
|
||||||
curtext = termlib.readHistory[readHistoryType][RHIndex]
|
updateHistory()
|
||||||
textCursorPos = unicode.wlen(curtext) + 1
|
elseif key=="enter" then
|
||||||
redrawLine()
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
|
||||||
|
break
|
||||||
elseif key == "down" and readHistoryType then
|
elseif not (args[3]<32 or (args[3]>0x7F and args[3]<=0x9F)) then
|
||||||
RHIndex = RHIndex + 1
|
add(unicode.char(args[3]) or " ")
|
||||||
if RHIndex > #termlib.readHistory[readHistoryType] then
|
updateHistory()
|
||||||
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
|
end
|
||||||
|
elseif args and args[1]=="clipboard" then
|
||||||
elseif args[1] == "clipboard" then
|
local clip = args[3]
|
||||||
-- Handle clipboard paste
|
if not args[3] then goto continue end
|
||||||
local text = args[3] or ""
|
while isLine(unicode.sub(clip,1,1)) do clip=unicode.sub(clip,2) end
|
||||||
local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0)
|
while isLine(unicode.sub(clip,-1)) do clip=unicode.sub(clip,1,-2) end
|
||||||
local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1))
|
add(clip)
|
||||||
curtext = beforeCursor .. text .. afterCursor
|
updateHistory()
|
||||||
textCursorPos = textCursorPos + #text
|
|
||||||
if readHistoryType then
|
|
||||||
termlib.readHistory[readHistoryType][RHIndex] = curtext
|
|
||||||
end
|
|
||||||
redrawLine()
|
|
||||||
|
|
||||||
else
|
else
|
||||||
-- Cursor blink timing
|
cursorBlink=not cursorBlink
|
||||||
cursorWhite = not cursorWhite
|
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),cursorBlink)
|
||||||
if cursorWhite then
|
end
|
||||||
redrawLine()
|
::continue::
|
||||||
else
|
end
|
||||||
-- Show cursor as normal character or space
|
|
||||||
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
|
if readHistoryType then
|
||||||
local beforeCursor = curtext:sub(1, utf8.offset(curtext, textCursorPos) - 1 or 0)
|
if termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType]]=="" then
|
||||||
local afterCursor = curtext:sub(utf8.offset(curtext, textCursorPos) or (#curtext + 1))
|
table.remove(termlib.readHistory[readHistoryType],#termlib.readHistory[readHistoryType])
|
||||||
termlib.write(prefix .. beforeCursor)
|
end
|
||||||
termlib.write(afterCursor:sub(1, 1) ~= "" and afterCursor:sub(1, 1) or " ")
|
if historyIdx<#termlib.readHistory[readHistoryType] then
|
||||||
termlib.write(afterCursor:sub(2))
|
table.remove(termlib.readHistory[readHistoryType],historyIdx)
|
||||||
end
|
table.insert(termlib.readHistory[readHistoryType],text)
|
||||||
|
end
|
||||||
|
while #termlib.readHistory[readHistoryType] > 50 do
|
||||||
|
table.remove(termlib.readHistory[readHistoryType], 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
termlib.cursorPosX=1
|
||||||
|
termlib.cursorPosY=termlib.cursorPosY+math.ceil((unicode.wlen(text)+startX-1)/width)
|
||||||
|
if termlib.cursorPosY>height then scrollDown() end
|
||||||
|
|
||||||
|
return text
|
||||||
end
|
end
|
||||||
|
|||||||
+84
-56
@@ -2,9 +2,11 @@ local loadfile = ... -- raw loadfile from boot.lua
|
|||||||
local component, computer
|
local component, computer
|
||||||
|
|
||||||
if loadfile then
|
if loadfile then
|
||||||
|
unicode = loadfile("/halyde/lib/unicode.lua")(loadfile)
|
||||||
component = loadfile("/halyde/lib/component.lua")(loadfile)
|
component = loadfile("/halyde/lib/component.lua")(loadfile)
|
||||||
computer = _G.computer
|
computer = _G.computer
|
||||||
elseif import then
|
elseif import then
|
||||||
|
unicode = import("unicode")
|
||||||
component = import("component")
|
component = import("component")
|
||||||
computer = import("computer")
|
computer = import("computer")
|
||||||
end
|
end
|
||||||
@@ -44,7 +46,10 @@ function filesystem.absolutePath(path) -- returns the address and absolute path
|
|||||||
checkArg(1, path, "string")
|
checkArg(1, path, "string")
|
||||||
path = filesystem.canonical(path)
|
path = filesystem.canonical(path)
|
||||||
local address = nil
|
local address = nil
|
||||||
if path:find("^/mnt/...") then
|
if path:find("^/tmp") then
|
||||||
|
address = computer.tmpAddress()
|
||||||
|
path = path:sub(5)
|
||||||
|
elseif path:find("^/mnt/...") then
|
||||||
address = component.get(path:sub(6,8))
|
address = component.get(path:sub(6,8))
|
||||||
if not address then
|
if not address then
|
||||||
address = computer.getBootAddress()
|
address = computer.getBootAddress()
|
||||||
@@ -69,48 +74,36 @@ function filesystem.exists(path) -- check if path exists
|
|||||||
return component.invoke(address, "exists", absPath)
|
return component.invoke(address, "exists", absPath)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function readUniChar(readByte)
|
local function readBytes(self,n)
|
||||||
local function inRange(min,max,...)
|
n = n or 1
|
||||||
for _,v in ipairs({...}) do
|
if n==1 then
|
||||||
if not (v and v>=min and v<max) then return false end
|
local byte = self:read(1)
|
||||||
end
|
if byte==nil then return nil end
|
||||||
return true
|
return string.byte(byte)
|
||||||
end
|
end
|
||||||
local function readByte0() return readByte() or 0 end
|
local bytes, res = {string.byte(self:read(n),1,n)}, 0
|
||||||
|
for i=1,#bytes do
|
||||||
|
res = (res<<8)&0xFFFFFFFF | bytes[i]
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
local byte = readByte()
|
local function readUnicodeChar(self)
|
||||||
|
return unicode.readChar(function()
|
||||||
|
return self:readBytes(1)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
if byte < 0x80 then
|
local function iterateBytes(self)
|
||||||
-- ASCII character (0xxxxxxx)
|
return function()
|
||||||
return byte
|
local byte = readBytes(self,1)
|
||||||
elseif byte < 0xC0 then
|
if byte==nil then self:close() end
|
||||||
-- Continuation byte (10xxxxxx), invalid at start position
|
return byte
|
||||||
return nil
|
end
|
||||||
elseif byte < 0xE0 then
|
end
|
||||||
-- 2-byte sequence (110xxxxx 10xxxxxx)
|
|
||||||
local byte2 = readByte0()
|
|
||||||
if inRange(0x80,0xC0,byte2) then
|
|
||||||
local code_point = ((byte & 0x1F) << 6) | (byte2 & 0x3F)
|
|
||||||
return code_point
|
|
||||||
end
|
|
||||||
elseif byte < 0xF0 then
|
|
||||||
-- 3-byte sequence (1110xxxx 10xxxxxx 10xxxxxx)
|
|
||||||
local byte2, byte3 = readByte0(), readByte0()
|
|
||||||
if inRange(0x80,0xC0,byte2,byte3)then
|
|
||||||
local code_point = ((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F)
|
|
||||||
return code_point
|
|
||||||
end
|
|
||||||
elseif byte < 0xF8 then
|
|
||||||
-- 4-byte sequence (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
|
||||||
local byte2, byte3, byte4 = readByte0(), readByte0(), readByte0()
|
|
||||||
if inRange(0x80,0xC0,byte2,byte3,byte4) then
|
|
||||||
local code_point = ((byte & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F)
|
|
||||||
return code_point
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Invalid UTF-8 byte sequence
|
local function iterateUnicodeChars(self)
|
||||||
return nil
|
return unicode.iterate(iterateBytes(self))
|
||||||
end
|
end
|
||||||
|
|
||||||
function filesystem.open(path, mode, buffered) -- opens a file and returns its handle
|
function filesystem.open(path, mode, buffered) -- opens a file and returns its handle
|
||||||
@@ -151,7 +144,6 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
|
|||||||
if buffered then
|
if buffered then
|
||||||
local limit = string.len(content)+1
|
local limit = string.len(content)+1
|
||||||
local out = nil
|
local out = nil
|
||||||
-- error("amount "..amount..", limit "..limit)
|
|
||||||
if readcursor<limit then
|
if readcursor<limit then
|
||||||
if amount==math.huge then
|
if amount==math.huge then
|
||||||
out = string.sub(content,math.min(readcursor,limit))
|
out = string.sub(content,math.min(readcursor,limit))
|
||||||
@@ -168,20 +160,10 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
|
|||||||
return component.invoke(self.address, "read", self.handle, amount)
|
return component.invoke(self.address, "read", self.handle, amount)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function properHandle.readBytes(self,n)
|
properHandle.readBytes = readBytes
|
||||||
n = n or 1
|
properHandle.readUnicodeChar = readUnicodeChar
|
||||||
if n==1 then return string.byte(self:read(1)) end
|
properHandle.iterateBytes = iterateBytes
|
||||||
local bytes, res = {string.byte(self:read(n),1,n)}, 0
|
properHandle.iterateUnicodeChars = iterateUnicodeChars
|
||||||
for i=1,#bytes do
|
|
||||||
res = (res<<8)&0xFFFFFFFF | bytes[i]
|
|
||||||
end
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
function properHandle.readUnicodeChar(self)
|
|
||||||
return unicode.char(readUniChar(function()
|
|
||||||
return self:readBytes(1)
|
|
||||||
end))
|
|
||||||
end
|
|
||||||
function properHandle.write(self, data)
|
function properHandle.write(self, data)
|
||||||
checkArg(2, data, "string")
|
checkArg(2, data, "string")
|
||||||
return component.invoke(self.address, "write", self.handle, data)
|
return component.invoke(self.address, "write", self.handle, data)
|
||||||
@@ -202,8 +184,11 @@ function filesystem.list(path)
|
|||||||
if path == "/mnt" then
|
if path == "/mnt" then
|
||||||
-- list drives
|
-- list drives
|
||||||
local returnTable = {}
|
local returnTable = {}
|
||||||
|
local tmpAddress = computer.tmpAddress()
|
||||||
for address, _ in component.list("filesystem") do
|
for address, _ in component.list("filesystem") do
|
||||||
table.insert(returnTable, address:sub(1, 3) .. "/")
|
if address~=tmpAddress then
|
||||||
|
table.insert(returnTable, address:sub(1, 3) .. "/")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return returnTable
|
return returnTable
|
||||||
else
|
else
|
||||||
@@ -295,4 +280,47 @@ function filesystem.makeDirectory(path)
|
|||||||
return component.invoke(address, "makeDirectory", absPath)
|
return component.invoke(address, "makeDirectory", absPath)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function randomHex(length)
|
||||||
|
local chars = "0123456789abcdef"
|
||||||
|
local result = ""
|
||||||
|
for i = 1, length do
|
||||||
|
local index = math.random(1, #chars)
|
||||||
|
result = result .. string.sub(chars, index, index)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.makeReadStream(content)
|
||||||
|
local properHandle = {}
|
||||||
|
local readcursor = 1
|
||||||
|
function properHandle.read(self, amount)
|
||||||
|
checkArg(2, amount, "number")
|
||||||
|
local limit = string.len(content)+1
|
||||||
|
local out = nil
|
||||||
|
if readcursor<limit then
|
||||||
|
if amount==math.huge then
|
||||||
|
out = string.sub(content,math.min(readcursor,limit))
|
||||||
|
else
|
||||||
|
out = string.sub(content,math.min(readcursor,limit),math.min(readcursor+amount-1,limit))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
readcursor=readcursor+amount
|
||||||
|
if out=="" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
properHandle.readBytes = readBytes
|
||||||
|
properHandle.readUnicodeChar = readUnicodeChar
|
||||||
|
properHandle.iterateBytes = iterateBytes
|
||||||
|
properHandle.iterateUnicodeChars = iterateUnicodeChars
|
||||||
|
function properHandle.write()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
function properHandle.close()
|
||||||
|
content=nil
|
||||||
|
end
|
||||||
|
return properHandle
|
||||||
|
end
|
||||||
|
|
||||||
return(filesystem)
|
return(filesystem)
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
local unicodeLib
|
||||||
|
local LLunicode
|
||||||
|
if table.copy then
|
||||||
|
unicodeLib = table.copy(unicode)
|
||||||
|
LLunicode = table.copy(unicode)
|
||||||
|
else
|
||||||
|
unicodeLib = {}
|
||||||
|
LLunicode = unicode
|
||||||
|
end
|
||||||
|
|
||||||
|
function unicodeLib.readCodePoint(readByte)
|
||||||
|
local function inRange(min,max,...)
|
||||||
|
for _,v in ipairs({...}) do
|
||||||
|
if not (v and v>=min and v<max) then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local byte = readByte()
|
||||||
|
if byte==nil then return end
|
||||||
|
|
||||||
|
if byte < 0x80 then
|
||||||
|
-- ASCII character (0xxxxxxx)
|
||||||
|
return byte
|
||||||
|
elseif byte < 0xC0 then
|
||||||
|
-- Continuation byte (10xxxxxx), invalid at start position
|
||||||
|
return nil
|
||||||
|
elseif byte < 0xE0 then
|
||||||
|
-- 2-byte sequence (110xxxxx 10xxxxxx)
|
||||||
|
local byte2 = readByte()
|
||||||
|
if byte2==nil then return nil end
|
||||||
|
if inRange(0x80,0xC0,byte2) then
|
||||||
|
local code_point = ((byte & 0x1F) << 6) | (byte2 & 0x3F)
|
||||||
|
return code_point
|
||||||
|
end
|
||||||
|
elseif byte < 0xF0 then
|
||||||
|
-- 3-byte sequence (1110xxxx 10xxxxxx 10xxxxxx)
|
||||||
|
local byte2, byte3 = readByte(), readByte()
|
||||||
|
if byte2==nil and byte3==nil then return nil end
|
||||||
|
if inRange(0x80,0xC0,byte2,byte3)then
|
||||||
|
local code_point = ((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F)
|
||||||
|
return code_point
|
||||||
|
end
|
||||||
|
elseif byte < 0xF8 then
|
||||||
|
-- 4-byte sequence (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
||||||
|
local byte2, byte3, byte4 = readByte(), readByte(), readByte()
|
||||||
|
if byte2==nil and byte3==nil and byte4==nil then return nil end
|
||||||
|
if inRange(0x80,0xC0,byte2,byte3,byte4) then
|
||||||
|
local code_point = ((byte & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F)
|
||||||
|
return code_point
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Invalid UTF-8 byte sequence
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function unicodeLib.readChar(readByte)
|
||||||
|
checkArg(1,readByte,"function")
|
||||||
|
return LLunicode.char(unicodeLib.readCodePoint(readByte))
|
||||||
|
end
|
||||||
|
|
||||||
|
function unicodeLib.codepoint(chr)
|
||||||
|
checkArg(1,readByte,"string")
|
||||||
|
local ptr = 1
|
||||||
|
return readUniChar(function()
|
||||||
|
local byte = chr:byte(ptr)
|
||||||
|
ptr=ptr+1
|
||||||
|
return byte
|
||||||
|
end),ptr-1
|
||||||
|
end
|
||||||
|
|
||||||
|
function unicodeLib.iterate(readByte)
|
||||||
|
checkArg(1,readByte,"string","function")
|
||||||
|
if type(readByte)=="string" then
|
||||||
|
local str,ptr = readByte,0
|
||||||
|
readByte = function()
|
||||||
|
ptr=ptr+1
|
||||||
|
return str:byte(ptr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return function()
|
||||||
|
local point = unicodeLib.readCodePoint(readByte)
|
||||||
|
if point==nil then return nil end
|
||||||
|
return LLunicode.char(point),point
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unicodeLib.char = LLunicode.char
|
||||||
|
unicodeLib.charWidth = LLunicode.charWidth
|
||||||
|
unicodeLib.isWide = LLunicode.isWide
|
||||||
|
unicodeLib.len = LLunicode.len
|
||||||
|
unicodeLib.lower = LLunicode.lower
|
||||||
|
unicodeLib.reverse = LLunicode.reverse
|
||||||
|
unicodeLib.sub = LLunicode.sub
|
||||||
|
unicodeLib.upper = LLunicode.upper
|
||||||
|
unicodeLib.wlen = LLunicode.wlen
|
||||||
|
unicodeLib.wtrunc = LLunicode.wtrunc
|
||||||
|
|
||||||
|
return unicodeLib
|
||||||
Reference in New Issue
Block a user