@@ -1500,4 +1500,58 @@ function typesetter:liner (name, content, outputYourself)
15001500 end
15011501end
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+
15031557return typesetter
0 commit comments