mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-05-04 00:14:13 +00:00
Add functions for parsing and drawing nft (#458)
This commit is contained in:
parent
9499654757
commit
b54519d0e6
@ -0,0 +1,107 @@
|
||||
--- Provides utilities for working with "nft" images.
|
||||
--
|
||||
-- nft ("Nitrogen Fingers Text") is a file format for drawing basic images.
|
||||
-- Unlike the images that @{paintutils.parseImage} uses, nft supports coloured
|
||||
-- text.
|
||||
--
|
||||
-- @module cc.image.nft
|
||||
-- @usage Load an image from `example.nft` and draw it.
|
||||
--
|
||||
-- local nft = require "cc.image.nft"
|
||||
-- local image = assert(nft.load("example.nft"))
|
||||
-- nft.draw(image)
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
|
||||
--- Parse an nft image from a string.
|
||||
--
|
||||
-- @tparam string image The image contents.
|
||||
-- @return table The parsed image.
|
||||
local function parse(image)
|
||||
expect(1, image, "string")
|
||||
|
||||
local result = {}
|
||||
local line = 1
|
||||
local foreground = "0"
|
||||
local background = "f"
|
||||
|
||||
local i, len = 1, #image
|
||||
while i <= len do
|
||||
local c = image:sub(i, i)
|
||||
if c == "\31" and i < len then
|
||||
i = i + 1
|
||||
foreground = image:sub(i, i)
|
||||
elseif c == "\30" and i < len then
|
||||
i = i + 1
|
||||
background = image:sub(i, i)
|
||||
elseif c == "\n" then
|
||||
if result[line] == nil then
|
||||
result[line] = { text = "", foreground = "", background = "" }
|
||||
end
|
||||
|
||||
line = line + 1
|
||||
else
|
||||
local next = image:find("[\n\30\31]", i) or #image + 1
|
||||
local seg_len = next - i
|
||||
|
||||
local this_line = result[line]
|
||||
if this_line == nil then
|
||||
this_line = { foreground = "", background = "", text = "" }
|
||||
result[line] = this_line
|
||||
end
|
||||
|
||||
this_line.text = this_line.text .. image:sub(i, next - 1)
|
||||
this_line.foreground = this_line.foreground .. foreground:rep(seg_len)
|
||||
this_line.background = this_line.background .. background:rep(seg_len)
|
||||
|
||||
i = next - 1
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Load an nft image from a file.
|
||||
--
|
||||
-- @tparam string path The file to load.
|
||||
-- @treturn[1] table The parsed image.
|
||||
-- @treturn[2] nil If the file does not exist or could not be loaded.
|
||||
-- @treturn[2] string An error message explaining why the file could not be
|
||||
-- loaded.
|
||||
local function load(path)
|
||||
expect(1, path, "string")
|
||||
local file, err = io.open(path, "r")
|
||||
if not file then return nil, err end
|
||||
|
||||
local result = file:read("*a")
|
||||
file:close()
|
||||
return parse(result)
|
||||
end
|
||||
|
||||
--- Draw an nft image to the screen.
|
||||
--
|
||||
-- @tparam table image An image, as returned from @{load} or @{draw}.
|
||||
-- @tparam number xPos The x position to start drawing at.
|
||||
-- @tparam number xPos The y position to start drawing at.
|
||||
-- @tparam[opt] term.Redirect target The terminal redirect to draw to. Defaults to the
|
||||
-- current terminal.
|
||||
local function draw(image, xPos, yPos, target)
|
||||
expect(1, image, "table")
|
||||
expect(2, xPos, "number")
|
||||
expect(3, yPos, "number")
|
||||
expect(4, target, "table", "nil")
|
||||
|
||||
if not target then target = term end
|
||||
|
||||
for y, line in ipairs(image) do
|
||||
target.setCursorPos(xPos, yPos + y - 1)
|
||||
target.blit(line.text, line.foreground, line.background)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
parse = parse,
|
||||
load = load,
|
||||
draw = draw,
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
local helpers = require "test_helpers"
|
||||
|
||||
describe("cc.image.nft", function()
|
||||
local nft = require("cc.image.nft")
|
||||
|
||||
describe("parse", function()
|
||||
it("validates arguments", function()
|
||||
nft.parse("")
|
||||
expect.error(nft.parse, nil):eq("bad argument #1 (expected string, got nil)")
|
||||
end)
|
||||
|
||||
it("parses an empty string", function()
|
||||
expect(nft.parse("")):same {}
|
||||
end)
|
||||
|
||||
it("parses a string with no colours", function()
|
||||
expect(nft.parse("Hello")):same { { text = "Hello", foreground = "00000", background = "fffff" } }
|
||||
end)
|
||||
|
||||
it("handles background and foreground colours", function()
|
||||
expect(nft.parse("\30a\31bHello"))
|
||||
:same { { text = "Hello", foreground = "bbbbb", background = "aaaaa" } }
|
||||
end)
|
||||
|
||||
it("parses multi-line files", function()
|
||||
expect(nft.parse("Hello\nWorld")):same {
|
||||
{ text = "Hello", foreground = "00000", background = "fffff" },
|
||||
{ text = "World", foreground = "00000", background = "fffff" },
|
||||
}
|
||||
end)
|
||||
|
||||
it("handles empty lines", function()
|
||||
expect(nft.parse("\n\n")):same {
|
||||
{ text = "", foreground = "", background = "" },
|
||||
{ text = "", foreground = "", background = "" },
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("load", function()
|
||||
it("validates arguments", function()
|
||||
nft.load("")
|
||||
expect.error(nft.load, nil):eq("bad argument #1 (expected string, got nil)")
|
||||
end)
|
||||
|
||||
it("loads from a file", function()
|
||||
local image = fs.open("/test-files/example.nft", "w")
|
||||
image.write("\30aHello, world!")
|
||||
image.close()
|
||||
|
||||
expect(nft.load("/test-files/example.nft")):same {
|
||||
{ background = "aaaaaaaaaaaaa", foreground = "0000000000000", text = "Hello, world!" },
|
||||
}
|
||||
end)
|
||||
|
||||
it("fails on missing files", function()
|
||||
expect({ nft.load("/test-files/not_a_file.nft") })
|
||||
:same { nil, "/test-files/not_a_file.nft: No such file" }
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("draw", function()
|
||||
it("validates arguments", function()
|
||||
expect.error(nft.draw, nil):eq("bad argument #1 (expected table, got nil)")
|
||||
expect.error(nft.draw, {}, nil):eq("bad argument #2 (expected number, got nil)")
|
||||
expect.error(nft.draw, {}, 1, nil):eq("bad argument #3 (expected number, got nil)")
|
||||
expect.error(nft.draw, {}, 1, 1, false):eq("bad argument #4 (expected table, got boolean)")
|
||||
end)
|
||||
|
||||
it("draws an image", function()
|
||||
local win = helpers.with_window(7, 3, function()
|
||||
nft.draw({
|
||||
{ background = "aaaaa", foreground = "f000f", text = "Hello" },
|
||||
}, 2, 2)
|
||||
end)
|
||||
|
||||
expect(win.getLine(1)):eq(" ")
|
||||
expect({ win.getLine(2) }):same { " Hello ", "0f000f0", "faaaaaf" }
|
||||
expect(win.getLine(3)):eq(" ")
|
||||
end)
|
||||
|
||||
it("draws an image to a custom redirect", function()
|
||||
local win = window.create(term.current(), 1, 1, 5, 1, false)
|
||||
nft.draw({
|
||||
{ background = "aaaaa", foreground = "f000f", text = "Hello" },
|
||||
}, 1, 1, win)
|
||||
|
||||
expect({ win.getLine(1) }):same { "Hello", "f000f", "aaaaa" }
|
||||
end)
|
||||
end)
|
||||
end)
|
Loading…
x
Reference in New Issue
Block a user