@@ -229,24 +229,28 @@ DefPrimitive('\lx@clear@creators OptionalKeyVals:Frontmatter', sub {
229229# DefMacro('\lx@clear@creators OptionalKeyVals:Frontmatter', '\lx@clear@frontmatter{ltx:creator)[#1]');
230230DefMacro(' \lx@clear@creators []' , ' \lx@clear@frontmatter{ltx:creator}[#1]' );
231231
232- # trailing \\ should disappear.
233- # OR alternatively a Tag if <ltx:break/> is last element?
234- DefMacro(' \lx@ignored OptionalMatch:* [Glue]' , sub {
235- my ($gullet , $star , $dim ) = @_ ;
236- return ($gullet -> peekToken ? Invocation(T_CS(' \lx@newline' ),$star , $dim ) : ()); });
237-
238- # Digest the content for a frontmatter item, disabling certain commands
232+ # Digest the content for a frontmatter item, disabling or masking certain commands
239233# Note that we shouldn't be digesting any frontmatter until within document, so inPreamble unnec.
240- # NOTE: shouldn't actually ignore \\, but trailing onces should be stripped!!!
234+ # See cleanTrailingBreak for cleanup of misused \\.
241235sub digestFrontmatterItem {
242236 my ($stomach , $item ) = @_ ;
243237 $stomach -> bgroup;
244- Let(' \\\\ ' , ' \lx@ignored' );
245238 Let(' \label' ,' \lx@set@contact@label' );
246239 my $digested = DigestText($item );
247240 $stomach -> egroup;
248241 return $digested ; }
249242
243+ sub cleanTrailingBreak {
244+ my ($document , $node ) = @_ ;
245+ while (my $last = $node -> lastChild ) {
246+ my $tag = $document -> getNodeQName($last );
247+ last unless (($tag eq ' #PCDATA' ) && ($last -> toString =~ / ^\s *$ /s ))
248+ || ($tag eq ' ltx:break' );
249+ $node -> removeChild($last ); }
250+ return ; }
251+ Tag(' ltx:personname' , afterClose => \&cleanTrailingBreak);
252+ Tag(' ltx:contact' , afterClose => \&cleanTrailingBreak);
253+
250254# Add a new frontmatter item that will be enclosed in <$tag %attr>...</$tag>
251255# The content is the result of digesting $tokens.
252256# \@add@frontmatter[keys]{tag}[attributes]{content}
@@ -317,6 +321,7 @@ DefPrimitive('\lx@add@contact OptionalKeyVals:Frontmatter {}', sub {
317321 my ($stomach , $kv , $content ) = @_ ;
318322 saveFrontMatter($stomach , ' ltx:contact' , $kv , Invocation(T_CS(' \lx@add@contact@now' ), $kv , $content ));
319323 return ; });
324+
320325DefPrimitive(' \lx@add@contact@now OptionalKeyVals:Frontmatter {}' , sub {
321326# #DefPrimitive('\lx@add@contact OptionalKeyVals:Frontmatter {}', sub {
322327 my ($stomach , $kv , $content ) = @_ ;
@@ -330,7 +335,7 @@ DefPrimitive('\lx@add@contact@now OptionalKeyVals:Frontmatter {}', sub {
330335 AssignMapping(' num_contacts' , $role => $n );
331336 if (!$options {name } || ! scalar ($options {name }-> unlist)) {
332337 my $cs = T_CS(' \lx@contact@' . $role . ' @name' );
333- $options {name } = (LookupDefinition( $cs ) ? $cs : Tokens() ); }
338+ $options {name } = DigestText( $cs ) if LookupDefinition( $cs ); }
334339 my @allcreators = @{ $$frontmatter {' ltx:creator' } || [] };
335340 my @creators = grep { ($$_ [1]{role } || ' ' ) ne ' pending' ; } @allcreators ;
336341 my $ncreators = scalar (@creators );
@@ -343,16 +348,19 @@ DefPrimitive('\lx@add@contact@now OptionalKeyVals:Frontmatter {}', sub {
343348 Debug(" ADD contact: [" .
344349 join (' ,' , map { $_ . ' =' . ToString($options {$_ }); } sort keys %options )
345350 . " ] " . ToString($content ) . " (with $ncreators available)" );
351+ # Tentatively create new entry in frontmatter, in case digestion changes marks!
352+ my $entry = [' ltx:creator' , { role => ' pending' , _marks => $marks }, ' place_keeper' ];
353+ push (@{ $$frontmatter {' ltx:creator' } }, $entry );
354+ my $xcontent = digestFrontmatterItem($stomach , $content );
355+ $marks = $$entry [1]{_marks }; # Reset if changed!
356+ my $datum = LaTeXML::Core::Whatsit-> new(LookupDefinition(T_CS(' \lx@make@contact@@' )),
357+ [$role ,$marks ,$options {name },$xcontent ]);
346358 if ($marks || !$ncreators ) { # deferred until we can compare marks
347- my $entry = [' ltx:creator' , { role => ' pending' , _marks => $marks }, ' place_keeper' ];
348- push (@{ $$frontmatter {' ltx:creator' } }, $entry );
349- # NOW, with that context saved, we can digest, THEN store the contact's content.
350359 Debug(" ... deferring to mark=$marks " );
351- # # $$entry[2] = DigestText(Invocation(T_CS('\lx@make@contact@'),
352- $$entry [2] = digestFrontmatterItem($stomach , Invocation(T_CS(' \lx@make@contact@' ),
353- # ### T_OTHER($role), T_OTHER($marks), $options{name} || Tokens(), $content)); }
354- T_OTHER($role ), T_OTHER($marks ), $options {name }, $content )); }
360+ $$entry [2] = $datum ; }
355361 else {
362+ $$frontmatter {' ltx:creator' } # Remove unneeded entry.
363+ = [grep { $_ ne $entry ; } @{ $$frontmatter {' ltx:creator' } }];
356364 my ($nprev , $newonly ) = (1, 0);
357365 my $attach = ToString($options {attach });
358366 if ((!defined $attach ) || ($attach eq ' ' )) { }
@@ -362,42 +370,57 @@ DefPrimitive('\lx@add@contact@now OptionalKeyVals:Frontmatter {}', sub {
362370 elsif ($attach eq ' new' ) { $nprev = $ncreators ; $newonly = 1; }
363371 else { Info(' unexpected' , ' contact' , $stomach , " Contact attach '$attach ' unrecognized" ); }
364372 Debug(" ...adding to $nprev previous" . ($newonly ? ' new' : ' ' ));
365- # # my $datum = DigestText(Invocation(T_CS('\lx@make@contact@'),
366- my $datum = digestFrontmatterItem($stomach , Invocation(T_CS(' \lx@make@contact@' ),
367- # ### T_OTHER($role), T_OTHER($marks), $options{name} || Tokens(), $content));
368- T_OTHER($role ), T_OTHER($marks ), $options {name }, $content ));
369373 while (my $creator = pop (@creators )) {
370374 push (@$creator , $datum );
371375 $$creator [1]{" _has$role " } = 1;
372376 last if (--$nprev <= 0) || ($newonly && $creators [-1][1]{" _has$role " }); } }
373377 return ; });
374378
379+ DefConstructor(' \lx@make@contact@@ Undigested Undigested {} Undigested' ,
380+ " ^<ltx:contact role='#1'_mark='#2' name='#3'>#4</ltx:contact>" );
381+
375382sub show_frontmatter_entry {
376383 my ($entry ) = @_ ;
377384 my ($tag , $attr , @content ) = @$entry ;
378385 return " [$tag {" .
379386 join (' ,' , map { $_ . ' =' . ToString($$attr {$_ }); } sort keys %$attr ) . " } "
380387 . join (' ' , map { ToString($_ ); } @content ) . " ]" ; }
381388
382- # Add comma-separated marks to the current ltx:creator by which some other ltx:contact
383- # data can be attached; expected to be embedded within the (eg) \author text.
384- # Canonical example: \inst, typically \inst is let to \lx@add@creator@mark in classes.
385- # If there are distinct kinds of marks, might want to prefix the mark
386- # with some unique text?
387- # NOTE: Could also treat \label & \ref as a mark pair?
388- DefConstructor(' \lx@add@creator@mark[]{}' , sub {
389- my ($document , $prefix , $mark ) = @_ ;
390- if (my $creator = $document -> findnode(' ancestor::ltx:creator' , $document -> getNode)) {
391- my $marks = $creator -> getAttribute(' _marks' ) || ' ' ;
392- $mark = join (' ,' , cleanFrontmatterMarks($mark , $prefix ));
393- Debug(" MARKS add: $mark " );
394- $creator -> setAttribute(_marks => ($marks ? " $marks ,$mark " : $mark )); } });
395- DefConstructor(' \lx@set@contact@label Semiverbatim' , sub {
396- my ($document , $mark ) = @_ ;
397- if (my $creator = $document -> findnode(' ancestor::ltx:contact' , $document -> getNode)) {
398- $mark = join (' ,' , cleanFrontmatterMarks($mark , ' LABEL' ));
399- Debug(" MARKS set: $mark " );
400- $creator -> setAttribute(_mark => $mark ); } });
389+ # Find the entry for the ltx:creator/ltx:contact currently being digested.
390+ sub fetchPendingCreatorEntry {
391+ my $frontmatter = LookupValue(' frontmatter' );
392+ my @allcreators = @{ $$frontmatter {' ltx:creator' } || [] };
393+ if (my $last = $allcreators [-1]) {
394+ # ## if ((($$last[1]{role} || '') eq 'pending') && (($$last[2] || '') eq 'place_keeper')) {
395+ if (($$last [2] || ' ' ) eq ' place_keeper' ) {
396+ return $last ; } }
397+ return ; }
398+
399+ # These next two are primitives executing during digestion (BEFORE XML);
400+ # they add to or replace marks to be used when building the frontmatter plan.
401+
402+ # \lx@add@creator@mark adds comma separated marks to the currently digesting creator;
403+ # Typically would \let\inst to this, and used within creator's content
404+ # to identify contacts to include.
405+ # Can provide the prefix to distinguish different sets of marks
406+ DefPrimitive(' \lx@add@creator@mark[]{}' , sub {
407+ my ($document , $prefix , $mark ) = @_ ;
408+ if (my $current = fetchPendingCreatorEntry()) {
409+ my $marks = $$current [1]{_marks };
410+ $mark = join (' ,' , cleanFrontmatterMarks($mark , $prefix ));
411+ $$current [1]{_marks } = ($marks ? " $marks ,$mark " : $mark );
412+ Debug(" MARKS add: $mark " ); } });
413+
414+ # \lx@set@contact@label sets (replaces) the _marks on the currently digesting creator
415+ # which could be a stub (role=pending) for a to-be-inserted contact.
416+ # Typically would \let\label to this so that a \ref within a creator
417+ # will get a contact with corresponding \label will be attached.
418+ DefPrimitive(' \lx@set@contact@label Semiverbatim' , sub {
419+ my ($stomach , $label ) = @_ ;
420+ if (my $current = fetchPendingCreatorEntry()) {
421+ $label = CleanLabel($label ,' LABEL' );
422+ $$current [1]{_marks } = $label ;
423+ Debug(" MARKS set: $label " ); } });
401424
402425# Append a piece of data to an existing frontmatter item that is contained in <$tag>
403426# If $label is given, look for an item which has label=>$label,
@@ -452,22 +475,11 @@ DefMacro('\lx@add@authors{}',
452475 . ' \lx@clear@frontmatter{ltx:contact}'
453476 # Note: must keep affiliations (after \\) embedded, to simplify clear@author removal
454477 . ' \lx@splitting{\lx@author@and@affil}{\and,\And}{#1}' );
455- # NOTE: Dangling <ltx:break> in affiliation???
456478DefMacro(' \lx@author@and@affil{}' , ' \lx@author@and@affil@#1\\\\ \done' );
457479DefMacro(' \lx@author@and@affil@ Until:\\\\ Until:\\ done' ,
458480 ' \ifx.#2.\lx@add@creator[role=author]{#1}'
459481 . ' \else\lx@add@creator[role=author]{#1\lx@add@contact[role=affiliation]{#2}}\fi' );
460482
461- # THIS SHOULD GO AWAY
462- DefConstructor(' \lx@contact@{}{}{}' ,
463- " ^<ltx:contact role='#1' _mark='#2'>#3</ltx:contact>" );
464-
465- DefConstructor(' \lx@make@contact@ Undigested Undigested {} {}' ,
466- " ^<ltx:contact role='#role'_mark='#mark' name='#name'>#4</ltx:contact>" ,
467- properties => sub {
468- my ($stomach , $role , $mark , $name , $content ) = @_ ;
469- (role => $role , mark => $mark , name => $name ); });
470-
471483DefMacro(' \lx@contact@affiliation@name' , " Affiliation:~" );
472484DefMacro(' \lx@contact@altaffiliation@name' , " Alternate Affiliation:~" );
473485DefMacro(' \lx@contact@address@name' , " Address:~" );
0 commit comments