diff options
Diffstat (limited to 'macros/luatex')
-rw-r--r-- | macros/luatex/generic/nodetree/nodetree.dtx | 10 | ||||
-rw-r--r-- | macros/luatex/generic/nodetree/nodetree.lua | 165 | ||||
-rw-r--r-- | macros/luatex/generic/nodetree/nodetree.pdf | bin | 357181 -> 361618 bytes |
3 files changed, 134 insertions, 41 deletions
diff --git a/macros/luatex/generic/nodetree/nodetree.dtx b/macros/luatex/generic/nodetree/nodetree.dtx index 5b18176843..30eb6bea9e 100644 --- a/macros/luatex/generic/nodetree/nodetree.dtx +++ b/macros/luatex/generic/nodetree/nodetree.dtx @@ -28,7 +28,7 @@ %<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01] %<package>\ProvidesPackage{nodetree} %<*package> - [2020/05/29 v2.0 Visualize node lists in a tree view] + [2020/10/03 v2.1 Visualize node lists in a tree view] %</package> % \fi % @@ -65,7 +65,10 @@ % * Less verbose representation of node attributes. % * Minor tree output adjustments. % } -% +% \changes{v2.1}{2020/10/03}{ +% * Make the package compatible with the Harfbuzz mode of the luaotfload fontloader. +% * Print node properties of copied nodes. +% } % \DoNotIndex{\newcommand,\newenvironment,\def,\directlua} % % \StopEventually{} @@ -119,7 +122,6 @@ \NodetreeResetOption{channel} \NodetreeResetOption{color} \NodetreeResetOption{decimalplaces} - \NodetreeResetOption{engine} \NodetreeResetOption{unit} \NodetreeResetOption{verbosity} } @@ -229,7 +231,7 @@ % \begin{macrocode} \NeedsTeXFormat{LaTeX2e}[1994/06/01] \ProvidesPackage{nodetree-embed} - [2020/05/29 v2.0 Embed node trees into a LaTeX document] + [2020/10/03 v2.1 Embed node trees into a LaTeX document] % \end{macrocode} % % \begin{macrocode} diff --git a/macros/luatex/generic/nodetree/nodetree.lua b/macros/luatex/generic/nodetree/nodetree.lua index 666413578d..880f189544 100644 --- a/macros/luatex/generic/nodetree/nodetree.lua +++ b/macros/luatex/generic/nodetree/nodetree.lua @@ -16,13 +16,19 @@ -- luacheck: globals node tex luatexbase lfs callback os unicode status modules if not modules then modules = { } end modules ['nodetree'] = { - version = '2.0', + version = '2.1', comment = 'nodetree', author = 'Josef Friedrich', copyright = 'Josef Friedrich', license = 'The LaTeX Project Public License Version 1.3c 2008-05-04' } +local direct = node.direct +local todirect = direct.todirect +local getchar = direct.getchar +local utfchar = utf8.char +local properties = direct.get_properties_table() + --- A counter for the compiled TeX examples. Some TeX code snippets -- a written into file, wrapped with some TeX boilerplate code. -- This written files are compiled. @@ -34,7 +40,6 @@ local default_options = { channel = 'term', color = 'colored', decimalplaces = 2, - engine = 'luatex', -- Required for the callback registration unit = 'pt', verbosity = 1, } @@ -46,10 +51,6 @@ for key, value in pairs(default_options) do options[key] = value end -if arg[0] == 'lualatex' then - options.engine = 'lualatex' -end - --- File descriptor local output_file @@ -334,18 +335,65 @@ local template = { return output .. format.color_code(code) end, - --- Format a single unicode character. + --- Format the char field of a node. Try to find a textual representation that + -- corresponds with the number stored into the `char` field. -- - -- @tparam string char A single input character. + -- LuaTeX’s `node.char` are not really characters, they are font glyph indices + -- which sometimes happen to match valid Unicode characters. HarfBuzz shapers + -- differentiates between glyph IDs and characters by adding to 0x120000 to + -- glyph ID. -- - -- @treturn string - char = function(char) - char = string.format('%s', unicode.utf8.char(char)) - char = '\'' .. char .. '\'' - if options.channel == 'tex' then - char = format.escape(char) + -- The code of this function is borrowed from the [function + -- `get_glyph_info(n)`](https://github.com/latex3/luaotfload/blob/4c09fe264c1644792d95182280be259449e7da02/src/luaotfload-harf-plug.lua#L1018-L1031) + -- of the luaotfload package. The harfbuzz mode in luaotfload uses this + -- function to embed text in a PDF file and for messages that show textual + -- representation of the nodes like over/underfull messages. It will not + -- result in an error in other modes, but it might not give proper text + -- representation, but that is a limitation of these modes. + -- + -- It should be understood what the glyph nodes represent. Before + -- processing by luaotfload they represent one-to-one mapping of the + -- input characters. After processing, they represent font glyphs with + -- potentially complicated relationship with input characters. + -- + -- Relation between input characters and output glyphs are many-to-many. + -- An input character may be represented by one or more glyphs, and + -- output glyph might represent one or more input characters, and in + -- some cases (e.g. when there is reordering) a group of input + -- characters are represented by a group of output glyphs. In the 2nd + -- and 3rd cases, the first glyph node will have a `glyph_info` property + -- with all the characters of the group, and subsequent glyph nodes in + -- the group will have empty `glyph_info` properties. + -- + -- It should also noted that this mapping is not unique, the same glyph + -- can represent different characters in different context. + -- + -- @tparam node head The head node of a node list. + -- + -- @treturn string A textual representation of the `char` number. + -- In verbosity level 2 or great suffixed with `[char number]` + char = function(head) + -- See Issue #6 + local node_id = todirect(head) -- Convert to node id + local props = properties[node_id] + local info = props and props.glyph_info + + local output + if info then + output = info + end + local c = getchar(node_id) + if c == 0 then + output = '^^@' + elseif c < 0x110000 then + output = utfchar(c) + else + output = string.format("^^^^^^%06X", c) + end + if options.verbosity > 1 then + return output .. ' [' .. head.char .. ']' end - return char + return output end, --- @@ -450,6 +498,47 @@ function template.length (input) ) end +--- Get all data from a table including metatables. +-- +-- Properties will reside in a metatable, if nodes were copied using an +-- operation like box copy: (\copy). The LuaTeX manual states this: “If +-- the second argument of `set_properties_mode` is true, then a +-- metatable approach is chosen: the copy gets its own table with the +-- original table as metatable.” +-- +-- Source: https://stackoverflow.com/a/5639667 Works if __index returns +-- table, which it should as per luatex manual +-- +-- @tparam table table A Lua table. +-- @tparam table previous_data table The of data of +-- a Lua table of a previous recursive call. +-- +-- @treturn table A merged table. +local function get_all_table_data(table, previous_data) + -- If previous_data is nil, start empty, otherwise start with previous_data. + local data = previous_data or {} + + -- Copy all the attributes from the table. + for key, value in pairs(table) do + data[key] = data[key] or value + end + + -- Get table’s metatable, or exit if not existing + local metatable = getmetatable(table) + if type(metatable) ~= 'table' then + return data + end + + -- Get the `__index` from metatable, or exit if not table. + local index = metatable.__index + if type(index) ~= 'table' then + return data + end + + -- Include the data from index into data, recursively, and return. + return get_all_table_data(index, data) +end + --- Convert a Lua table into a format string. -- -- @tparam table table A table to generate a inline view of. @@ -461,6 +550,7 @@ function template.table_inline(table) tex_escape = '\\' end if type(table) == 'table' then + table = get_all_table_data(table) local output = tex_escape .. '{' local kv_list = '' for key, value in pairs(table) do @@ -833,7 +923,7 @@ end local tree = {} --- --- @tparam node head +-- @tparam node head The head node of a node list. -- @tparam string field -- -- @treturn string @@ -879,7 +969,7 @@ function tree.format_field(head, field) field == 'shift' then output = template.length(head[field]) elseif field == 'char' then - output = template.char(head[field]) + output = template.char(head) elseif field == 'glue_set' then output = format.number(head[field]) elseif field == 'stretch' or field == 'shrink' then @@ -896,7 +986,7 @@ end -- list. The attribute `0` with the value `0` is skipped because this -- attribute is in every node by default. -- --- @tparam node head +-- @tparam node head The head node of a node list. -- -- @treturn string function tree.format_attributes(head) @@ -957,7 +1047,7 @@ function tree.analyze_fields(fields, level) end --- --- @tparam node head +-- @tparam node head The head node of a node list. -- @tparam number level function tree.analyze_node(head, level) local connection_state @@ -1027,7 +1117,7 @@ function tree.analyze_node(head, level) end --- --- @tparam node head +-- @tparam node head The head node of a node list. -- @tparam number level function tree.analyze_list(head, level) while head do @@ -1037,7 +1127,7 @@ function tree.analyze_list(head, level) end --- --- @tparam node head +-- @tparam node head The head node of a node list. function tree.analyze_callback(head) tree.analyze_list(head, 1) nodetree_print(template.line('short') .. format.new_line()) @@ -1072,7 +1162,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam string groupcode pre_linebreak_filter = function(head, groupcode) template.callback('pre_linebreak_filter', {groupcode = groupcode}) @@ -1081,7 +1171,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam boolean is_display linebreak_filter = function(head, is_display) template.callback('linebreak_filter', {is_display = is_display}) @@ -1106,7 +1196,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam string groupcode post_linebreak_filter = function(head, groupcode) template.callback('post_linebreak_filter', {groupcode = groupcode}) @@ -1115,7 +1205,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam string groupcode -- @tparam number size -- @tparam string packtype @@ -1135,7 +1225,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam string groupcode -- @tparam number size -- @tparam string packtype @@ -1159,7 +1249,7 @@ local callbacks = { --- -- @tparam string incident -- @tparam number detail - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam number first -- @tparam number last hpack_quality = function(incident, detail, head, first, last) @@ -1176,7 +1266,7 @@ local callbacks = { --- -- @tparam string incident -- @tparam number detail - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam number first -- @tparam number last vpack_quality = function(incident, detail, head, first, last) @@ -1191,7 +1281,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam number width -- @tparam number height process_rule = function(head, width, height) @@ -1205,7 +1295,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam string groupcode -- @tparam number size -- @tparam string packtype @@ -1225,7 +1315,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam node tail hyphenate = function(head, tail) template.callback('hyphenate') @@ -1236,7 +1326,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam node tail ligaturing = function(head, tail) template.callback('ligaturing') @@ -1247,7 +1337,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam node tail kerning = function(head, tail) template.callback('kerning') @@ -1267,7 +1357,7 @@ local callbacks = { end, --- - -- @tparam node head + -- @tparam node head The head node of a node list. -- @tparam string display_type -- @tparam boolean need_penalties mlist_to_hlist = function(head, display_type, need_penalties) @@ -1403,7 +1493,7 @@ end -- -- @tparam string cb The name of a callback. local function register_callback(cb) - if options.engine == 'lualatex' then + if luatexbase then luatexbase.add_to_callback(cb, callbacks[cb], 'nodetree') else callback.register(cb, callbacks[cb]) @@ -1414,7 +1504,7 @@ end -- -- @tparam string cb The name of a callback. local function unregister_callback(cb) - if options.engine == 'lualatex' then + if luatexbase then luatexbase.remove_from_callback(cb, 'nodetree') else register_callback(cb, nil) @@ -1541,7 +1631,8 @@ local export = { } --- Use export.print --- @tparam node head +-- +-- @tparam node head The head node of a node list. export.analyze = export.print return export diff --git a/macros/luatex/generic/nodetree/nodetree.pdf b/macros/luatex/generic/nodetree/nodetree.pdf Binary files differindex c7cdf1d72c..ab7b6c9539 100644 --- a/macros/luatex/generic/nodetree/nodetree.pdf +++ b/macros/luatex/generic/nodetree/nodetree.pdf |