1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-03-31 15:56:58 +00:00

Standardise on term colour parsing

- colors.toBlit now performs bounds checks on the passed value,
   preventing weird behaviour like color.toBlit(2 ^ 16) returning "10".

 - The window API now uses colors.toBlit (or rather a copy of it) for
   parsing colours, allowing doing silly things like
   term.setTextColour(colours.blue + 5).

 - Add some top-level documentation to the term API to explain some of
   the basics.

Closes #1736
This commit is contained in:
Jonathan Coates 2024-03-06 10:18:09 +00:00
parent 4daa2a2b6a
commit 6e374579a4
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
5 changed files with 86 additions and 25 deletions

View File

@ -13,8 +13,54 @@ import dan200.computercraft.core.util.Colour;
/** /**
* Interact with a computer's terminal or monitors, writing text and drawing * Interact with a computer's terminal or monitors, writing text and drawing ASCII graphics.
* ASCII graphics. *
* <h2>Writing to the terminal</h2>
* The simplest operation one can perform on a terminal is displaying (or writing) some text. This can be performed with
* the [`term.write`] method.
*
* <pre>{@code
* term.write("Hello, world!")
* }</pre>
* <p>
* When you write text, this advances the cursor, so the next call to [`term.write`] will write text immediately after
* the previous one.
*
* <pre>{@code
* term.write("Hello, world!")
* term.write("Some more text")
* }</pre>
* <p>
* [`term.getCursorPos`] and [`term.setCursorPos`] can be used to manually change the cursor's position.
* <p>
* <pre>{@code
* term.clear()
*
* term.setCursorPos(1, 1) -- The first column of line 1
* term.write("First line")
*
* term.setCursorPos(20, 2) -- The 20th column of line 2
* term.write("Second line")
* }</pre>
* <p>
* [`term.write`] is a relatively basic and low-level function, and does not handle more advanced features such as line
* breaks or word wrapping. If you just want to display text to the screen, you probably want to use [`print`] or
* [`write`] instead.
*
* <h2>Colours</h2>
* So far we've been writing text in black and white. However, advanced computers are also capable of displaying text
* in a variety of colours, with the [`term.setTextColour`] and [`term.setBackgroundColour`] functions.
*
* <pre>{@code
* print("This text is white")
* term.setTextColour(colours.green)
* print("This text is green")
* }</pre>
* <p>
* These functions accept any of the constants from the [`colors`] API. [Combinations of colours][`colors.combine`] may
* be accepted, but will only display a single colour (typically following the behaviour of [`colors.toBlit`]).
* <p>
* The [`paintutils`] API provides several helpful functions for displaying graphics using [`term.setBackgroundColour`].
* *
* @cc.module term * @cc.module term
*/ */

View File

@ -353,7 +353,8 @@ end
--[[- Converts the given color to a paint/blit hex character (0-9a-f). --[[- Converts the given color to a paint/blit hex character (0-9a-f).
This is equivalent to converting floor(log_2(color)) to hexadecimal. This is equivalent to converting `floor(log_2(color))` to hexadecimal. Values
outside the range of a valid colour will error.
@tparam number color The color to convert. @tparam number color The color to convert.
@treturn string The blit hex code of the color. @treturn string The blit hex code of the color.
@ -367,7 +368,11 @@ colors.toBlit(colors.red)
]] ]]
function toBlit(color) function toBlit(color)
expect(1, color, "number") expect(1, color, "number")
return color_hex_lookup[color] or string.format("%x", math.floor(math.log(color, 2))) 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
return string.format("%x", math.floor(math.log(color, 2)))
end end
--[[- Converts the given paint/blit hex character (0-9a-f) to a color. --[[- Converts the given paint/blit hex character (0-9a-f) to a color.

View File

@ -58,6 +58,17 @@ local type = type
local string_rep = string.rep local string_rep = string.rep
local string_sub = string.sub local string_sub = string.sub
--- A custom version of [`colors.toBlit`], specialised for the window API.
local function parse_color(color)
if type(color) ~= "number" then
-- By tail-calling expect, we ensure expect has the right error level.
return expect(1, color, "number")
end
if color < 0 or color > 0xffff then error("Colour out of range", 3) end
return 2 ^ math.floor(math.log(color, 2))
end
--[[- Returns a terminal object that is a space within the specified parent --[[- Returns a terminal object that is a space within the specified parent
terminal object. This can then be used (or even redirected to) in the same terminal object. This can then be used (or even redirected to) in the same
manner as eg a wrapped monitor. Refer to [the term API][`term`] for a list of manner as eg a wrapped monitor. Refer to [the term API][`term`] for a list of
@ -341,10 +352,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
end end
local function setTextColor(color) local function setTextColor(color)
if type(color) ~= "number" then expect(1, color, "number") end if tHex[color] == nil then color = parse_color(color) end
if tHex[color] == nil then
error("Invalid color (got " .. color .. ")" , 2)
end
nTextColor = color nTextColor = color
if bVisible then if bVisible then
@ -356,11 +364,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
window.setTextColour = setTextColor window.setTextColour = setTextColor
function window.setPaletteColour(colour, r, g, b) function window.setPaletteColour(colour, r, g, b)
if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then colour = parse_color(colour) end
if tHex[colour] == nil then
error("Invalid color (got " .. colour .. ")" , 2)
end
local tCol local tCol
if type(r) == "number" and g == nil and b == nil then if type(r) == "number" and g == nil and b == nil then
@ -385,10 +389,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
window.setPaletteColor = window.setPaletteColour window.setPaletteColor = window.setPaletteColour
function window.getPaletteColour(colour) function window.getPaletteColour(colour)
if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then colour = parse_color(colour) end
if tHex[colour] == nil then
error("Invalid color (got " .. colour .. ")" , 2)
end
local tCol = tPalette[colour] local tCol = tPalette[colour]
return tCol[1], tCol[2], tCol[3] return tCol[1], tCol[2], tCol[3]
end end
@ -396,10 +397,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
window.getPaletteColor = window.getPaletteColour window.getPaletteColor = window.getPaletteColour
local function setBackgroundColor(color) local function setBackgroundColor(color)
if type(color) ~= "number" then expect(1, color, "number") end if tHex[color] == nil then color = parse_color(color) end
if tHex[color] == nil then
error("Invalid color (got " .. color .. ")", 2)
end
nBackgroundColor = color nBackgroundColor = color
end end

View File

@ -92,6 +92,11 @@ describe("The colors library", function()
it("floors colors", function() it("floors colors", function()
expect(colors.toBlit(16385)):eq("e") expect(colors.toBlit(16385)):eq("e")
end) end)
it("errors on out-of-range colours", function()
expect.error(colors.toBlit, -120):eq("Colour out of range")
expect.error(colors.toBlit, 0x10000):eq("Colour out of range")
end)
end) end)
describe("colors.fromBlit", function() describe("colors.fromBlit", function()

View File

@ -58,7 +58,14 @@ describe("The window library", function()
w.setTextColour(colors.white) w.setTextColour(colors.white)
expect.error(w.setTextColour, nil):eq("bad argument #1 (number expected, got nil)") expect.error(w.setTextColour, nil):eq("bad argument #1 (number expected, got nil)")
expect.error(w.setTextColour, -5):eq("Invalid color (got -5)") expect.error(w.setTextColour, -5):eq("Colour out of range")
end)
it("supports invalid combined colours", function()
local w = mk()
w.setTextColour(colours.combine(colours.red, colours.green))
expect(w.getTextColour()):eq(colours.red)
end) end)
end) end)
@ -69,7 +76,7 @@ describe("The window library", function()
w.setPaletteColour(colors.white, 0x000000) w.setPaletteColour(colors.white, 0x000000)
expect.error(w.setPaletteColour, nil):eq("bad argument #1 (number expected, got nil)") expect.error(w.setPaletteColour, nil):eq("bad argument #1 (number expected, got nil)")
expect.error(w.setPaletteColour, -5):eq("Invalid color (got -5)") expect.error(w.setPaletteColour, -5):eq("Colour out of range")
expect.error(w.setPaletteColour, colors.white):eq("bad argument #2 (number expected, got nil)") expect.error(w.setPaletteColour, colors.white):eq("bad argument #2 (number expected, got nil)")
expect.error(w.setPaletteColour, colors.white, 1, false):eq("bad argument #3 (number expected, got boolean)") expect.error(w.setPaletteColour, colors.white, 1, false):eq("bad argument #3 (number expected, got boolean)")
expect.error(w.setPaletteColour, colors.white, 1, nil, 1):eq("bad argument #3 (number expected, got nil)") expect.error(w.setPaletteColour, colors.white, 1, nil, 1):eq("bad argument #3 (number expected, got nil)")
@ -82,7 +89,7 @@ describe("The window library", function()
local w = mk() local w = mk()
w.getPaletteColour(colors.white) w.getPaletteColour(colors.white)
expect.error(w.getPaletteColour, nil):eq("bad argument #1 (number expected, got nil)") expect.error(w.getPaletteColour, nil):eq("bad argument #1 (number expected, got nil)")
expect.error(w.getPaletteColour, -5):eq("Invalid color (got -5)") expect.error(w.getPaletteColour, -5):eq("Colour out of range")
end) end)
end) end)
@ -92,7 +99,7 @@ describe("The window library", function()
w.setBackgroundColour(colors.white) w.setBackgroundColour(colors.white)
expect.error(w.setBackgroundColour, nil):eq("bad argument #1 (number expected, got nil)") expect.error(w.setBackgroundColour, nil):eq("bad argument #1 (number expected, got nil)")
expect.error(w.setBackgroundColour, -5):eq("Invalid color (got -5)") expect.error(w.setBackgroundColour, -5):eq("Colour out of range")
end) end)
end) end)