diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java b/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java index 24590cde4..879e51583 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java @@ -73,12 +73,9 @@ public class TerminalWidget extends AbstractWidget { @Override public boolean charTyped(char ch, int modifiers) { if (ch >= 32 && ch <= 126 || ch >= 160) { - if (ch <= 255){ - // Queue the char event for any printable chars in byte range - computer.queueEvent("char", new Object[]{ Character.toString(ch) }); - } - // always send 'charutf' event so that in the computer it only needs to poll one type of event - computer.queueEvent("charutf", new Object[]{ StringUtil.utfToByteString(Character.toString(ch)) }); + // Queue the char event for any printable chars in byte range + var s = Character.toString(ch); + computer.queueEvent("char", new Object[]{ s, StringUtil.utfToByteString(s) }); } return true; @@ -135,8 +132,7 @@ public class TerminalWidget extends AbstractWidget { if (!clipboard.isEmpty()) { // Clip to 512 characters and queue the event if (clipboard.length() > 512) clipboard = clipboard.substring(0, 512); - computer.queueEvent("paste", new Object[]{ clipboard }); - computer.queueEvent("pasteutf", new Object[]{StringUtil.utfToByteString(clipboard)}); + computer.queueEvent("paste", new Object[]{ clipboard, StringUtil.utfToByteString(clipboard) }); } } diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt index 19f8279c1..676d8fac6 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt @@ -5,6 +5,7 @@ package dan200.computercraft.gametest import dan200.computercraft.api.lua.Coerced +import dan200.computercraft.api.lua.ObjectArguments import dan200.computercraft.client.gui.AbstractComputerScreen import dan200.computercraft.core.apis.RedstoneAPI import dan200.computercraft.core.apis.TermAPI @@ -88,7 +89,7 @@ class Computer_Test { @ClientGameTest fun Open_on_client(context: GameTestHelper) = context.sequence { // Write "Hello, world!" and then print each event to the terminal. - thenOnComputer { getApi().write(Coerced("Hello, world!")) } + thenOnComputer { getApi().write(ObjectArguments("Hello, world!")) } thenStartComputer { val term = getApi().terminal while (true) { diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt index d070f8e0f..f112d6ea5 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt @@ -5,6 +5,7 @@ package dan200.computercraft.gametest import dan200.computercraft.api.lua.Coerced +import dan200.computercraft.api.lua.ObjectArguments import dan200.computercraft.client.pocket.ClientPocketComputers import dan200.computercraft.core.apis.TermAPI import dan200.computercraft.gametest.api.* @@ -34,7 +35,7 @@ class Pocket_Computer_Test { context.givePocketComputer(unique) } // Write some text to the computer. - thenOnComputer(unique) { getApi().write(Coerced("Hello, world!")) } + thenOnComputer(unique) { getApi().write(ObjectArguments("Hello, world!")) } // And ensure its synced to the client. thenIdle(4) thenOnClient { @@ -49,7 +50,7 @@ class Pocket_Computer_Test { val term = getApi() term.setCursorPos(1, 1) term.setCursorBlink(true) - term.write(Coerced("Updated text :)")) + term.write(ObjectArguments("Updated text :)")) } // And ensure the new computer state and terminal are sent. thenIdle(4) diff --git a/projects/core/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/projects/core/src/main/java/dan200/computercraft/core/apis/TermMethods.java index eb4495be8..ac22a4407 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/apis/TermMethods.java +++ b/projects/core/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -13,6 +13,7 @@ import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.util.StringUtil; import java.nio.ByteBuffer; +import java.util.Map; /** * A base class for all objects which interact with a terminal. Namely the {@link TermAPI} and monitors. @@ -37,30 +38,15 @@ public abstract class TermMethods { * @throws LuaException (hidden) If the terminal cannot be found. */ @LuaFunction - public final void write(Coerced textA) throws LuaException { - var text = textA.value(); - var terminal = getTerminal(); - synchronized (terminal) { - terminal.write(text); - terminal.setCursorPos(terminal.getCursorX() + text.length(), terminal.getCursorY()); + public final void write(IArguments textA) throws LuaException { + String text; + if(textA.get(0) instanceof Map utfString && utfString.containsKey("bytestring")){ + text = utfString.get("bytestring").toString(); + text = StringUtil.byteStringToUtf8(text); + } + else{ + text = textA.getStringCoerced(0); } - } - - /** - * Write utf8 encoded byte string{@code text} at the current cursor position, moving the cursor to the end of the text. - *

- * Unlike functions like {@code write} and {@code print}, this does not wrap the text - it simply copies the - * text to the current terminal line. - *

- * Developer should not use this function directly, but use the {@code utflib.term.write} to write Unicode strings. - * - * @param textA The utf8 encoded byte string to write. - * @throws LuaException (hidden) If the terminal cannot be found. - */ - @LuaFunction - public final void _writeutf8(Coerced textA) throws LuaException { - var text = textA.value(); - text = StringUtil.byteStringToUtf8(text); var terminal = getTerminal(); synchronized (terminal) { terminal.write(text); @@ -274,53 +260,25 @@ public abstract class TermMethods { * } */ @LuaFunction - public final void blit(ByteBuffer text, ByteBuffer textColour, ByteBuffer backgroundColour) throws LuaException { - if (textColour.remaining() != text.remaining() || backgroundColour.remaining() != text.remaining()) { - throw new LuaException(String.format("Arguments must be the same length (%d, %d, %d)", text.remaining(), textColour.remaining(), backgroundColour.remaining())); + public final void blit(IArguments args) throws LuaException { + String text; + if(args.get(0) instanceof Map utfString && utfString.containsKey("bytestring")){ + text = utfString.get("bytestring").toString(); + text = StringUtil.byteStringToUtf8(text); } - - var terminal = getTerminal(); - synchronized (terminal) { - terminal.blit(text, textColour, backgroundColour); - terminal.setCursorPos(terminal.getCursorX() + text.remaining(), terminal.getCursorY()); + else{ + text = args.getString(0); } - } - - /** - * Writes utf8 encoded byte string {@code text} to the terminal with the specific foreground and background colours. - *

- * As with {@link #write(Coerced)}, the text will be written at the current cursor location, with the cursor - * moving to the end of the text. - *

- * {@code textColour} and {@code backgroundColour} must both be strings the same length as teh decoded {@code text}. - * All characters represent a single hexadecimal digit, which is converted to one of CC's colours. For instance, - * {@code "a"} corresponds to purple. - *

- * Developer should not use this function directly, but use the {@code utflib.blit} to write Unicode strings. - * - * @param text The utf8 encoded byte string to write. - * @param textColour The corresponding text colours. - * @param backgroundColour The corresponding background colours. - * @throws LuaException If the three inputs are not the same length. - * @cc.see colors For a list of colour constants, and their hexadecimal values. - * @cc.since 1.74 - * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. - * @cc.usage Prints "Hello, world!" in rainbow text. - *

{@code
-     * term.blit("Hello, world!","01234456789ab","0000000000000")
-     * }
- */ - @LuaFunction - public final void _blitutf8(String text, ByteBuffer textColour, ByteBuffer backgroundColour) throws LuaException { - text = StringUtil.byteStringToUtf8(text); var textLen = text.codePointCount(0, text.length()); + ByteBuffer textColour = args.getBytes(1); + ByteBuffer backgroundColour = args.getBytes(2); if (textColour.remaining() != textLen || backgroundColour.remaining() != textLen) { throw new LuaException("Arguments must be the same length"); } var terminal = getTerminal(); synchronized (terminal) { - terminal.blitUtf(text, textColour, backgroundColour); + terminal.blit(text, textColour, backgroundColour); terminal.setCursorPos(terminal.getCursorX() + textLen, terminal.getCursorY()); } } diff --git a/projects/core/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/projects/core/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 61c375a0b..76fd65536 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/projects/core/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -176,11 +176,11 @@ public class Terminal { } } - public synchronized void blitUtf(String utf, ByteBuffer textColour, ByteBuffer backgroundColour) { + public synchronized void blit(String text, ByteBuffer textColour, ByteBuffer backgroundColour) { var x = cursorX; var y = cursorY; if (y >= 0 && y < height) { - this.text[y].write(utf, x); + this.text[y].write(text, x); this.textColour[y].write(textColour, x); this.backgroundColour[y].write(backgroundColour, x); setChanged(); diff --git a/projects/core/src/main/resources/data/computercraft/lua/bios.lua b/projects/core/src/main/resources/data/computercraft/lua/bios.lua index 2b3bd2b35..bce54501e 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/bios.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/bios.lua @@ -94,7 +94,9 @@ function sleep(nTime) end function write(sText) - expect(1, sText, "string", "number") + if not utflib.isUTFString(sText) then + expect(1, sText, "string", "number") + end local w, h = term.getSize() local x, y = term.getCursorPos() @@ -112,26 +114,28 @@ function write(sText) end -- Print the line with proper word wrapping - sText = tostring(sText) + if not utflib.isUTFString(sText) then + sText = tostring(sText) + end while #sText > 0 do - local whitespace = string.match(sText, "^[ \t]+") + local whitespace = sText:match("^[ \t]+") if whitespace then -- Print whitespace term.write(whitespace) x, y = term.getCursorPos() - sText = string.sub(sText, #whitespace + 1) + sText = sText:sub(#whitespace + 1) end - local newline = string.match(sText, "^\n") + local newline = sText:match("^\n") if newline then -- Print newlines newLine() - sText = string.sub(sText, 2) + sText = sText:sub(2) end - local text = string.match(sText, "^[^ \t\n]+") + local text = sText:match("^[^ \t\n]+") if text then - sText = string.sub(sText, #text + 1) + sText = sText:sub(#text + 1) if #text > w then -- Print a multiline word while #text > 0 do @@ -139,7 +143,7 @@ function write(sText) newLine() end term.write(text) - text = string.sub(text, w - x + 2) + text = text:sub(w - x + 2) x, y = term.getCursorPos() end else @@ -160,7 +164,8 @@ function print(...) local nLinesPrinted = 0 local nLimit = select("#", ...) for n = 1, nLimit do - local s = tostring(select(n, ...)) + local s = select(n, ...) + if not utflib.isUTFString(s) then s = tostring(s) end if n < nLimit then s = s .. "\t" end @@ -182,16 +187,17 @@ function printError(...) end end -function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) - expect(1, _sReplaceChar, "string", "nil") +function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault, _bReadUnicode) + if not utflib.isUTFString(_sReplaceChar) then expect(1, _sReplaceChar, "string", "nil") end expect(2, _tHistory, "table", "nil") expect(3, _fnComplete, "function", "nil") - expect(4, _sDefault, "string", "nil") + if not utflib.isUTFString(_sDefault) then expect(4, _sDefault, "string", "nil") end + expect(5, _bReadUnicode, "boolean", "nil") term.setCursorBlink(true) local sLine - if type(_sDefault) == "string" then + if type(_sDefault) ~= "nil" then sLine = _sDefault else sLine = "" @@ -199,7 +205,7 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) local nHistoryPos local nPos, nScroll = #sLine, 0 if _sReplaceChar then - _sReplaceChar = string.sub(_sReplaceChar, 1, 1) + _sReplaceChar = _sReplaceChar:sub(1, 1) end local tCompletions @@ -240,9 +246,9 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) term.setCursorPos(sx, cy) local sReplace = _bClear and " " or _sReplaceChar if sReplace then - term.write(string.rep(sReplace, math.max(#sLine - nScroll, 0))) + term.write(sReplace:rep(math.max(#sLine - nScroll, 0))) else - term.write(string.sub(sLine, nScroll + 1)) + term.write(sLine:sub(nScroll + 1)) end if nCompletion then @@ -255,7 +261,7 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) term.setBackgroundColor(colors.gray) end if sReplace then - term.write(string.rep(sReplace, #sCompletion)) + term.write(sReplace:rep(#sCompletion)) else term.write(sCompletion) end @@ -295,7 +301,7 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) if sEvent == "char" then -- Typed key clear() - sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1) + sLine = sLine:sub(1, nPos) .. (_bReadUnicode and utflib.UTFString(param1) or param) .. sLine:sub(nPos + 1) nPos = nPos + 1 recomplete() redraw() @@ -303,8 +309,9 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) elseif sEvent == "paste" then -- Pasted text clear() - sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1) - nPos = nPos + #param + local pastedText = (_bReadUnicode and utflib.UTFString(param1) or param) + sLine = sLine:sub(sLine, 1, nPos) .. pastedText .. sLine:sub(nPos + 1) + nPos = nPos + #pastedText recomplete() redraw() @@ -394,7 +401,7 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) -- Backspace if nPos > 0 then clear() - sLine = string.sub(sLine, 1, nPos - 1) .. string.sub(sLine, nPos + 1) + sLine = sLine:sub(1, nPos - 1) .. sLine:sub(nPos + 1) nPos = nPos - 1 if nScroll > 0 then nScroll = nScroll - 1 end recomplete() @@ -414,7 +421,7 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) -- Delete if nPos < #sLine then clear() - sLine = string.sub(sLine, 1, nPos) .. string.sub(sLine, nPos + 2) + sLine = sLine:sub(1, nPos) .. sLine:sub(nPos + 2) recomplete() redraw() end diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 3d34c27b3..242fca999 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -28,9 +28,12 @@ function slowWrite(text, rate) if rate < 0 then error("Rate must be positive", 2) end + if not utflib.isUTFString(text) and type(text) ~= 'string' then + text = tostring(text) + end local to_sleep = 1 / rate - local wrapped_lines = wrap(tostring(text), (term.getSize())) + local wrapped_lines = wrap(text, (term.getSize())) local wrapped_str = table.concat(wrapped_lines, "\n") for n = 1, #wrapped_str do @@ -180,10 +183,11 @@ local function tabulateCommon(bPaged, ...) if type(t) == "table" then for nu, sItem in pairs(t) do local ty = type(sItem) - if ty ~= "string" and ty ~= "number" then + if not utflib.isUTFString(ty) and ty ~= "string" and ty ~= "number" then error("bad argument #" .. n .. "." .. nu .. " (string expected, got " .. ty .. ")", 3) end - nMaxLen = math.max(#tostring(sItem) + 1, nMaxLen) + sItem1 = ty == "number" and tostring(sItem) or sItem + nMaxLen = math.max(#sItem1 + 1, nMaxLen) end end end @@ -898,22 +902,17 @@ unserialiseJSON = unserialise_json -- @usage print("https://example.com/?view=" .. textutils.urlEncode("some text&things")) -- @since 1.31 function urlEncode(str) - expect(1, str, "string") + if not utflib.isUTFString(str) then + expect(1, str, "string") + end if str then - str = string.gsub(str, "\n", "\r\n") - str = string.gsub(str, "([^A-Za-z0-9 %-%_%.])", function(c) + str = tostring(utflib.fromLatin(str)) + str = str:gsub("\n", "\r\n") + str = str:gsub("([^A-Za-z0-9 %-%_%.])", function(c) local n = string.byte(c) - if n < 128 then - -- ASCII - return string.format("%%%02X", n) - else - -- Non-ASCII (encode as UTF-8) - return - string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) .. - string.format("%%%02X", 128 + bit32.band(n, 63)) - end + return string.format("%%%02X", n) end) - str = string.gsub(str, " ", "+") + str = str:gsub(" ", "+") end return str end @@ -938,27 +937,29 @@ local tEmpty = {} -- @usage textutils.complete( "pa", _ENV ) -- @since 1.74 function complete(sSearchText, tSearchTable) - expect(1, sSearchText, "string") + if not utflib.isUTFString(sSearchText) then + expect(1, sSearchText, "string") + end expect(2, tSearchTable, "table", "nil") - if g_tLuaKeywords[sSearchText] then return tEmpty end + if g_tLuaKeywords[tostring(sSearchText)] then return tEmpty end local nStart = 1 - local nDot = string.find(sSearchText, ".", nStart, true) + local nDot = sSearchText:find(".", nStart, true) local tTable = tSearchTable or _ENV while nDot do - local sPart = string.sub(sSearchText, nStart, nDot - 1) + local sPart = tostring(sSearchText:sub(nStart, nDot - 1)) local value = tTable[sPart] if type(value) == "table" then tTable = value nStart = nDot + 1 - nDot = string.find(sSearchText, ".", nStart, true) + nDot = sSearchText:find(".", nStart, true) else return tEmpty end end - local nColon = string.find(sSearchText, ":", nStart, true) + local nColon = sSearchText:find(":", nStart, true) if nColon then - local sPart = string.sub(sSearchText, nStart, nColon - 1) + local sPart = tostring(sSearchText:sub(nStart, nColon - 1)) local value = tTable[sPart] if type(value) == "table" then tTable = value @@ -968,7 +969,7 @@ function complete(sSearchText, tSearchTable) end end - local sPart = string.sub(sSearchText, nStart) + local sPart = sSearchText:sub(nStart) local nPartLength = #sPart local tResults = {} @@ -976,9 +977,9 @@ function complete(sSearchText, tSearchTable) while tTable do for k, v in pairs(tTable) do if not tSeen[k] and type(k) == "string" then - if string.find(k, sPart, 1, true) == 1 then - if not g_tLuaKeywords[k] and string.match(k, "^[%a_][%a%d_]*$") then - local sResult = string.sub(k, nPartLength + 1) + if k:find(sPart, 1, true) == 1 then + if not g_tLuaKeywords[k] and k:match("^[%a_][%a%d_]*$") then + local sResult = k:sub(nPartLength + 1) if nColon then if type(v) == "function" then table.insert(tResults, sResult .. "(") diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/utflib.lua similarity index 98% rename from projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib.lua rename to projects/core/src/main/resources/data/computercraft/lua/rom/apis/utflib.lua index f1e555af5..ebb03c02c 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/utflib.lua @@ -1,6 +1,6 @@ -local expect = (require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")).expect +local expect = (dofile("rom/modules/main/cc/expect.lua")).expect -local UTFString = {} +UTFString = {} local UTFString_mt = { __index = UTFString, __name = 'UTFString' } @@ -12,6 +12,8 @@ local StringWrapper_mt = { __len = function() return #self.str end } +wrapStr = StringWrapper + local function rectify_string(s) -- check a string is a valid utf8 byte sequence -- if an invalid byte is found, consider it as raw codepoint and convert it to valid byte sequence @@ -32,11 +34,11 @@ local function rectify_string(s) return result end -local function isUTFString(obj) +function isUTFString(obj) return type(obj) == 'table' and getmetatable(obj) == UTFString_mt end -local function isStringWrapper(obj) +function isStringWrapper(obj) return type(obj) == 'table' and getmetatable(obj) == StringWrapper_mt end @@ -59,7 +61,7 @@ end setmetatable(StringWrapper, {__call = StringWrapper.new }) -local function from_latin(s) +function fromLatin(s) local str = "" for _, c in string.codes(s) do str = str .. utf8.char(c) @@ -206,7 +208,7 @@ function UTFString:byte(i, j) return utf8.codepoint(self.bytestring, utf8.offset(self.bytestring, i), j and utf8.offset(self.bytestring, j)) end -function UTFString:to_latin() +function UTFString:toLatin() local str = "" for _, c in utf8.codes(self.bytestring) do if c > 255 then str = str .. "?" @@ -787,11 +789,3 @@ function UTFString:reverse() for i = codes.n, 1, -1 do s = s .. utf8.char(codes[i]) end return unsafe_utfstring(s) end - -return { - UTFString = UTFString, - from_latin = from_latin, - isUTFString = isUTFString, - isStringWrapper = isStringWrapper, - wrap_str = StringWrapper -} diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/apis/window.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/window.lua index 8da3168ef..a73b0f11e 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/apis/window.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/window.lua @@ -34,9 +34,6 @@ parent, and only one of which is visible at a time. ]] local expect = dofile("rom/modules/main/cc/expect.lua").expect -local utflib = dofile("rom/modules/main/cc/utflib.lua") -local isUTFString = utflib.isUTFString -local u = utflib.UTFString local tHex = { [colors.white] = "0", @@ -164,9 +161,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) local function redrawLine(n) local tLine = tLines[n] parent.setCursorPos(nX, nY + n - 1) - if isUTFString(tLine[1]) then - parent._blitutf8(tostring(tLine[1]), tLine[2], tLine[3]) - else parent.blit(tLine[1], tLine[2], tLine[3]) end + parent.blit(tLine[1], tLine[2], tLine[3]) end local function redraw() @@ -260,35 +255,12 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) local window = {} function window.write(sText) - sText = tostring(sText) + if not utflib.isUTFString(sText) then sText = tostring(sText) end internalBlit(sText, string_rep(tHex[nTextColor], #sText), string_rep(tHex[nBackgroundColor], #sText)) end - function window._writeutf8(utfText) - if not isUTFString(utfText) then - if type(utfText) ~= "string" then utfText = tostring(utfText) end - utfText = u(utfText) - end - internalBlit(utfText, string_rep(tHex[nTextColor], #utfText), string_rep(tHex[nBackgroundColor], #utfText)) - end - function window.blit(sText, sTextColor, sBackgroundColor) - if type(sText) ~= "string" then expect(1, sText, "string") end - if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end - if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end - if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then - error("Arguments must be the same length", 2) - end - sTextColor = sTextColor:lower() - sBackgroundColor = sBackgroundColor:lower() - internalBlit(sText, sTextColor, sBackgroundColor) - end - - function window._blitutf8(sText, sTextColor, sBackgroundColor) - if not isUTFString(sText) then - expect(1, sText, "string") - sText = u(sText) - end + if not utflib.isUTFString(sText) and type(sText) ~= "string" then expect(1, sText, "string", "UTFString") end if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then @@ -494,9 +466,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end local line = tLines[y] - if isUTFString(line[1]) then - return tostring(line[1]), line[2], line[3] - else return line[1], line[2], line[3] end + return line[1], line[2], line[3] end -- Other functions diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua index 11bf4cad4..9d39dd5ab 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua @@ -29,7 +29,9 @@ the terminal. end ]] local function wrap(text, width) - expect(1, text, "string") + if not utflib.isUTFString(text) then + expect(1, text, "string") + end expect(2, width, "number", "nil") width = width or term.getSize() @@ -42,18 +44,17 @@ local function wrap(text, width) end local pos, length = 1, #text - local sub, match = string.sub, string.match while pos <= length do - local head = sub(text, pos, pos) + local head = text:sub(pos, pos) if head == " " or head == "\t" then - local whitespace = match(text, "^[ \t]+", pos) + local whitespace = text:match("^[ \t]+", pos) current_line = current_line .. whitespace pos = pos + #whitespace elseif head == "\n" then push_line() pos = pos + 1 else - local word = match(text, "^[^ \t\n]+", pos) + local word = text:match("^[^ \t\n]+", pos) pos = pos + #word if #word > width then -- Print a multiline word @@ -64,8 +65,8 @@ local function wrap(text, width) space_remaining = width end - current_line = current_line .. sub(word, 1, space_remaining) - word = sub(word, space_remaining + 1) + current_line = current_line .. word:sub(1, space_remaining) + word = word:sub(space_remaining + 1) end else -- Print a word normally @@ -97,7 +98,9 @@ end -- @usage require "cc.strings".ensure_width("a short string", 20) -- @usage require "cc.strings".ensure_width("a rather long string which is truncated", 20) local function ensure_width(line, width) - expect(1, line, "string") + if not isUTFString(line) then + expect(1, line, "string") + end expect(2, width, "number", "nil") width = width or term.getSize() diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/strings.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/strings.lua deleted file mode 100644 index f33716bda..000000000 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/strings.lua +++ /dev/null @@ -1,119 +0,0 @@ --- SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers --- --- SPDX-License-Identifier: MPL-2.0 - ---- Various utilities for working with strings and text. --- --- @module cc.strings --- @since 1.95.0 --- @see textutils For additional string related utilities. - -local expect = (require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")).expect -local utflib = (require and require("cc.utflib") or dofile("rom/modules/main/cc/utflib.lua")) - ---[[- Wraps a block of text, so that each line fits within the given width. - -This may be useful if you want to wrap text before displaying it to a -@{monitor} or @{printer} without using @{_G.print|print}. - -@tparam string text The string to wrap. -@tparam[opt] number width The width to constrain to, defaults to the width of -the terminal. -@treturn { string... } The wrapped input string as a list of lines. -@usage Wrap a string and write it to the terminal. - - term.clear() - local lines = require "cc.strings".wrap("This is a long piece of text", 10) - for i = 1, #lines do - term.setCursorPos(1, i) - term.write(lines[i]) - end -]] -local function wrap(text, width) - if not utflib.isUTFString(text) then - expect(1, text, "string") - end - expect(2, width, "number", "nil") - width = width or term.getSize() - - - local lines, lines_n, current_line = {}, 0, "" - local function push_line() - lines_n = lines_n + 1 - lines[lines_n] = current_line - current_line = "" - end - - local pos, length = 1, #text - while pos <= length do - local head = text:sub(pos, pos) - if head == " " or head == "\t" then - local whitespace = text:match("^[ \t]+", pos) - current_line = current_line .. whitespace - pos = pos + #whitespace - elseif head == "\n" then - push_line() - pos = pos + 1 - else - local word = text:match("^[^ \t\n]+", pos) - pos = pos + #word - if #word > width then - -- Print a multiline word - while #word > 0 do - local space_remaining = width - #current_line - 1 - if space_remaining <= 0 then - push_line() - space_remaining = width - end - - current_line = current_line .. word:sub(1, space_remaining) - word = word:sub(space_remaining + 1) - end - else - -- Print a word normally - if width - #current_line < #word then push_line() end - current_line = current_line .. word - end - end - end - - push_line() - - -- Trim whitespace longer than width. - for k, line in pairs(lines) do - line = line:sub(1, width) - lines[k] = line - end - - return lines -end - ---- Makes the input string a fixed width. This either truncates it, or pads it --- with spaces. --- --- @tparam string line The string to normalise. --- @tparam[opt] number width The width to constrain to, defaults to the width of --- the terminal. --- --- @treturn string The string with a specific width. --- @usage require "cc.strings".ensure_width("a short string", 20) --- @usage require "cc.strings".ensure_width("a rather long string which is truncated", 20) -local function ensure_width(line, width) - if not isUTFString(line) then - expect(1, line, "string") - end - expect(2, width, "number", "nil") - width = width or term.getSize() - - line = line:sub(1, width) - if #line < width then - line = line .. (" "):rep(width - #line) - end - - return line -end - -return { - wrap = wrap, - ensure_width = ensure_width, -} diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/term.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/term.lua deleted file mode 100644 index 6efc76d76..000000000 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/term.lua +++ /dev/null @@ -1,392 +0,0 @@ -local expect = (require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")).expect -local utflib = (require and require("cc.utflib") or dofile("rom/modules/main/cc/utflib.lua")) - -local function twrite(sText) - if not utflib.isUTFString(sText) then - expect(1, sText, "UTFString") -- type(sText) == "UTFString" should never happened. Just use for triggering errors - end - term._writeutf8(tostring(sText)) -end - -local function writeutf8(sText, targetTerm) - if not utflib.isUTFString(sText) then - expect(1, sText, "string", "number") - end - expect(2, targetTerm, "table", "nil") - targetTerm = targetTerm or term - - local w, h = targetTerm.getSize() - local x, y = targetTerm.getCursorPos() - - local nLinesPrinted = 0 - local function newLine() - if y + 1 <= h then - targetTerm.setCursorPos(1, y + 1) - else - targetTerm.setCursorPos(1, h) - targetTerm.scroll(1) - end - x, y = targetTerm.getCursorPos() - nLinesPrinted = nLinesPrinted + 1 - end - - -- Print the line with proper word wrapping - if not utflib.isUTFString(sText) then - sText = utflib.UTFString(tostring(sText)) - end - while #sText > 0 do - local whitespace = sText:match("^[ \t]+") - if whitespace then - -- Print whitespace - targetTerm.write(whitespace) - x, y = term.getCursorPos() - sText = sText:sub(#whitespace + 1) - end - - local newline = sText:match("^\n") - if newline then - -- Print newlines - newLine() - sText = sText:sub(2) - end - - local text = sText:match("^[^ \t\n]+") - if text then - sText = sText:sub(#text + 1) - if #text > w then - -- Print a multiline word - while #text > 0 do - if x > w then - newLine() - end - targetTerm._writeutf8(tostring(text)) - text = text:sub(w - x + 2) - x, y = term.getCursorPos() - end - else - -- Print a word normally - if x + #text - 1 > w then - newLine() - end - targetTerm._writeutf8(tostring(text)) - x, y = term.getCursorPos() - end - end - end - - return nLinesPrinted -end - -local function printutf8(...) - local nLinesPrinted = 0 - local nLimit = select("#", ...) - for n = 1, nLimit do - local s = select(n, ...) - if not utflib.isUTFString(s) then s = tostring(s) end - if n < nLimit then - s = s .. "\t" - end - nLinesPrinted = nLinesPrinted + writeutf8(s) - end - nLinesPrinted = nLinesPrinted + writeutf8("\n") - return nLinesPrinted -end - -local function printErrorutf8(...) - local oldColour - if term.isColour() then - oldColour = term.getTextColour() - term.setTextColour(colors.red) - end - printutf8(...) - if term.isColour() then - term.setTextColour(oldColour) - end -end - -local function readutf8(_sReplaceChar, _tHistory, _fnComplete, _sDefault) - if not utflib.isUTFString(_sReplaceChar) then expect(1, _sReplaceChar, "string", "nil") end - expect(2, _tHistory, "table", "nil") - expect(3, _fnComplete, "function", "nil") - if not utflib.isUTFString(_sDefault) then expect(4, _sDefault, "string", "nil") end - - term.setCursorBlink(true) - - local sLine - if type(_sDefault) ~= "nil" then - sLine = _sDefault - else - sLine = "" - end - sLine = utflib.UTFString(sLine) - local nHistoryPos - local nPos, nScroll = #sLine, 0 - if _sReplaceChar then - _sReplaceChar = _sReplaceChar:sub(1, 1) - end - - local tCompletions - local nCompletion - local function recomplete() - if _fnComplete and nPos == #sLine then - tCompletions = _fnComplete(tostring(sLine)) - if tCompletions and #tCompletions > 0 then - nCompletion = 1 - else - nCompletion = nil - end - else - tCompletions = nil - nCompletion = nil - end - end - - local function uncomplete() - tCompletions = nil - nCompletion = nil - end - - local w = term.getSize() - local sx = term.getCursorPos() - - local function redraw(_bClear) - local cursor_pos = nPos - nScroll - if sx + cursor_pos >= w then - -- We've moved beyond the RHS, ensure we're on the edge. - nScroll = sx + nPos - w - elseif cursor_pos < 0 then - -- We've moved beyond the LHS, ensure we're on the edge. - nScroll = nPos - end - - local _, cy = term.getCursorPos() - term.setCursorPos(sx, cy) - local sReplace = _bClear and " " or _sReplaceChar - if sReplace then - term._writeutf8(sReplace:rep(math.max(#sLine - nScroll, 0))) - else - term._writeutf8(sLine:sub(nScroll + 1)) - end - - if nCompletion then - local sCompletion = tCompletions[nCompletion] - local oldText, oldBg - if not _bClear then - oldText = term.getTextColor() - oldBg = term.getBackgroundColor() - term.setTextColor(colors.white) - term.setBackgroundColor(colors.gray) - end - if sReplace then - term._writeutf8(sReplace:rep(#sCompletion)) - else - term._writeutf8(sCompletion) - end - if not _bClear then - term.setTextColor(oldText) - term.setBackgroundColor(oldBg) - end - end - - term.setCursorPos(sx + nPos - nScroll, cy) - end - - local function clear() - redraw(true) - end - - recomplete() - redraw() - - local function acceptCompletion() - if nCompletion then - -- Clear - clear() - - -- Find the common prefix of all the other suggestions which start with the same letter as the current one - local sCompletion = tCompletions[nCompletion] - sLine = sLine .. sCompletion - nPos = #sLine - - -- Redraw - recomplete() - redraw() - end - end - while true do - local sEvent, param, param1, param2 = os.pullEvent() - if sEvent == "charutf" then - -- Typed key - clear() - sLine = sLine:sub(1, nPos) .. param .. sLine:sub(nPos + 1) - nPos = nPos + 1 - recomplete() - redraw() - - elseif sEvent == "pasteutf" then - -- Pasted text - clear() - param = utflib.UTFString(param) - sLine = sLine:sub(1, nPos) .. param .. sLine:sub(nPos + 1) - nPos = nPos + #param - recomplete() - redraw() - - elseif sEvent == "key" then - if param == keys.enter or param == keys.numPadEnter then - -- Enter/Numpad Enter - if nCompletion then - clear() - uncomplete() - redraw() - end - break - - elseif param == keys.left then - -- Left - if nPos > 0 then - clear() - nPos = nPos - 1 - recomplete() - redraw() - end - - elseif param == keys.right then - -- Right - if nPos < #sLine then - -- Move right - clear() - nPos = nPos + 1 - recomplete() - redraw() - else - -- Accept autocomplete - acceptCompletion() - end - - elseif param == keys.up or param == keys.down then - -- Up or down - if nCompletion then - -- Cycle completions - clear() - if param == keys.up then - nCompletion = nCompletion - 1 - if nCompletion < 1 then - nCompletion = #tCompletions - end - elseif param == keys.down then - nCompletion = nCompletion + 1 - if nCompletion > #tCompletions then - nCompletion = 1 - end - end - redraw() - - elseif _tHistory then - -- Cycle history - clear() - if param == keys.up then - -- Up - if nHistoryPos == nil then - if #_tHistory > 0 then - nHistoryPos = #_tHistory - end - elseif nHistoryPos > 1 then - nHistoryPos = nHistoryPos - 1 - end - else - -- Down - if nHistoryPos == #_tHistory then - nHistoryPos = nil - elseif nHistoryPos ~= nil then - nHistoryPos = nHistoryPos + 1 - end - end - if nHistoryPos then - sLine = _tHistory[nHistoryPos] - nPos, nScroll = #sLine, 0 - else - sLine = "" - nPos, nScroll = 0, 0 - end - uncomplete() - redraw() - - end - - elseif param == keys.backspace then - -- Backspace - if nPos > 0 then - clear() - sLine = sLine:sub(1, nPos - 1) .. sLine:sub(nPos + 1) - nPos = nPos - 1 - if nScroll > 0 then nScroll = nScroll - 1 end - recomplete() - redraw() - end - - elseif param == keys.home then - -- Home - if nPos > 0 then - clear() - nPos = 0 - recomplete() - redraw() - end - - elseif param == keys.delete then - -- Delete - if nPos < #sLine then - clear() - sLine = sLine:sub(1, nPos) .. sLine:sub(nPos + 2) - recomplete() - redraw() - end - - elseif param == keys["end"] then - -- End - if nPos < #sLine then - clear() - nPos = #sLine - recomplete() - redraw() - end - - elseif param == keys.tab then - -- Tab (accept autocomplete) - acceptCompletion() - - end - - elseif sEvent == "mouse_click" or sEvent == "mouse_drag" and param == 1 then - local _, cy = term.getCursorPos() - if param1 >= sx and param1 <= w and param2 == cy then - -- Ensure we don't scroll beyond the current line - nPos = math.min(math.max(nScroll + param1 - sx, 0), #sLine) - redraw() - end - - elseif sEvent == "term_resize" then - -- Terminal resized - w = term.getSize() - redraw() - - end - end - - local _, cy = term.getCursorPos() - term.setCursorBlink(false) - term.setCursorPos(w + 1, cy) - print() - - return sLine -end - - -return { - twrite = twrite, - write = writeutf8, - print = printutf8, - printError = printErrorutf8, - read = readutf8 -} diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/textutils.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/textutils.lua deleted file mode 100644 index 0328206bc..000000000 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/utflib/textutils.lua +++ /dev/null @@ -1,308 +0,0 @@ -local expect = (require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")) -local utflib = (require and require("cc.utflib") or dofile("rom/modules/main/cc/utflib.lua")) -local expect, field = expect.expect, expect.field -local wrap = (require and require("cc.utflib.strings") or dofile("rom/modules/main/cc/utflib/strings.lua")).wrap -local uterm = (require and require("cc.utflib.term") or dofile("rom/modules/main/cc/utflib/term.lua")) - -local write, print = uterm.write, uterm.print - -local utextutils = {} - ---- Slowly writes string text at current cursor position, --- character-by-character. --- --- Like @{_G.write}, this does not insert a newline at the end. --- --- @tparam string text The the text to write to the screen --- @tparam[opt] number rate The number of characters to write each second, --- Defaults to 20. --- @usage textutils.slowWrite("Hello, world!") --- @usage textutils.slowWrite("Hello, world!", 5) --- @since 1.3 -function utextutils.slowWrite(text, rate) - expect(2, rate, "number", "nil") - rate = rate or 20 - if rate < 0 then - error("Rate must be positive", 2) - end - if not utflib.isUTFString(text) and type(text) ~= 'string' then - text = tostring(text) - end - local to_sleep = 1 / rate - - local wrapped_lines = wrap(text, (term.getSize())) - local wrapped_str = table.concat(wrapped_lines, "\n") - - for n = 1, #wrapped_str do - sleep(to_sleep) - write(wrapped_str:sub(n, n)) - end -end - ---- Slowly prints string text at current cursor position, --- character-by-character. --- --- Like @{print}, this inserts a newline after printing. --- --- @tparam string sText The the text to write to the screen --- @tparam[opt] number nRate The number of characters to write each second, --- Defaults to 20. --- @usage textutils.slowPrint("Hello, world!") --- @usage textutils.slowPrint("Hello, world!", 5) -function utextutils.slowPrint(sText, nRate) - slowWrite(sText, nRate) - print() -end - ---- Takes input time and formats it in a more readable format such as `6:30 PM`. --- differ from the normal version, this accepts custom 12-hour format. --- --- @tparam number nTime The time to format, as provided by @{os.time}. --- @tparam[opt] boolean bTwentyFourHour Whether to format this as a 24-hour --- clock (`18:30`) rather than a 12-hour one (`6:30 AM`) --- @tparam[opt] string amFormat format for time before noon. default to `%s AM`. can be UTFString --- @tparam[opt] string pmFormat format for time after noon. default to `%s PM`. can be UTFString --- @treturn string The formatted time --- @usage Print the current in-game time as a 12-hour clock. --- --- textutils.formatTime(os.time()) --- @usage Print the local time as a 24-hour clock. --- --- textutils.formatTime(os.time("local"), true) -function utextutils.formatTime(nTime, bTwentyFourHour, amFormat, pmFormat) - expect(1, nTime, "number") - expect(2, bTwentyFourHour, "boolean", "nil") - if not isUTFString(amFormat) then expect(3, amFormat, "string", "nil") end - if not isUTFString(pmFormat) then expect(4, pmFormat, "string", "nil") end - local sTOD = nil - if not bTwentyFourHour then - if nTime >= 12 then - sTOD = utflib.UTFString(pmFormat or "%s PM") - else - sTOD = utflib.UTFString(amFormat or "%s AM") - end - if nTime >= 13 then - nTime = nTime - 12 - end - end - - local nHour = math.floor(nTime) - local nMinute = math.floor((nTime - nHour) * 60) - if sTOD then - return sTOD:format(string.format("%d:%02d", nHour == 0 and 12 or nHour, nMinute)) - else - return utflib.UTFString(string.format("%d:%02d", nHour, nMinute)) - end -end - -local function makePagedScroll(_term, _nFreeLines, _cont_hint) - local nativeScroll = _term.scroll - local nFreeLines = _nFreeLines or 0 - _cont_hint = utflib.UTFString(_cont_hint or "Press any key to continue") - return function(_n) - for _ = 1, _n do - nativeScroll(1) - - if nFreeLines <= 0 then - local _, h = _term.getSize() - _term.setCursorPos(1, h) - _term._writeutf8(_cont_hint) - os.pullEvent("key") - _term.clearLine() - _term.setCursorPos(1, h) - else - nFreeLines = nFreeLines - 1 - end - end - end -end - ---[[- Prints a given string to the display. - -If the action can be completed without scrolling, it acts much the same as -@{print}; otherwise, it will throw up a "Press any key to continue" prompt at -the bottom of the display. Each press will cause it to scroll down and write a -single line more before prompting again, if need be. -Differ from the normal version, this allows customization on the continue prompt. - -@tparam string text The text to print to the screen. -@tparam[opt] number free_lines The number of lines which will be -automatically scrolled before the first prompt appears (meaning free_lines + -1 lines will be printed). This can be set to the cursor's y position - 2 to -always try to fill the screen. Defaults to 0, meaning only one line is -displayed before prompting. -@tparam[opt] string contHint The continue prompt shown if the action cannot be -completed without scrolling. Use the default prompt when not provided. Can be UTFString. -@treturn number The number of lines printed. - -@usage Generates several lines of text and then prints it, paging once the -bottom of the terminal is reached. - - local lines = {} - for i = 1, 30 do lines[i] = ("This is line #%d"):format(i) end - local message = table.concat(lines, "\n") - - local width, height = term.getCursorPos() - textutils.pagedPrint(message, height - 2) -]] -function utextutils.pagedPrint(text, free_lines, contHint) - expect(2, free_lines, "number", "nil") - if not utflib.isUTFString(contHint) then expect(3, contHint, "string", "nil") end - -- Setup a redirector - local oldTerm = term.current() - local newTerm = {} - for k, v in pairs(oldTerm) do - newTerm[k] = v - end - - newTerm.scroll = makePagedScroll(oldTerm, free_lines, contHint) - term.redirect(newTerm) - - -- Print the text - local result - local ok, err = pcall(function() - if text ~= nil then - result = print(text) - else - result = print() - end - end) - - -- Removed the redirector - term.redirect(oldTerm) - - -- Propagate errors - if not ok then - error(err, 0) - end - return result -end - -local function tabulateCommon(bPaged, ...) - local tAll = table.pack(...) - for i = 1, tAll.n do - expect(i, tAll[i], "number", "table") - end - - local w, h = term.getSize() - local nMaxLen = w / 8 - for n, t in ipairs(tAll) do - if type(t) == "table" then - for nu, sItem in pairs(t) do - local ty = type(sItem) - if not utflib.isUTFString(sItem) and ty ~= "string" and ty ~= "number" then - error("bad argument #" .. n .. "." .. nu .. " (string expected, got " .. ty .. ")", 3) - end - sItem1 = ty == "number" and tostring(sItem) or sItem - nMaxLen = math.max(#sItem1 + 1, nMaxLen) - end - end - end - local nCols = math.floor(w / nMaxLen) - local nLines = 0 - local function newLine() - if bPaged and nLines >= h - 3 then - pagedPrint() - else - print() - end - nLines = nLines + 1 - end - - local function drawCols(_t) - local nCol = 1 - for _, s in ipairs(_t) do - if nCol > nCols then - nCol = 1 - newLine() - end - - local cx, cy = term.getCursorPos() - cx = 1 + (nCol - 1) * nMaxLen - term.setCursorPos(cx, cy) - uterm.write(s, term) - - nCol = nCol + 1 - end - print() - end - - local previous_colour = term.getTextColour() - for _, t in ipairs(tAll) do - if type(t) == "table" then - if #t > 0 then - drawCols(t) - end - elseif type(t) == "number" then - term.setTextColor(t) - end - end - term.setTextColor(previous_colour) -end - ---[[- Prints tables in a structured form. - -This accepts multiple arguments, either a table or a number. When -encountering a table, this will be treated as a table row, with each column -width being auto-adjusted. - -When encountering a number, this sets the text color of the subsequent rows to it. - -@tparam {string...}|number ... The rows and text colors to display. -@since 1.3 -@usage - - textutils.tabulate( - colors.orange, { "1", "2", "3" }, - colors.lightBlue, { "A", "B", "C" } - ) -]] -function utextutils.tabulate(...) - return tabulateCommon(false, ...) -end - ---[[- Prints tables in a structured form, stopping and prompting for input should -the result not fit on the terminal. - -This functions identically to @{textutils.tabulate}, but will prompt for user -input should the whole output not fit on the display. - -@tparam {string...}|number ... The rows and text colors to display. -@see textutils.tabulate -@see textutils.pagedPrint -@since 1.3 - -@usage Generates a long table, tabulates it, and prints it to the screen. - - local rows = {} - for i = 1, 30 do rows[i] = {("Row #%d"):format(i), math.random(1, 400)} end - - textutils.pagedTabulate(colors.orange, {"Column", "Value"}, colors.lightBlue, table.unpack(rows)) -]] -function utextutils.pagedTabulate(...) - return tabulateCommon(true, ...) -end - ---- Replaces certain characters in a string to make it safe for use in URLs or POST data. --- --- @tparam string str The string to encode --- @treturn string The encoded string. --- @usage print("https://example.com/?view=" .. textutils.urlEncode("some text&things")) --- @since 1.31 -function utextutils.urlEncode(str) - if not utflib.isUTFString(str) then - expect(1, str, "string") - end - if str then - str = utflib.UTFString(str) - str = str:gsub("\n", "\r\n") - str = str:gsub("([^A-Za-z0-9 %-%_%.])", function(c) - local n = string.byte(c) - return string.format("%%%02X", n) - end) - str = str:gsub(" ", "+") - end - return str -end - -return utextutils diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua index da83e2414..8ab5b7bcf 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua @@ -339,7 +339,7 @@ while #tProcesses > 0 do resizeWindows() redrawMenu() - elseif sEvent == "char" or sEvent == "charutf" or sEvent == "key" or sEvent == "key_up" or sEvent == "paste" or sEvent == "pasteutf" or sEvent == "terminate" or sEvent == "file_transfer" then + elseif sEvent == "char" or sEvent == "key" or sEvent == "key_up" or sEvent == "paste" or sEvent == "terminate" or sEvent == "file_transfer" then -- Basic input, just passthrough to current process resumeProcess(nCurrentProcess, table.unpack(tEventData, 1, tEventData.n)) if cullProcess(nCurrentProcess) then diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/edit.lua index 99d90b758..758e13113 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/edit.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/edit.lua @@ -53,8 +53,6 @@ else errorColour = colours.white end -local utflib = (require and require("cc.utflib") or dofile("rom/modules/main/cc/utflib.lua")) -local uterm = (require and require("cc.utflib.term") or dofile("rom/modules/main/cc/utflib/term.lua")) local unicodeMode = settings.get("edit.unicode") local runHandler = [[multishell.setTitle(multishell.getCurrent(), %q) @@ -211,8 +209,7 @@ local function tryWrite(sLine, regex, colour) else term.setTextColour(colour(match)) end - if utflib.isUTFString(match) then uterm.twrite(match) - else term.write(match) end + term.write(match) term.setTextColour(textColour) return sLine:sub(#match + 1) end @@ -276,8 +273,7 @@ local function writeCompletion(sLine) local sCompletion = tCompletions[nCompletion] term.setTextColor(colours.white) term.setBackgroundColor(colours.grey) - if utflib.isUTFString(sCompletion) then uterm.write(sCompletion) - else term.write(sCompletion) end + term.write(sCompletion) term.setTextColor(textColour) term.setBackgroundColor(bgColour) end @@ -791,12 +787,12 @@ while bRunning do end end - elseif unicodeMode and sEvent == "charutf" or not unicodeMode and sEvent == "char" then + elseif sEvent == "char" then if not bMenu and not bReadOnly then -- Input text local sLine = tLines[y] if unicodeMode then - tLines[y] = sLine:sub(1, x - 1) .. utflib.UTFString(param) .. sLine:sub(x) + tLines[y] = sLine:sub(1, x - 1) .. utflib.UTFString(param2) .. sLine:sub(x) else tLines[y] = sLine:sub(1, x - 1) .. param .. sLine:sub(x) end @@ -812,7 +808,7 @@ while bRunning do end end - elseif unicodeMode and sEvent == "pasteutf" or not unicodeMode and sEvent == "paste" then + elseif sEvent == "paste" then if not bReadOnly then -- Close menu if open if bMenu then @@ -822,12 +818,9 @@ while bRunning do end -- Input text local sLine = tLines[y] - if unicodeMode then - tLines[y] = sLine:sub(1, x - 1) .. utflib.UTFString(param) .. sLine:sub(x) - else - tLines[y] = sLine:sub(1, x - 1) .. param .. sLine:sub(x) - end - setCursor(x + #param , y) + local copiedText = unicodeMode and utflib.UTFString(param2) or param + tLines[y] = sLine:sub(1, x - 1) .. copiedText .. sLine:sub(x) + setCursor(x + #copiedText , y) end elseif sEvent == "mouse_click" then diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/lua.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/lua.lua index 2aaec8193..aa74fc7e8 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/lua.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/lua.lua @@ -42,14 +42,6 @@ print("Call exit() to exit.") term.setTextColour(colours.white) local unicodeMode = settings.get("lua.unicode") -local ulib = require("cc.utflib") -local write, print, printError, read -if unicodeMode then - local uterm = require("cc.utflib.term") - write, print, printError, read = uterm.write, uterm.print, uterm.printError, uterm.read -else - write, print, printError, read = _G.write, _G.print, _G.printError, _G.read -end local chunk_idx, chunk_map = 1, {} while running do @@ -83,7 +75,7 @@ while running do end local name, offset = "=lua[" .. chunk_idx .. "]", 0 - if ulib.isUTFString(input) then input = tostring(input) end + if utflib.isUTFString(input) then input = tostring(input) end local func, err = load(input, name, "t", tEnv) if load("return " .. input) then -- We wrap the expression with a call to _echo(...), which prevents tail diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/shell.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/shell.lua index 915859b37..ce310a782 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/shell.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/shell.lua @@ -86,14 +86,6 @@ else end local unicodeMode = settings.get("shell.unicode") -local write, print, printError, read -if unicodeMode then - local uterm = require("cc.utflib.term") - write, print, printError, read = uterm.write, uterm.print, uterm.printError, uterm.read -else - write, print, printError, read = _G.write, _G.print, _G.printError, _G.read -end -local utflib = require("cc.utflib") local function tokenise(...) local args = { ... } @@ -368,10 +360,10 @@ end local function pathWithExtension(_sPath, _sExt) local nLen = #sPath - local sEndChar = string.sub(_sPath, nLen, nLen) + local sEndChar = _sPath:sub(nLen, nLen) -- Remove any trailing slashes so we can add an extension to the path safely if sEndChar == "/" or sEndChar == "\\" then - _sPath = string.sub(_sPath, 1, nLen - 1) + _sPath = _sPath:sub(1, nLen - 1) end return _sPath .. "." .. _sExt end @@ -388,10 +380,12 @@ end -- shell.resolveProgram("hello") -- -- => rom/programs/fun/hello.lua function shell.resolveProgram(command) - expect(1, command, "string") + if not utflib.isUTFString(command) then + expect(1, command, "string") + end -- Substitute aliases firsts - if tAliases[command] ~= nil then - command = tAliases[command] + if tAliases[tostring(command)] ~= nil then + command = tAliases[tostring(command)] end -- If the path is a global path, use it directly @@ -409,7 +403,7 @@ function shell.resolveProgram(command) end -- Otherwise, look on the path variable - for sPath in string.gmatch(sPath, "[^:]+") do + for sPath in sPath:gmatch("[^:]+") do sPath = fs.combine(shell.resolve(sPath), command) if fs.exists(sPath) and not fs.isDir(sPath) then return sPath @@ -547,11 +541,13 @@ end -- @see shell.getCompletionInfo -- @since 1.74 function shell.complete(sLine) - expect(1, sLine, "string") + if not utflib.isUTFString(sLine) then + expect(1, sLine, "string") + end if #sLine > 0 then local tWords = tokenise(sLine) local nIndex = #tWords - if string.sub(sLine, #sLine, #sLine) == " " then + if sLine:sub(#sLine, #sLine) == " " then nIndex = nIndex + 1 end if nIndex == 1 then @@ -774,7 +770,7 @@ else local ok, result local co = coroutine.create(read) - assert(coroutine.resume(co, nil, tCommandHistory, complete)) + assert(coroutine.resume(co, nil, tCommandHistory, complete, nil, unicodeMode)) while coroutine.status(co) ~= "dead" do local event = table.pack(os.pullEvent())