forum-dwarves.lua
-- Save a copy of a text screen for the DF forums
-- original author: Caldfir; edited by expwnent, Mchl
---
-- Library methods for handling unicode strings.
--
-- @author Daniel Miller
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
local string = require "string"
local table = require "table"
-- Localize a few functions for a tiny speed boost, since these will be looped
-- over every char of a string
local byte = string.byte
local char = string.char
local pack = string.pack
local unpack = string.unpack
local concat = table.concat
local helpstr = [====[
forum-dwarves
=============
Saves a copy of a text screen, formatted in bbcode for posting to the
Bay12 Forums. See `markdown` to export for Reddit etc.
This script will attempt to read the current df-screen, and if it is a
text-viewscreen (such as the dwarf 'thoughts' screen or an item
'description') then append a marked-up version of this text to the
target file. Previous entries in the file are not overwritten, so you
may use the 'forumdwarves' command multiple times to create a single
document containing the text from multiple screens (eg: text screens
from several dwarves, or text screens from multiple artifacts/items,
or some combination).
The screens which have been tested and known to function properly with
this script are:
1. dwarf/unit 'thoughts' screen
2. item/art 'description' screen
3. individual 'historical item/figure' screens
There may be other screens to which the script applies. It should be
safe to attempt running the script with any screen active, with an
error message to inform you when the selected screen is not appropriate
for this script.
The target file's name is 'forumdwarves.txt'. A reminder to this effect
will be displayed if the script is successful.
.. note::
The text will be encoded in CP437, which is likely to be incompatible
with the system default. This causes incorrect display of special
characters (eg. :guilabel:`é õ ç` = ``é õ ç``). You can fix this by
opening the file in an editor such as Notepad++ and selecting the
correct encoding before using the text.
]====]
local args = {...}
if args[1] == 'help' then
print(helpstr)
return
end
local utils = require 'utils'
local gui = require 'gui'
local dialog = require 'gui.dialogs'
local colors_css = {
- = 'black',
[1] = 'navy',
[2] = 'green',
[3] = 'teal',
[4] = 'maroon',
[5] = 'purple',
[6] = 'olive',
[7] = 'silver',
[8] = 'gray',
[9] = 'blue',
[10] = 'lime',
[11] = 'cyan',
[12] = 'red',
[13] = 'magenta',
[14] = 'yellow',
[15] = 'white'
}
local scrn = dfhack.gui.getCurViewscreen() --as:df.viewscreen_textviewerst
local flerb = dfhack.gui.getFocusString(scrn)
-- The following functions up until format_for_forum were shamelessly stolen from
https://github.com/nmap/nmap/blob/master/nselib/unicode.lua--Invert a one-to-one mapping
local function invert(t)
local out = {}
for k, v in pairs(t) do
out[v] = k
end
return out
end
-- Code Page 437, native US-English Windows OEM code page
local cp437_decode = {
[0x80] = 0x00c7,
[0x81] = 0x00fc,
[0x82] = 0x00e9,
[0x83] = 0x00e2,
[0x84] = 0x00e4,
[0x85] = 0x00e0,
[0x86] = 0x00e5,
[0x87] = 0x00e7,
[0x88] = 0x00ea,
[0x89] = 0x00eb,
[0x8a] = 0x00e8,
[0x8b] = 0x00ef,
[0x8c] = 0x00ee,
[0x8d] = 0x00ec,
[0x8e] = 0x00c4,
[0x8f] = 0x00c5,
[0x90] = 0x00c9,
[0x91] = 0x00e6,
[0x92] = 0x00c6,
[0x93] = 0x00f4,
[0x94] = 0x00f6,
[0x95] = 0x00f2,
[0x96] = 0x00fb,
[0x97] = 0x00f9,
[0x98] = 0x00ff,
[0x99] = 0x00d6,
[0x9a] = 0x00dc,
[0x9b] = 0x00a2,
[0x9c] = 0x00a3,
[0x9d] = 0x00a5,
[0x9e] = 0x20a7,
[0x9f] = 0x0192,
[0xa0] = 0x00e1,
[0xa1] = 0x00ed,
[0xa2] = 0x00f3,
[0xa3] = 0x00fa,
[0xa4] = 0x00f1,
[0xa5] = 0x00d1,
[0xa6] = 0x00aa,
[0xa7] = 0x00ba,
[0xa8] = 0x00bf,
[0xa9] = 0x2310,
[0xaa] = 0x00ac,
[0xab] = 0x00bd,
[0xac] = 0x00bc,
[0xad] = 0x00a1,
[0xae] = 0x00ab,
[0xaf] = 0x00bb,
[0xb0] = 0x2591,
[0xb1] = 0x2592,
[0xb2] = 0x2593,
[0xb3] = 0x2502,
[0xb4] = 0x2524,
[0xb5] = 0x2561,
[0xb6] = 0x2562,
[0xb7] = 0x2556,
[0xb8] = 0x2555,
[0xb9] = 0x2563,
[0xba] = 0x2551,
[0xbb] = 0x2557,
[0xbc] = 0x255d,
[0xbd] = 0x255c,
[0xbe] = 0x255b,
[0xbf] = 0x2510,
[0xc0] = 0x2514,
[0xc1] = 0x2534,
[0xc2] = 0x252c,
[0xc3] = 0x251c,
[0xc4] = 0x2500,
[0xc5] = 0x253c,
[0xc6] = 0x255e,
[0xc7] = 0x255f,
[0xc8] = 0x255a,
[0xc9] = 0x2554,
[0xca] = 0x2569,
[0xcb] = 0x2566,
[0xcc] = 0x2560,
[0xcd] = 0x2550,
[0xce] = 0x256c,
[0xcf] = 0x2567,
[0xd0] = 0x2568,
[0xd1] = 0x2564,
[0xd2] = 0x2565,
[0xd3] = 0x2559,
[0xd4] = 0x2558,
[0xd5] = 0x2552,
[0xd6] = 0x2553,
[0xd7] = 0x256b,
[0xd8] = 0x256a,
[0xd9] = 0x2518,
[0xda] = 0x250c,
[0xdb] = 0x2588,
[0xdc] = 0x2584,
[0xdd] = 0x258c,
[0xde] = 0x2590,
[0xdf] = 0x2580,
[0xe0] = 0x03b1,
[0xe1] = 0x00df,
[0xe2] = 0x0393,
[0xe3] = 0x03c0,
[0xe4] = 0x03a3,
[0xe5] = 0x03c3,
[0xe6] = 0x00b5,
[0xe7] = 0x03c4,
[0xe8] = 0x03a6,
[0xe9] = 0x0398,
[0xea] = 0x03a9,
[0xeb] = 0x03b4,
[0xec] = 0x221e,
[0xed] = 0x03c6,
[0xee] = 0x03b5,
[0xef] = 0x2229,
[0xf0] = 0x2261,
[0xf1] = 0x00b1,
[0xf2] = 0x2265,
[0xf3] = 0x2264,
[0xf4] = 0x2320,
[0xf5] = 0x2321,
[0xf6] = 0x00f7,
[0xf7] = 0x2248,
[0xf8] = 0x00b0,
[0xf9] = 0x2219,
[0xfa] = 0x00b7,
[0xfb] = 0x221a,
[0xfc] = 0x207f,
[0xfd] = 0x00b2,
[0xfe] = 0x25a0,
[0xff] = 0x00a0,
}
local cp437_encode = invert(cp437_decode)
--The string will be decoded and re-encoded in one pass. This saves some
--overhead vs simply passing the output of <code>unicode.encode</code> to
--<code>unicode.decode</code>.
function transcode(buf, decoder, encoder, bigendian_dec, bigendian_enc)
local out = {}
local cp
local pos = 1
while pos <= #buf do
pos, cp = decoder(buf, pos, bigendian_dec)
out[#out+1] = encoder(cp, bigendian_enc)
end
return table.concat(out)
end
---Encode a Unicode code point to UTF-8. See RFC 3629.
--
-- Does not check that cp is a real character; that is, doesn't exclude the
-- surrogate range U+D800 - U+DFFF and a handful of others.
function utf8_enc(cp)
local bytes = {}
local n, mask
if cp % 1.0 ~= 0.0 or cp < 0 then
-- Only defined for nonnegative integers.
return nil
elseif cp <= 0x7F then
-- Special case of one-byte encoding.
return char(cp)
elseif cp <= 0x7FF then
n = 2
mask = 0xC0
elseif cp <= 0xFFFF then
n = 3
mask = 0xE0
elseif cp <= 0x10FFFF then
n = 4
mask = 0xF0
else
return nil
end
while n > 1 do
bytes[n] = char(0x80 + (cp & 0x3F))
cp = cp >> 6
n = n - 1
end
bytes[1] = char(mask + cp)
return table.concat(bytes)
end
---Decodes a CP437 character
function cp437_dec(buf, pos)
pos = pos or 1
local bv = byte(buf, pos)
if bv < 0x80 then
return pos + 1, bv
else
return pos + 1, cp437_decode[bv]
end
end
local function format_for_forum(strin)
local strout = transcode(strin, cp437_dec, utf8_enc, false, false)
local newline_idx = string.find(strout, '[P]', 1, true)
while newline_idx ~= nil do
strout = string.sub(strout,1, newline_idx-1)..'\n'..string.sub(strout,newline_idx+3)
newline_idx = string.find(strout, '[P]', 1, true)
end
newline_idx = string.find(strout, '
', 1, true)
while newline_idx ~= nil do
strout = string.sub(strout,1, newline_idx-1)..'\n'..string.sub(strout,newline_idx+3)
newline_idx = string.find(strout, '', 1, true)
end
newline_idx = string.find(strout, '[R]', 1, true)
while newline_idx ~= nil do
strout = string.sub(strout,1, newline_idx-1)..'\n'..string.sub(strout,newline_idx+3)
newline_idx = string.find(strout, '[R]', 1, true)
end
local color_idx = string.find(strout, '[C:', 1, true)
while color_idx ~= nil do
local colormatch = (string.byte(strout, color_idx+3)-48)+((string.byte(strout, color_idx+7)-48)*8)
strout = string.sub(strout,1, color_idx-1)..'[/color][color='..colors_css[colormatch]..']'..string.sub(strout,color_idx+9)
color_idx = string.find(strout, '[C:', 1, true)
end
return strout
end
if flerb == 'textviewer' then
print(scrn)
printall(scrn)
local lines = scrn.src_text
local line = ""
local first = true
if lines ~= nil then
local log = io.open('forumdwarves.txt', 'a')
log:write("")
local titleconv = transcode(scrn.title, cp437_dec, utf8_enc, false, false)
log:write(titleconv)
for n,x in ipairs(lines) do
print(x)
printall(x)
print(x.value)
printall(x.value)
if (x ~= nil) and (x.value ~= nil) then
log:write(format_for_forum(x.value), ' ')
--log:write(x[0],'\n')
end
end
log:write("\n")
log:close()
end
print 'data prepared for forum in \"forumdwarves.txt\"'
else
print 'this is not a textview screen'
end