summaryrefslogtreecommitdiff
path: root/macros/luatex
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex')
-rw-r--r--macros/luatex/generic/nodetree/nodetree.dtx10
-rw-r--r--macros/luatex/generic/nodetree/nodetree.lua165
-rw-r--r--macros/luatex/generic/nodetree/nodetree.pdfbin357181 -> 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
index c7cdf1d72c..ab7b6c9539 100644
--- a/macros/luatex/generic/nodetree/nodetree.pdf
+++ b/macros/luatex/generic/nodetree/nodetree.pdf
Binary files differ