1# -*- mode: Perl -*- 2# /=====================================================================\ # 3# | numprint | # 4# | Implementation for LaTeXML | # 5# |=====================================================================| # 6# | Part of LaTeXML: | # 7# | Public domain software, produced as part of work done by the | # 8# | United States Government & not subject to copyright in the US. | # 9# |---------------------------------------------------------------------| # 10# | Bruce Miller <bruce.miller@nist.gov> #_# | # 11# | http://dlmf.nist.gov/LaTeXML/ (o o) | # 12# \=========================================================ooo==U==ooo=/ # 13package LaTeXML::Package::Pool; 14use strict; 15use warnings; 16use LaTeXML::Package; 17 18#====================================================================== 19# What an interesting package! A bit complex to rewrite in Perl 20# So, we'd prefer to just process the TeX source for it. 21# Basically, we read in the TeX distribution's numprint 22InputDefinitions('numprint', type => 'sty', noltxml => 1); 23# That done, however, there are a few issues. 24# * numprint uses a mix of text & math modes to get the desired appearance. 25# Here, we'd like to try to be slightly semantic, so rewrap things. 26# * numprint uses a bit too much knowledge of latex's tabular 27# and latex's tabular doesn't quite match the internals of latexml's! 28#====================================================================== 29 30#====================================================================== 31# (Pseudo) Semantics 32#====================================================================== 33# When printing in text mode, wrap the number in something that _says_ that it's a number! 34# And, avoid putting the various symbolic bits in Math mode (if we can) 35# In Math mode, wrap it in an XMDual, and try to avoid parsing too much 'nonsense'. 36Let('\ltx@orig@numprint', '\numprint'); 37DefMacro('\numprint[]{}', 38 '\ifx.#1.\ltx@numprint@{#2}\else\ltx@numprint@@{#1}{#2}\fi'); 39DefMacro('\ltx@numprint@{}', 40 '\ifmmode\ltx@math@numprint@{#1}\else\ltx@text@numprint@{#1}\fi'); 41DefMacro('\ltx@numprint@@{}{}', 42 '\ifmmode\ltx@math@numprint@@{#1}{#2}\else\ltx@text@numprint@@{#1}{#2}\fi'); 43 44# Text Mode 45DefMacro('\ltx@text@numprint@{}', '\ltx@text@number{\ltx@orig@numprint{#1}}'); 46DefMacro('\ltx@text@numprint@@{}{}', '\ltx@text@number{\ltx@orig@numprint[#1]{#2}}'); 47 48DefConstructor('\ltx@text@number{}', 49 "<ltx:text class='ltx_number' _noautoclose='1'>#1</ltx:text>"); 50 51# Math mode 52DefMacro('\ltx@math@numprint@{}', 53 '\ltx@math@@numprint@{#1}{\ltx@orig@numprint{#1}}'); 54DefMacro('\ltx@math@numprint@@{}{}', 55 '\ltx@math@@numprint@@{#1}{#2}{\ltx@mark@units{#1}}{\ltx@orig@numprint[#1]{#2}}'); 56 57# Note that this could be even more "semantic" if we'd peel off any sign... 58DefConstructor('\ltx@math@@numprint@{}{}', 59 "<ltx:XMDual>" 60 . "<ltx:XMTok meaning='#value' role='NUMBER'>#value</ltx:XMTok>" 61 . "<ltx:XMWrap>#2</ltx:XMWrap>" 62 . "</ltx:XMDual>", 63 reversion => '\numprint{#1}', 64 properties => sub { (value => ToString($_[1])); }); 65DefConstructor('\ltx@math@@numprint@@{}{}{}{}', 66 "<ltx:XMDual>" 67 . "<ltx:XMApp>" 68 . "<ltx:XMTok meaning='times' role='MULOP'>\x{2062}</ltx:XMTok>" 69 . "<ltx:XMTok meaning='#value' role='NUMBER'>#value</ltx:XMTok>" 70 . "<ltx:XMWrap>#3</ltx:XMWrap>" 71 . "</ltx:XMApp>" 72 . "<ltx:XMWrap>#4</ltx:XMWrap>" 73 . "</ltx:XMDual>", 74 reversion => '\numprint[#1]{#2}', 75 properties => sub { (value => ToString($_[2])); }); 76 77# When printing the numbers in text, use (unicode) text symbols where possible 78DefMacroI('\nprt@sign@+', undef, '\ifmmode+\else\ltx@text@plus\fi'); 79DefMacroI('\nprt@sign@-', undef, '\ifmmode-\else\ltx@text@minus\fi'); 80DefMacroI('\nprt@sign@+-', undef, '\ifmmode\pm\else\ltx@text@plusminus\fi'); 81DefPrimitiveI('\ltx@text@plus', undef, '+'); 82DefPrimitiveI('\ltx@text@minus', undef, '-'); 83DefPrimitiveI('\ltx@text@plusminus', undef, UTF(0xB1)); 84 85# When defining the product sign, use the text form, if possible... 86DefMacro('\npproductsign{}', 87 '\ifmmode #1' 88 . '\else\@ifundefined{ltx@text@prod\string #1}' 89 . '{\def\nprt@prod{\ensuremath{{}#1{}}}}' 90 . '{\def\nprt@prod{\csname ltx@text@prod\string #1\endcsname}}' 91 . '\fi'); 92DefPrimitiveI('\ltx@text@prod\times', undef, UTF(0xD7)); 93DefPrimitiveI('\ltx@text@prod\cdot', undef, "\x{22C5}"); 94 95# Mark units, as well 96# But note that this effect is easily lost, 97# since \npunitcommand is an official "customization" point (and thus user defined)! 98DefMacro('\npunitcommand{}', '\ensuremath{\mathrm{\ltx@mark@units #1}}'); 99DefConstructor('\ltx@mark@units{}', sub { 100 my ($document, $units) = @_; 101 my @nodes = $document->filterChildren($document->filterDeletions($document->absorb($units))); 102 foreach my $node (@nodes) { 103 # Only add this class to "identifiers" ? 104 my $role; 105 if (($node->nodeType == XML_ELEMENT_NODE) 106 && (!($role = $node->getAttribute('role')) 107 || ($role eq 'ID') || ($role eq 'UNKNOWN') 108 || ($role eq 'FLOATSUPERSCRIPT'))) { # This covers things like primes(?) 109 $document->addClass($node, 'ltx_unit'); } } }, 110 reversion => '#1'); 111 112#====================================================================== 113# Tabular issues 114#====================================================================== 115# numprint is scanning for args late, the lazy TeX way, 116# but that doesn't fit the way LaTeXML want's to recognize the argument structure (too) early. 117# So, we need BOTH to define the templates n & N in a way that works with LaTeXML, 118# AND we need to tweak the scanner that looks for the end of the column 119# (since ours end differently than normal LaTeX's) 120# 121# NOTE also that current browsers do not (yet) support the char:. alignment 122# and that LaTeXML does not (yet) compute actual box dimensions. 123# Thus (at the moment) these tabulars will not be aligned on the . Sigh! 124# But maybe soon...? 125 126DefColumnType('N Optional:-1 Optional:-1 {}{}', sub { 127 my ($gullet, $nd_exp_before, $nd_exp_after, $nd_man_before, $nd_man_after) = @_; 128 $LaTeXML::BUILD_TEMPLATE->addColumn(before => Tokens(T_CS('\nprt@begin'), T_CS('\ignorespaces')), 129 after => Invocation(T_CS('\nprt@end'), 130 $nd_man_before, $nd_man_after, 131 $nd_exp_before, $nd_exp_after, 132 Tokens(), Tokens()), 133 align => 'char:' . ToString(Digest(T_CS('\nprt@decimal')))); 134 return; }); 135 136DefColumnType('n Optional:-1 Optional:-1 {}{}', sub { 137 my ($gullet, $nd_exp_before, $nd_exp_after, $nd_man_before, $nd_man_after) = @_; 138 $LaTeXML::BUILD_TEMPLATE->addColumn(before => Tokens(T_CS('\nprt@begin'), T_CS('\ignorespaces')), 139 after => Invocation(T_CS('\nprt@end'), 140 $nd_man_before, $nd_man_after, 141 $nd_exp_before, $nd_exp_after, 142 T_MATH, T_MATH), 143 align => 'char:' . ToString(Digest(T_CS('\nprt@decimal')))); 144 return; }); 145 1461; 147