Skip to content

Commit 6af4934

Browse files
OmikhleiaDidier Willis
authored andcommitted
feat(typesetters): Add content to text utility to the base typesetter
Such textual reconstructions from typeset nodes were performed differently in the tableofcontents and indexer packages, and possibly elsewhere. The logic is tied to the typeset nodes and typesetter internal states, so it's better moved there.
1 parent 4572ad2 commit 6af4934

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

typesetters/base.lua

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,4 +1500,58 @@ function typesetter:liner (name, content, outputYourself)
15001500
end
15011501
end
15021502

1503+
--- Flatten a node list into just its string representation.
1504+
-- @tparam table nodes Typeset nodes
1505+
-- @treturn string Textual Text reconstruction of the nodes
1506+
local function _nodesToText (nodes)
1507+
-- A real interword space width depends on several settings (depending on variable
1508+
-- spaces being enabled or not, etc.), and the computation below takes that into
1509+
-- account.
1510+
local iwspc = SILE.shaper:measureSpace(SILE.font.loadDefaults({}))
1511+
local iwspcmin = (iwspc.length - iwspc.shrink):tonumber()
1512+
1513+
local string = ""
1514+
for i = 1, #nodes do
1515+
local node = nodes[i]
1516+
if node.is_nnode or node.is_unshaped then
1517+
string = string .. node:toText()
1518+
elseif node.is_glue or node.is_kern then
1519+
-- What we want to avoid is "small" glues or kerns to be expanded as full
1520+
-- spaces.
1521+
-- Comparing them to half of the smallest width of a possibly shrinkable
1522+
-- interword space is fairly fragile and empirical: the content could contain
1523+
-- font changes, so the comparison is wrong in the general case.
1524+
-- It's a simplistic approach. We cannot really be sure what a "space" meant
1525+
-- at the point where the kern or glue got absolutized.
1526+
if node.width:tonumber() > iwspcmin * 0.5 then
1527+
string = string .. " "
1528+
end
1529+
elseif not (node.is_zerohbox or node.is_migrating) then
1530+
-- Here, typically, the main case is an hbox.
1531+
-- Even if extracting its content could be possible in some regular cases
1532+
-- we cannot take a general decision, as it is a versatile object and its
1533+
-- outputYourself() method could moreover have been redefined to do fancy
1534+
-- things. Better warn and skip.
1535+
SU.warn("Some content could not be converted to text: " .. node)
1536+
end
1537+
end
1538+
-- Trim leading and trailing spaces, and simplify internal spaces.
1539+
return pl.stringx.strip(string):gsub("%s%s+", " ")
1540+
end
1541+
1542+
--- Convert a SILE AST to a textual representation.
1543+
-- This is similar to SU.ast.contentToString(), but it performs a full
1544+
-- typesetting of the content, and then reconstructs the text from the
1545+
-- typeset nodes.
1546+
-- @tparam table content SILE AST to process
1547+
-- @treturn string Textual representation of the content
1548+
function typesetter:contentToText (content)
1549+
self:pushState()
1550+
self.state.hmodeOnly = true
1551+
SILE.process(content)
1552+
local text = _nodesToText(self.state.nodes)
1553+
self:popState()
1554+
return text
1555+
end
1556+
15031557
return typesetter

0 commit comments

Comments
 (0)