mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Add functions for parsing and drawing nft (#458)
This commit is contained in:
		| @@ -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) | ||||
		Reference in New Issue
	
	Block a user
	 JakobDev
					JakobDev