those diverged will eventually reunited

merge separated unicode modules/functions back to their normal variant.
This commit is contained in:
cvrunmin 2023-07-12 22:46:03 +08:00
parent a07a1b0152
commit cf466874ef
17 changed files with 134 additions and 1041 deletions

View File

@ -73,12 +73,9 @@ public TerminalWidget(Terminal terminal, InputHandler computer, int x, int y) {
@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 @@ private void paste() {
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) });
}
}

View File

@ -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 @@ fun Computer_peripheral(context: GameTestHelper) = context.sequence {
@ClientGameTest
fun Open_on_client(context: GameTestHelper) = context.sequence {
// Write "Hello, world!" and then print each event to the terminal.
thenOnComputer { getApi<TermAPI>().write(Coerced("Hello, world!")) }
thenOnComputer { getApi<TermAPI>().write(ObjectArguments("Hello, world!")) }
thenStartComputer {
val term = getApi<TermAPI>().terminal
while (true) {

View File

@ -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 @@ fun Sync_state(context: GameTestHelper) = context.sequence {
context.givePocketComputer(unique)
}
// Write some text to the computer.
thenOnComputer(unique) { getApi<TermAPI>().write(Coerced("Hello, world!")) }
thenOnComputer(unique) { getApi<TermAPI>().write(ObjectArguments("Hello, world!")) }
// And ensure its synced to the client.
thenIdle(4)
thenOnClient {
@ -49,7 +50,7 @@ fun Sync_state(context: GameTestHelper) = context.sequence {
val term = getApi<TermAPI>()
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)

View File

@ -13,6 +13,7 @@
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 @@ private static int getHighestBit(int group) {
* @throws LuaException (hidden) If the terminal cannot be found.
*/
@LuaFunction
public final void write(Coerced<String> 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.
* <p>
* Unlike functions like {@code write} and {@code print}, this does not wrap the text - it simply copies the
* text to the current terminal line.
* <p>
* 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<String> textA) throws LuaException {
var text = textA.value();
text = StringUtil.byteStringToUtf8(text);
var terminal = getTerminal();
synchronized (terminal) {
terminal.write(text);
@ -274,53 +260,25 @@ public final boolean getIsColour() throws LuaException {
* }</pre>
*/
@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.
* <p>
* 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.
* <p>
* {@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.
* <p>
* 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.
* <pre>{@code
* term.blit("Hello, world!","01234456789ab","0000000000000")
* }</pre>
*/
@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());
}
}

View File

@ -176,11 +176,11 @@ public synchronized void blit(ByteBuffer text, ByteBuffer textColour, ByteBuffer
}
}
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();

View File

@ -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

View File

@ -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 .. "(")

View File

@ -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
}

View File

@ -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

View File

@ -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()

View File

@ -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,
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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())