Add functions to wrap text

This commit is contained in:
Lupus590 2020-12-23 16:19:54 +00:00 committed by Jonathan Coates
parent 24bb92007a
commit 16d74dd2e8
2 changed files with 143 additions and 0 deletions

View File

@ -0,0 +1,102 @@
--- Various utilities for working with strings and text.
--
-- @see textutils For additional string related utilities.
local expect = require "cc.expect".expect
--- 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.
-- @usage require "cc.strings".wrap("This is a long piece of text", 10)
local function wrap(text, width)
expect(1, text, "string")
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
local sub, match = string.sub, string.match
while pos <= length do
local head = sub(text, pos, pos)
if head == " " or head == "\t" then
local whitespace = match(text, "^[ \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)
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 .. sub(word, 1, space_remaining)
word = sub(word, 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)
expect(1, line, "string")
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

@ -0,0 +1,41 @@
describe("cc.pretty", function()
local str = require("cc.strings")
describe("wrap", function()
it("validates arguments", function()
str.wrap("test string is long")
str.wrap("test string is long", 11)
expect.error(str.wrap, nil):eq("bad argument #1 (expected string, got nil)")
expect.error(str.wrap, "", false):eq("bad argument #2 (expected number, got boolean)")
end)
it("wraps lines", function()
expect(str.wrap("test string is long")[1]):eq("test string is long")
expect(str.wrap("test string is long", 15)[1]):eq("test string is ")
expect(str.wrap("test string is long", 15)[2]):eq("long")
expect(str.wrap("test string is long", 12)[1]):eq("test string ")
expect(str.wrap("test string is long", 12)[2]):eq("is long")
expect(str.wrap("test string is long", 11)[1]):eq("test string")
expect(str.wrap("test string is long", 11)[2]):eq("is long")
end)
end)
describe("ensure_width", function()
it("validates arguments", function()
str.wrap("test string is long")
str.wrap("test string is long", 11)
expect.error(str.ensure_width, nil):eq("bad argument #1 (expected string, got nil)")
expect.error(str.ensure_width, "", false):eq("bad argument #2 (expected number, got boolean)")
end)
it("pads lines", function()
expect(str.ensure_width("test string is long", 25)):eq("test string is long ")
end)
it("truncates lines", function()
expect(str.ensure_width("test string is long", 15)):eq("test string is ")
end)
end)
end)