user_defined node clears \lastskip
Hi, I'm sure that for lua gurus it is known behavior that user_defined whatsit clears the \lastskip but for me it was a big surprise. little example: aa \vskip11.1pt \showthe\lastskip \directlua{% local x = node.new('whatsit', 'user_defined') x.type=115 x.value="TEXT" node.write(x) }% \showthe\lastskip \bye log:
11.1pt. l.4 \showthe\lastskip
?
0.0pt. l.13 \showthe\lastskip
I just accidentally noticed that I messed up output trying to markup document. I was sure that luatex will step over these whatsits. Is there another way to write user_defined whatsits directly without effecting \lastskip? My goal is to mark text in DVI mode with user_defined whatsits and on the shipout turn them to postscript \special's for accessible pdf Thanks, Linas
On 5/29/2024 8:58 PM, Linas Stonys wrote:
Hi, I'm sure that for lua gurus it is known behavior that user_defined whatsit clears the \lastskip but for me it was a big surprise.
little example: aa \vskip11.1pt \showthe\lastskip \directlua{% local x = node.new('whatsit', 'user_defined') x.type=115 x.value="TEXT" node.write(x) }% \showthe\lastskip \bye
log:
11.1pt. l.4 \showthe\lastskip
?
0.0pt. l.13 \showthe\lastskip
I just accidentally noticed that I messed up output trying to markup document. I was sure that luatex will step over these whatsits.
Is there another way to write user_defined whatsits directly without effecting \lastskip? My goal is to mark text in DVI mode with user_defined whatsits and on the shipout turn them to postscript \special's for accessible pdf I'd probably try to insert before the last glue in a list but it all depends one the macro package and what it does with skips etc in various
Why? We also have \lastpenalty etc and if would become confusing if last means "last seen" instead of last on the list. It's not a register but a 'reference to a stored state'. You could check the lastskip before you write the whatsit, maybe backtrack i.e. remove it, insert the whatsit and then reinsert the glue node or otherwise insert the whatsit before the last node if it's a skip (you can mess with the current list) places. Hans ----------------------------------------------------------------- Hans Hagen | PRAGMA ADE Ridderstraat 27 | 8061 GH Hasselt | The Netherlands tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl -----------------------------------------------------------------
On Wed, 29 May 2024 at 20:07, Linas Stonys
Hi, I'm sure that for lua gurus it is known behavior that user_defined whatsit clears the \lastskip but for me it was a big surprise.
that is consistent with other whatsits from classic tex like \special or \write, or in fact any node of any type. \lastskip only picks up a value if the last node added to the current list is a skip.
little example: aa \vskip11.1pt \showthe\lastskip \directlua{% local x = node.new('whatsit', 'user_defined') x.type=115 x.value="TEXT" node.write(x) }% \showthe\lastskip \bye
log:
11.1pt. l.4 \showthe\lastskip
?
0.0pt. l.13 \showthe\lastskip
I just accidentally noticed that I messed up output trying to markup document. I was sure that luatex will step over these whatsits. Is there another way to write user_defined whatsits directly without effecting \lastskip? My goal is to mark text in DVI mode with user_defined whatsits and on the shipout turn them to postscript \special's for accessible pdf
Thanks, Linas _______________________________________________ dev-luatex mailing list -- dev-luatex@ntg.nl To unsubscribe send an email to dev-luatex-leave@ntg.nl
I know I'm asking impossible but who knows... Maybe in the "near" future luatex could adapt user_defined whatsit to have some more fields where it could store lastskip, lastpenalty, ... So that \last... checkers could point to this corresponding field to check the value if it sees that last node is user_defined whatsit :)
that is consistent with other whatsits from classic tex like \special or \write, or in fact any node of any type. \lastskip only picks up a value if the last node added to the current list is a skip.
On 5/29/2024 10:08 PM, Linas Stonys wrote:
I know I'm asking impossible but who knows... Maybe in the "near" future luatex could adapt user_defined whatsit to have some more fields where it could store lastskip, lastpenalty, ... So that \last... checkers could point to this corresponding field to check the value if it sees that last node is user_defined whatsit
that would then also involve some guesswork and be somewhat alien to how these state variables are handled you could set a property (or attribute) on x that stores the skip, and then redefine lastskip to look at the list and if found fetch that value or otherwise report the normal one or you can be adventurous and intercept the builder in a callback
:) because injecting whatsits this way will likely mess up your page building unless you take precautions you can as well do something
aa \vskip10pt \skip0\lastskip \vskip-\lastskip \directlua{% local x = node.new('whatsit', 'user_defined') x.type = 115 x.value = "TEXT" node.write(x) }% \vskip\skip0 bb with a bit testing and maybe some penalties .. it all depends on how / what / where you inject, after all you probably want to keep the whatsit bound to what comes before anyway (as you check the skip) Hans ----------------------------------------------------------------- Hans Hagen | PRAGMA ADE Ridderstraat 27 | 8061 GH Hasselt | The Netherlands tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl -----------------------------------------------------------------
Hi Linas, On Wed, 2024-05-29 at 21:58 +0300, Linas Stonys wrote:
Is there another way to write user_defined whatsits directly without effecting \lastskip? My goal is to mark text in DVI mode with user_defined whatsits and on the shipout turn them to postscript \special's for accessible pdf
You can set an attribute on the previous node, then add the node itself in pre_output_filter: \directlua{% user_nodes = {} % Better to use luatexbase.new_attribute and luatexbase.add_to_callback attribute_number = 1234 % "pre_shipout_filter" is better if you're using LaTeX or OpTeX callback.register("pre_output_filter", function(head) % Better if this recurses through any nested lists local n = head while n do local attr attr, n = node.find_attribute(n.next, attribute_number) if not n then break end head, n = node.insert_after(head, n, user_nodes[attr]) end return head end) } aa \vskip11.1pt \showthe\lastskip \directlua{% % I'm using a rule to make the effect obvious local x = node.new("rule") x.width = 655360 x.height = 655360 x.depth = 0 table.insert(user_nodes, x) node.set_attribute( tex.nest[tex.nest.ptr].tail, attribute_number, \luaescapestring{#}user_nodes ) }% \showthe\lastskip bb \bye It's a little risky to mess with tex.nest.tail, but just setting an attribute should be mostly safe. Thanks, -- Max
Thanks Max, I'm thinking the same to add attribute and property with corresponding tags and then add whatsits on the 255 box shipout. I just need to think about discardable items. If one wants to mark up tex sources for xml or tagged pdf a common issue how to safely mark start and end of semantic text without effecting output. For example if there would be few primitives which could add an attribute or/and properties to next (yet to be created) non discardable item like \luaAddFeaturesNodeNext {{attr=1, properties={"<section>}}} \section{foo} \luaAddFeaturesNodePrev{{attr=1, properties={"</section>}}} It could save a lot of headache. Of course this is not an easy task because of page breaks.
You can set an attribute on the previous node, then add the node itself in pre_output_filter:
\directlua{% user_nodes = {} % Better to use luatexbase.new_attribute and luatexbase.add_to_callback attribute_number = 1234 % "pre_shipout_filter" is better if you're using LaTeX or OpTeX callback.register("pre_output_filter", function(head) % Better if this recurses through any nested lists local n = head while n do local attr attr, n = node.find_attribute(n.next, attribute_number) if not n then break end head, n = node.insert_after(head, n, user_nodes[attr]) end return head end) }
aa \vskip11.1pt \showthe\lastskip \directlua{% % I'm using a rule to make the effect obvious local x = node.new("rule") x.width = 655360 x.height = 655360 x.depth = 0 table.insert(user_nodes, x) node.set_attribute( tex.nest[tex.nest.ptr].tail, attribute_number, \luaescapestring{#}user_nodes ) }% \showthe\lastskip bb \bye
It's a little risky to mess with tex.nest.tail, but just setting an attribute should be mostly safe.
Thanks, -- Max
On 5/30/2024 9:39 AM, Linas Stonys wrote:
Thanks Max, I'm thinking the same to add attribute and property with corresponding tags and then add whatsits on the 255 box shipout. I just need to think about discardable items. If one wants to mark up tex sources for xml or tagged pdf a common issue how to safely mark start and end of semantic text without effecting output. For example if there would be few primitives which could add an attribute or/and properties to next (yet to be created) non discardable item like \luaAddFeaturesNodeNext {{attr=1, properties={"<section>}}} \section{foo} \luaAddFeaturesNodePrev{{attr=1, properties={"</section>}}} It could save a lot of headache.
and also introduce new ones: (1) it's not tex primitive syntax, (2) you'd have to disable it anytime you have some nested boxing going on (a bit like with \everyhbox etc)
Of course this is not an easy task because of page breaks.
indeed, but i assume you know your macros and this never generic Hans ----------------------------------------------------------------- Hans Hagen | PRAGMA ADE Ridderstraat 27 | 8061 GH Hasselt | The Netherlands tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl -----------------------------------------------------------------
Hi Linas, On Thu, 2024-05-30 at 10:39 +0300, Linas Stonys wrote:
For example if there would be few primitives which could add an attribute or/and properties to next (yet to be created) non discardable item like \luaAddFeaturesNodeNext {{attr=1, properties={"<section>}}} \section{foo} \luaAddFeaturesNodePrev{{attr=1, properties={"</section>}}}
The primitive \attribute is pretty close. You just need a little bit of Lua to make it behave exactly like you want: \attributedef\myattribute=1234 % or use \newattribute \newcount\mycount \def\addattribute#1{% \advance\mycount by 1 \global\myattribute=\mycount \global\expandafter\def\csname myattribute\the\mycount\endcsname{#1}% } \catcode`\~=12 \directlua{% attribute_number = token.create("myattribute").index local function recurse(head) for n in node.traverse(head) do if n.list then recurse(n.list) end local attr = node.get_attribute(n, attribute_number) local value if attr and n.id ~= node.id("glue") and n.id ~= node.id("local_par") then value = token.get_macro("myattribute" .. attr) token.set_macro("myattribute" .. attr, nil, "global") end if value and value ~= "" then local colour = node.new("whatsit", "pdf_literal") node.unset_attribute(colour, attribute_number) colour.mode = 2 colour.data = value node.insert_before(head, n, colour) end end return head end callback.register("pre_output_filter", recurse) } \addattribute{1 0 0 rg} abc \addattribute{0 1 0 rg} def \addattribute{0 0 1 rg} ghi \bye -- Max
With attributes it is difficult to know when marked contend is really finished because when attribute removed (set to -"7FFFFFFF) it just stops adding new attributes. If latest written node with some current attribute would get some meaningful value that this is a final node with that attribute that would be perfect. For example \setbox0=\hbox {very long} \attribute2=5 Section \unhbox0 title \attribute2=-"7FFFFFFF And if I say that everything with attributes (2=5) is semantic section in this document than I'll get two "sections" in this case because when I'll be scanning nodes I will not know that this box without attributes is part of the section and I need to seek for other node without attribute which should mean ending. On 5/30/2024 11:25 AM, Max Chernoff wrote:
Hi Linas,
On Thu, 2024-05-30 at 10:39 +0300, Linas Stonys wrote:
For example if there would be few primitives which could add an attribute or/and properties to next (yet to be created) non discardable item like \luaAddFeaturesNodeNext {{attr=1, properties={"<section>}}} \section{foo} \luaAddFeaturesNodePrev{{attr=1, properties={"</section>}}} The primitive \attribute is pretty close. You just need a little bit of Lua to make it behave exactly like you want:
\attributedef\myattribute=1234 % or use \newattribute \newcount\mycount \def\addattribute#1{% \advance\mycount by 1 \global\myattribute=\mycount \global\expandafter\def\csname myattribute\the\mycount\endcsname{#1}% }
\catcode`\~=12 \directlua{% attribute_number = token.create("myattribute").index local function recurse(head) for n in node.traverse(head) do if n.list then recurse(n.list) end
local attr = node.get_attribute(n, attribute_number) local value if attr and n.id ~= node.id("glue") and n.id ~= node.id("local_par") then value = token.get_macro("myattribute" .. attr) token.set_macro("myattribute" .. attr, nil, "global") end
if value and value ~= "" then local colour = node.new("whatsit", "pdf_literal") node.unset_attribute(colour, attribute_number) colour.mode = 2 colour.data = value node.insert_before(head, n, colour) end end return head end callback.register("pre_output_filter", recurse) }
\addattribute{1 0 0 rg} abc \addattribute{0 1 0 rg} def \addattribute{0 0 1 rg} ghi
\bye
-- Max
participants (4)
-
David Carlisle
-
Hans Hagen
-
Linas Stonys
-
Max Chernoff