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:
Ponali
2025-07-07 17:45:52 +02:00
parent d386ec5eba
commit c0929bf639
7 changed files with 342 additions and 237 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
local agcfg = {
["halyde"] = {
["maindir"] = "",
["version"] = "1.15.0",
["version"] = "2.0.0",
["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.",
["directories"] = {
"halyde/apps",
@@ -82,7 +82,7 @@ local agcfg = {
},
["edit"] = {
["maindir"] = "",
["version"] = "1.2.0",
["version"] = "1.2.1",
["description"] = "The default text editor for Halyde.",
["files"] = {
"halyde/apps/edit.lua",
+1
View File
@@ -2,6 +2,7 @@ local file = ...
local fs = import("filesystem")
local event = import("event")
local component = import("component")
local unicode = import("unicode")
local gpu = component.gpu
local width, height = gpu.getResolution()
local scrollPosX, scrollPosY = 1, 1
+1
View File
@@ -2,6 +2,7 @@ local args = {...}
local target = args[1]
args = nil
local fs = import("filesystem")
local unicode = import("unicode")
local maxLength = 0
local margin = 2 -- minimum space between filename and size
local dirTable = {}
+1 -1
View File
@@ -1,7 +1,7 @@
local loadfile = ...
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
_G._OSVERSION = "Halyde 1.15.0"
_G._OSVERSION = "Halyde 2.0.0"
_G._OSLOGO = ""
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
repeat
+140 -165
View File
@@ -1,3 +1,4 @@
local unicode = import("unicode")
local event = import("event")
--local keyboard = import("keyboard")
@@ -86,8 +87,8 @@ function termlib.write(text, textWrap)
if text:find("\a") then
computer.beep()
end
text = "\27[0m" .. text:gsub("\t", " ")
text = tostring(text)
text = "\27[0m" .. text:gsub("\t", " ")
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.
-- 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
end
-- god i hope this silly claude code works first try
-- Fluxdrive caught vibe coding???
function _G.read(readHistoryType, prefix, defaultText)
function _G.read(readHistoryType, prefix, defaultText, maxChars)
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(4, maxChars, "number", "nil")
maxChars = maxChars or math.huge
local RHIndex
local text = defaultText or ""
local historyIdx
if readHistoryType then
if not termlib.readHistory[readHistoryType] then
termlib.readHistory[readHistoryType] = {curtext}
termlib.readHistory[readHistoryType] = {text}
elseif termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType] ] ~= "" then
table.insert(termlib.readHistory[readHistoryType], curtext)
table.insert(termlib.readHistory[readHistoryType], text)
end
RHIndex = #termlib.readHistory[readHistoryType]
historyIdx = #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)
local cur = unicode.len(text)+1
if prefix then termlib.write(prefix) end
local startX, startY = termlib.cursorPosX, termlib.cursorPosY
local fg, bg = gpu.getForeground(), gpu.getBackground()
local cursorBlink = true
local function get(idx)
idx=startX+idx-1
return gpu.get(idx%width,startY+(idx//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))
local function checkScroll(y)
for i=1,y-height do
scrollDown()
startY=startY-1
end
return math.min(y,height)
end
local function set(idx,chr,rev)
if chr==nil or chr=="" then return end
if rev then
gpu.setForeground(bg)
gpu.setBackground(fg)
else
gpu.setForeground(fg)
gpu.setBackground(bg)
end
idx=startX+idx-1
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
-- Reset cursor to start position
termlib.cursorPosX, termlib.cursorPosY = startX, startY
-- 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))
local function strDef(a,b)
if #a==0 then return b end
return a
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 cursorWhite = true
local function reprint(new)
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
local args = {event.pull("key_down", "clipboard", 0.5)}
if args[1] == "key_down" and args[4] then
cursorWhite = true
local keycode = args[4]
local key = keyboard.keys[keycode]
-- Handle arrow keys
if args and args[1] == "key_down" and args[4] then
local key = keyboard.keys[args[4]]
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()
historyIdx=math.max(historyIdx-1,1)
reprint(termlib.readHistory[readHistoryType][historyIdx])
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()
historyIdx=math.min(historyIdx+1,#termlib.readHistory[readHistoryType])
reprint(termlib.readHistory[readHistoryType][historyIdx])
elseif key=="left" then
-- Move cursor left
if textCursorPos > 1 then
textCursorPos = textCursorPos - 1
redrawLine()
end
moveCur(-1)
elseif key=="right" then
-- Move cursor right
if textCursorPos <= unicode.wlen(curtext) then
textCursorPos = textCursorPos + 1
redrawLine()
end
moveCur(1)
elseif key=="home" then
-- Move to beginning of line
textCursorPos = 1
redrawLine()
moveCur(-math.huge)
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
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
-- 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
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
redrawLine()
updateHistory()
elseif key=="enter" then
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),false)
break
elseif not (args[3]<32 or (args[3]>0x7F and args[3]<=0x9F)) then
add(unicode.char(args[3]) or " ")
updateHistory()
end
elseif args and args[1]=="clipboard" then
local clip = args[3]
if not args[3] then goto continue end
while isLine(unicode.sub(clip,1,1)) do clip=unicode.sub(clip,2) end
while isLine(unicode.sub(clip,-1)) do clip=unicode.sub(clip,1,-2) end
add(clip)
updateHistory()
else
cursorBlink=not cursorBlink
set(curPos(cur),strDef(unicode.sub(text,cur,cur)," "),cursorBlink)
end
::continue::
end
elseif key == "enter" then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(prefix .. curtext .. " ")
if readHistoryType then
if termlib.readHistory[readHistoryType][#termlib.readHistory[readHistoryType]]=="" then
table.remove(termlib.readHistory[readHistoryType],#termlib.readHistory[readHistoryType])
end
if historyIdx<#termlib.readHistory[readHistoryType] then
table.remove(termlib.readHistory[readHistoryType],historyIdx)
table.insert(termlib.readHistory[readHistoryType],text)
end
while #termlib.readHistory[readHistoryType] > 50 do
table.remove(termlib.readHistory[readHistoryType], 1)
end
end
return curtext
termlib.cursorPosX=1
termlib.cursorPosY=termlib.cursorPosY+math.ceil((unicode.wlen(text)+startX-1)/width)
if termlib.cursorPosY>height then scrollDown() end
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
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()
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
return text
end
+78 -50
View File
@@ -2,9 +2,11 @@ local loadfile = ... -- raw loadfile from boot.lua
local component, computer
if loadfile then
unicode = loadfile("/halyde/lib/unicode.lua")(loadfile)
component = loadfile("/halyde/lib/component.lua")(loadfile)
computer = _G.computer
elseif import then
unicode = import("unicode")
component = import("component")
computer = import("computer")
end
@@ -44,7 +46,10 @@ function filesystem.absolutePath(path) -- returns the address and absolute path
checkArg(1, path, "string")
path = filesystem.canonical(path)
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))
if not address then
address = computer.getBootAddress()
@@ -69,48 +74,36 @@ function filesystem.exists(path) -- check if path exists
return component.invoke(address, "exists", absPath)
end
local function readUniChar(readByte)
local function inRange(min,max,...)
for _,v in ipairs({...}) do
if not (v and v>=min and v<max) then return false end
local function readBytes(self,n)
n = n or 1
if n==1 then
local byte = self:read(1)
if byte==nil then return nil end
return string.byte(byte)
end
return true
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 function readByte0() return readByte() or 0 end
local byte = readByte()
local function readUnicodeChar(self)
return unicode.readChar(function()
return self:readBytes(1)
end)
end
if byte < 0x80 then
-- ASCII character (0xxxxxxx)
local function iterateBytes(self)
return function()
local byte = readBytes(self,1)
if byte==nil then self:close() end
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 = 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
return nil
local function iterateUnicodeChars(self)
return unicode.iterate(iterateBytes(self))
end
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
local limit = string.len(content)+1
local out = nil
-- error("amount "..amount..", limit "..limit)
if readcursor<limit then
if amount==math.huge then
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)
end
end
function properHandle.readBytes(self,n)
n = n or 1
if n==1 then return string.byte(self:read(1)) 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
function properHandle.readUnicodeChar(self)
return unicode.char(readUniChar(function()
return self:readBytes(1)
end))
end
properHandle.readBytes = readBytes
properHandle.readUnicodeChar = readUnicodeChar
properHandle.iterateBytes = iterateBytes
properHandle.iterateUnicodeChars = iterateUnicodeChars
function properHandle.write(self, data)
checkArg(2, data, "string")
return component.invoke(self.address, "write", self.handle, data)
@@ -202,9 +184,12 @@ function filesystem.list(path)
if path == "/mnt" then
-- list drives
local returnTable = {}
local tmpAddress = computer.tmpAddress()
for address, _ in component.list("filesystem") do
if address~=tmpAddress then
table.insert(returnTable, address:sub(1, 3) .. "/")
end
end
return returnTable
else
local address, absPath = filesystem.absolutePath(path)
@@ -295,4 +280,47 @@ function filesystem.makeDirectory(path)
return component.invoke(address, "makeDirectory", absPath)
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)
+100
View File
@@ -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