mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-23 05:58:14 +00:00
Merge branch 'mc-1.20.x' into mc-1.21.x
This commit is contained in:
commit
89dd521930
@ -59,8 +59,8 @@ jmh = "1.37"
|
||||
|
||||
# Build tools
|
||||
cctJavadoc = "1.8.4"
|
||||
checkstyle = "10.21.4"
|
||||
errorProne-core = "2.37.0"
|
||||
checkstyle = "10.23.1"
|
||||
errorProne-core = "2.38.0"
|
||||
errorProne-plugin = "4.1.0"
|
||||
fabric-loom = "1.10.4"
|
||||
githubRelease = "2.5.2"
|
||||
@ -70,7 +70,7 @@ illuaminate = "0.1.0-83-g1131f68"
|
||||
lwjgl = "3.3.3"
|
||||
minotaur = "2.8.7"
|
||||
modDevGradle = "2.0.78"
|
||||
nullAway = "0.12.4"
|
||||
nullAway = "0.12.7"
|
||||
shadow = "8.3.1"
|
||||
spotless = "7.0.2"
|
||||
taskTree = "2.1.1"
|
||||
|
@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
* Supports for converting/translating key codes.
|
||||
*/
|
||||
public class KeyConverter {
|
||||
/**
|
||||
* GLFW's key events refer to the physical key code, rather than the "actual" key code (with keyboard layout
|
||||
* applied).
|
||||
* <p>
|
||||
* This makes sense for WASD-style input, but is a right pain for keyboard shortcuts — this function attempts to
|
||||
* translate those keys back to their "actual" key code. See also
|
||||
* <a href="https://github.com/glfw/glfw/issues/1502"> this discussion on GLFW's GitHub.</a>
|
||||
*
|
||||
* @param key The current key code.
|
||||
* @param scanCode The current scan code.
|
||||
* @return The translated key code.
|
||||
*/
|
||||
public static int physicalToActual(int key, int scanCode) {
|
||||
var name = GLFW.glfwGetKeyName(key, scanCode);
|
||||
if (name == null || name.length() != 1) return key;
|
||||
|
||||
// If we've got a single character as the key name, treat that as the ASCII value of the key,
|
||||
// and map that back to a key code.
|
||||
var character = name.charAt(0);
|
||||
|
||||
// 0-9 and A-Z map directly to their GLFW key (they're the same ASCII code).
|
||||
if ((character >= '0' && character <= '9') || (character >= 'A' && character <= 'Z')) return character;
|
||||
// a-z map to GLFW_KEY_{A,Z}
|
||||
if (character >= 'a' && character <= 'z') return GLFW.GLFW_KEY_A + (character - 'a');
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.gui.widgets;
|
||||
|
||||
import dan200.computercraft.client.gui.KeyConverter;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
@ -83,7 +84,7 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) {
|
||||
switch (key) {
|
||||
switch (KeyConverter.physicalToActual(key, scancode)) {
|
||||
case GLFW.GLFW_KEY_T -> {
|
||||
if (terminateTimer < 0) terminateTimer = 0;
|
||||
}
|
||||
@ -119,7 +120,7 @@ public class TerminalWidget extends AbstractWidget {
|
||||
computer.keyUp(key);
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
switch (KeyConverter.physicalToActual(key, scancode)) {
|
||||
case GLFW.GLFW_KEY_T -> terminateTimer = -1;
|
||||
case GLFW.GLFW_KEY_R -> rebootTimer = -1;
|
||||
case GLFW.GLFW_KEY_S -> shutdownTimer = -1;
|
||||
|
@ -62,8 +62,8 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
var matrix = transform.last().pose();
|
||||
var opacity = (int) (mc.options.getBackgroundOpacity(0.25f) * 255) << 24;
|
||||
var width = -font.width(label) / 2.0f;
|
||||
font.drawInBatch(label, width, (float) 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
||||
font.drawInBatch(label, width, (float) 0, CommonColors.WHITE, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
||||
font.drawInBatch(label, width, 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
||||
font.drawInBatch(label, width, 0, CommonColors.WHITE, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 136 B |
@ -76,6 +76,7 @@ public abstract class AbstractHandle {
|
||||
* @cc.treturn [2] nil If seeking failed.
|
||||
* @cc.treturn string The reason seeking failed.
|
||||
* @cc.since 1.80pr1.9
|
||||
* @cc.changed 1.109.0 Now available on all file handles, not just binary-mode handles.
|
||||
*/
|
||||
public Object @Nullable [] seek(Optional<String> whence, Optional<Long> offset) throws LuaException {
|
||||
checkOpen();
|
||||
@ -179,6 +180,8 @@ public abstract class AbstractHandle {
|
||||
* @throws LuaException If the file has been closed.
|
||||
* @cc.treturn string|nil The remaining contents of the file, or {@code nil} in the event of an error.
|
||||
* @cc.since 1.80pr1
|
||||
* @cc.changed 1.109.0 Binary-mode handles are now consistent with non-binary files, and return an empty string at
|
||||
* the end of the file, rather than {@code nil}.
|
||||
*/
|
||||
public Object @Nullable [] readAll() throws LuaException {
|
||||
checkOpen();
|
||||
|
@ -120,7 +120,7 @@ public final class StringUtil {
|
||||
var idx = 0;
|
||||
|
||||
var iterator = clipboard.codePoints().iterator();
|
||||
while (iterator.hasNext() && idx <= output.length) {
|
||||
while (iterator.hasNext() && idx < output.length) {
|
||||
var chr = unicodeToTerminal(iterator.next());
|
||||
if (chr < 0) continue; // Strip out unconvertible characters
|
||||
if (!isTypableChar(chr)) break; // Stop at untypable ones.
|
||||
|
@ -371,7 +371,7 @@ function toBlit(color)
|
||||
local hex = color_hex_lookup[color]
|
||||
if hex then return hex end
|
||||
|
||||
if color < 0 or color > 0xffff then error("Colour out of range", 2) end
|
||||
if color < 1 or color > 0xffff then error("Colour out of range", 2) end
|
||||
return string.format("%x", math.floor(math.log(color, 2)))
|
||||
end
|
||||
|
||||
|
@ -65,7 +65,7 @@ local function parse_color(color)
|
||||
return expect(1, color, "number")
|
||||
end
|
||||
|
||||
if color < 0 or color > 0xffff then error("Colour out of range", 3) end
|
||||
if color < 1 or color > 0xffff then error("Colour out of range", 3) end
|
||||
return 2 ^ math.floor(math.log(color, 2))
|
||||
end
|
||||
|
||||
|
@ -238,7 +238,7 @@ local function lex_token(context, str, pos)
|
||||
if end_pos then return tokens.STRING, end_pos end
|
||||
|
||||
context.report(errors.unfinished_long_string, pos, boundary_pos, boundary_pos - pos)
|
||||
return tokens.ERROR, #str
|
||||
return tokens.STRING, #str
|
||||
elseif pos + 1 == boundary_pos then -- Just a "["
|
||||
return tokens.OSQUARE, pos
|
||||
else -- Malformed long string, for instance "[="
|
||||
@ -260,7 +260,7 @@ local function lex_token(context, str, pos)
|
||||
if end_pos then return tokens.COMMENT, end_pos end
|
||||
|
||||
context.report(errors.unfinished_long_comment, pos, boundary_pos, boundary_pos - comment_pos)
|
||||
return tokens.ERROR, #str
|
||||
return tokens.COMMENT, #str
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -175,63 +175,62 @@ local function save(_sPath, fWrite)
|
||||
return ok, err, fileerr
|
||||
end
|
||||
|
||||
local tKeywords = {
|
||||
["and"] = true,
|
||||
["break"] = true,
|
||||
["do"] = true,
|
||||
["else"] = true,
|
||||
["elseif"] = true,
|
||||
["end"] = true,
|
||||
["false"] = true,
|
||||
["for"] = true,
|
||||
["function"] = true,
|
||||
["if"] = true,
|
||||
["in"] = true,
|
||||
["local"] = true,
|
||||
["nil"] = true,
|
||||
["not"] = true,
|
||||
["or"] = true,
|
||||
["repeat"] = true,
|
||||
["return"] = true,
|
||||
["then"] = true,
|
||||
["true"] = true,
|
||||
["until"] = true,
|
||||
["while"] = true,
|
||||
}
|
||||
|
||||
local function tryWrite(sLine, regex, colour)
|
||||
local match = string.match(sLine, regex)
|
||||
if match then
|
||||
if type(colour) == "number" then
|
||||
term.setTextColour(colour)
|
||||
else
|
||||
term.setTextColour(colour(match))
|
||||
end
|
||||
term.write(match)
|
||||
term.setTextColour(textColour)
|
||||
return string.sub(sLine, #match + 1)
|
||||
end
|
||||
return nil
|
||||
local tokens = require "cc.internal.syntax.parser".tokens
|
||||
local lex_one = require "cc.internal.syntax.lexer".lex_one
|
||||
|
||||
local token_colours = {
|
||||
[tokens.STRING] = stringColour,
|
||||
[tokens.COMMENT] = commentColour,
|
||||
-- Keywords
|
||||
[tokens.AND] = keywordColour,
|
||||
[tokens.BREAK] = keywordColour,
|
||||
[tokens.DO] = keywordColour,
|
||||
[tokens.ELSE] = keywordColour,
|
||||
[tokens.ELSEIF] = keywordColour,
|
||||
[tokens.END] = keywordColour,
|
||||
[tokens.FALSE] = keywordColour,
|
||||
[tokens.FOR] = keywordColour,
|
||||
[tokens.FUNCTION] = keywordColour,
|
||||
[tokens.GOTO] = keywordColour,
|
||||
[tokens.IF] = keywordColour,
|
||||
[tokens.IN] = keywordColour,
|
||||
[tokens.LOCAL] = keywordColour,
|
||||
[tokens.NIL] = keywordColour,
|
||||
[tokens.NOT] = keywordColour,
|
||||
[tokens.OR] = keywordColour,
|
||||
[tokens.REPEAT] = keywordColour,
|
||||
[tokens.RETURN] = keywordColour,
|
||||
[tokens.THEN] = keywordColour,
|
||||
[tokens.TRUE] = keywordColour,
|
||||
[tokens.UNTIL] = keywordColour,
|
||||
[tokens.WHILE] = keywordColour,
|
||||
}
|
||||
-- Fill in the remaining tokens.
|
||||
for _, token in pairs(tokens) do
|
||||
if not token_colours[token] then token_colours[token] = textColour end
|
||||
end
|
||||
|
||||
local function writeHighlighted(sLine)
|
||||
while #sLine > 0 do
|
||||
sLine =
|
||||
tryWrite(sLine, "^%-%-%[%[.-%]%]", commentColour) or
|
||||
tryWrite(sLine, "^%-%-.*", commentColour) or
|
||||
tryWrite(sLine, "^\"\"", stringColour) or
|
||||
tryWrite(sLine, "^\".-[^\\]\"", stringColour) or
|
||||
tryWrite(sLine, "^\'\'", stringColour) or
|
||||
tryWrite(sLine, "^\'.-[^\\]\'", stringColour) or
|
||||
tryWrite(sLine, "^%[%[.-%]%]", stringColour) or
|
||||
tryWrite(sLine, "^[%w_]+", function(match)
|
||||
if tKeywords[match] then
|
||||
return keywordColour
|
||||
end
|
||||
return textColour
|
||||
end) or
|
||||
tryWrite(sLine, "^[^%w_]", textColour)
|
||||
local lex_context = { line = function() end, report = function() end }
|
||||
|
||||
local function writeHighlighted(line)
|
||||
local pos, colour = 1, nil
|
||||
|
||||
while true do
|
||||
local token, _, finish = lex_one(lex_context, line, pos)
|
||||
if not token then break end
|
||||
|
||||
local new_colour = token_colours[token]
|
||||
if new_colour ~= colour then
|
||||
term.setTextColor(new_colour)
|
||||
colour = new_colour
|
||||
end
|
||||
|
||||
term.write(line:sub(pos, finish))
|
||||
pos = finish + 1
|
||||
end
|
||||
|
||||
term.write(line:sub(pos))
|
||||
end
|
||||
|
||||
local tCompletions
|
||||
@ -352,7 +351,7 @@ local tMenuFuncs = {
|
||||
if bReadOnly then
|
||||
set_status("Access denied", false)
|
||||
else
|
||||
local ok, _, fileerr = save(sPath, function(file)
|
||||
local ok, _, fileerr = save(sPath, function(file)
|
||||
for _, sLine in ipairs(tLines) do
|
||||
file.write(sLine .. "\n")
|
||||
end
|
||||
@ -547,7 +546,7 @@ local function acceptCompletion()
|
||||
-- Append the completion
|
||||
local sCompletion = tCompletions[nCompletion]
|
||||
tLines[y] = tLines[y] .. sCompletion
|
||||
setCursor(x + #sCompletion , y)
|
||||
setCursor(x + #sCompletion, y)
|
||||
end
|
||||
end
|
||||
|
||||
@ -805,7 +804,7 @@ while bRunning do
|
||||
-- Input text
|
||||
local sLine = tLines[y]
|
||||
tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x)
|
||||
setCursor(x + #param , y)
|
||||
setCursor(x + #param, y)
|
||||
end
|
||||
|
||||
elseif sEvent == "mouse_click" then
|
||||
|
@ -191,7 +191,7 @@ end
|
||||
|
||||
-- Show MOTD
|
||||
if settings.get("motd.enable") then
|
||||
shell.run("motd")
|
||||
shell.run("/rom/programs/motd")
|
||||
end
|
||||
|
||||
-- Run the user created startup, either from disk drives or the root
|
||||
|
@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.util;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaValues;
|
||||
import dan200.computercraft.test.core.ReplaceUnderscoresDisplayNameGenerator;
|
||||
import org.junit.jupiter.api.DisplayNameGeneration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@DisplayNameGeneration(ReplaceUnderscoresDisplayNameGenerator.class)
|
||||
class StringUtilTest {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "hello\nworld", "hello\n\rworld", "hello\rworld" })
|
||||
public void getClipboardString_returns_a_single_line(String input) {
|
||||
var result = StringUtil.getClipboardString(input);
|
||||
assertEquals(LuaValues.encode("hello"), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClipboardString_limits_length() {
|
||||
var input = "abcdefghijklmnop".repeat(50);
|
||||
var result = StringUtil.getClipboardString(input);
|
||||
assertEquals(StringUtil.MAX_PASTE_LENGTH, result.limit());
|
||||
|
||||
assertEquals(
|
||||
LuaValues.encode(input.substring(0, StringUtil.MAX_PASTE_LENGTH)),
|
||||
result
|
||||
);
|
||||
}
|
||||
}
|
@ -94,6 +94,7 @@ describe("The colors library", function()
|
||||
end)
|
||||
|
||||
it("errors on out-of-range colours", function()
|
||||
expect.error(colors.toBlit, 0):eq("Colour out of range")
|
||||
expect.error(colors.toBlit, -120):eq("Colour out of range")
|
||||
expect.error(colors.toBlit, 0x10000):eq("Colour out of range")
|
||||
end)
|
||||
|
@ -59,6 +59,16 @@ describe("The window library", function()
|
||||
|
||||
expect.error(w.setTextColour, nil):eq("bad argument #1 (number expected, got nil)")
|
||||
expect.error(w.setTextColour, -5):eq("Colour out of range")
|
||||
expect.error(w.setTextColour, 0):eq("Colour out of range")
|
||||
expect.error(w.setTextColour, 0x10000):eq("Colour out of range")
|
||||
end)
|
||||
|
||||
it("accepts valid colours", function()
|
||||
local w = mk()
|
||||
for i = 0, 15 do
|
||||
w.setBackgroundColour(2 ^ i)
|
||||
expect(w.getBackgroundColour()):eq(2 ^ i)
|
||||
end
|
||||
end)
|
||||
|
||||
it("supports invalid combined colours", function()
|
||||
|
@ -67,7 +67,7 @@ This comment was never finished.
|
||||
1 | --[=[
|
||||
| ^^^^^ Comment was started here.
|
||||
We expected a closing delimiter (]=]) somewhere after this comment was started.
|
||||
1:1-1:5 ERROR --[=[
|
||||
1:1-1:5 COMMENT --[=[
|
||||
```
|
||||
|
||||
Nested comments are rejected, just as Lua 5.1 does:
|
||||
@ -191,7 +191,7 @@ This string was never finished.
|
||||
1 | return [[
|
||||
| ^^ String was started here.
|
||||
We expected a closing delimiter (]]) somewhere after this string was started.
|
||||
1:8-1:9 ERROR [[
|
||||
1:8-1:9 STRING [[
|
||||
```
|
||||
|
||||
We also handle malformed opening strings:
|
||||
|
Loading…
x
Reference in New Issue
Block a user