# -*- mode: Perl -*-
# /=====================================================================\ #
# | ntheorem | #
# | Implementation for LaTeXML | #
# |=====================================================================| #
# | Part of LaTeXML: | #
# | Public domain software, produced as part of work done by the | #
# | United States Government & not subject to copyright in the US. | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov> #_# | #
# | http://dlmf.nist.gov/LaTeXML/ (o o) | #
# \=========================================================ooo==U==ooo=/ #
package LaTeXML::Package::Pool;
use strict;
use warnings;
use LaTeXML::Package;
#**********************************************************************
# Basically, this package is similar to amsthm.sty (or theorem.sty)
# with two main enhancements:
# endmarks
# list of theorem (which should actually be covered in some postprocessor?)
RequirePackage('amsthm');
RequirePackage('ifthen');
# but re-redefine from amsthm from LaTeX; use save note font as head font
DefRegister('\thm@notefont' => Tokens(T_CS('\the'), T_CS('\thm@headfont')));
# options....
DefConditional('\if@thref', undef);
DefConditional('\ifthm@inframe', undef);
DefConditional('\ifthm@tempif', undef);
# thmmarks, leqno, fleqn, thref
# standard, noconfig, amsthm,
# framed (needs framed.sty)
#======================================================================
foreach my $option (qw(leqno fleqn
amsmath amsthm hyperref)) {
DeclareOption($option, undef); }
DeclareOption('standard', sub { AssignValue('thm@usestd' => 1); }); # ?
DeclareOption('noconfig', sub { }); # ?
DeclareOption('framed', sub { }); # ? [and needs framed.sty to be loaded]
DeclareOption('thmmarks', sub { }); # ?
DeclareOption('thref', sub {
# Redefine \label to take 2nd optional argument, being the type of thing.
# [seems out-of-place here, but...]
# [Nominally would require support from aux file, but we'll have to see...]
Let('\orig@label', '\label');
# Perhaps this type could be attached somehow?
# [too bad there's no way to record the type of objects...(too verbose)]
DefMacro('\label Semiverbatim []', '\orig@label{#1}');
# \thref{} should also output the type from the above.
# We'll use latexml's show attribute to mimic the effect
DefConstructor('\thref OptionalMatch:* Semiverbatim',
"<ltx:ref labelref='#label' show='typerefnum' _force_font='true'/>",
properties => sub { (label => CleanLabel($_[2])); });
});
ProcessOptions();
#, \InTheoType should be set within theorem environment to the theorem
# \<type>Keyword
# \<type>Symbol
# , \Oldeqnnum, \OrganizeTheoremSymbol, \PotEndMark,
# \RestoreTags,
# \SetEndMark, \SetOnlyEndMark, \SetTagPlusEndMark, \TagsPlusEndmarks,
# \endalign, \endalignat, \endflalign, \endgather, \endmathdisplay, \endxalignat, \endxxalignat,
# \getKeywordOf,
# \mysavskip,
# \newframedtheorem, \newshadedtheorem,
# \FrameCommand
# \proofSymbol,
#, \renewtheoremstyle,
# \shadecolor,
# \theoremframecommand, \theoremkeyword,
# Note:
# * the namespace of \theoremstyle{<theoremstyle>}, \newtheoremstyle{name}
# is distinct from the namespace of newtheorem{<theoremclass>} ,\begin{<theoremclass>}
# theoremstyle{nmae}
# should set a recorded (sub?)set of params
# newtheoremstyle{name}<params...>
# should associate ALL (?) params with the named style?
# newtheorem{name}
# should record all(?) current params for that name
# \begin{name} should merge current values with ones recorded for name
DefRegister('\theoremindent' => Dimension('0em'));
DefRegister('\theoremrightindent' => Dimension('0em'));
DefRegister('\theorempreskipamount' => Dimension('0em'));
DefRegister('\theorempostskipamount' => Dimension('0em'));
DefRegister('\theoremframepreskipamount' => Dimension('0em'));
DefRegister('\theoremframepostskipamount' => Dimension('0em'));
DefRegister('\theoreminframepreskipamount' => Dimension('0em'));
DefRegister('\theoreminframepostskipamount' => Dimension('0em'));
DefMacro('\theorempreskip{}', '');
DefMacro('\theorempostskip{}', '');
DefMacro('\theoremframepreskip{}', '');
DefMacro('\theoremframepostskip{}', '');
DefMacro('\theoreminframepreskip{}', '');
DefMacro('\theoreminframepostskip{}', '');
DefMacro('\None', 'None');
DefMacro('\NoneSymbol', 'None');
DefMacro('\NoneKeyword', 'None');
DefRegister('\shadecolor' => Tokens());
# Include a few other theorem paramters in definitions
setSavableTheoremParameters(qw(
\thm@headfont \thm@bodyfont \thm@headpunct
\thm@styling \thm@headstyling thm@swap
\thm@numbering \thm@prework \thm@postwork \thm@symbol));
DefMacro('\theoremheaderfont{}', sub {
AssignRegister('\thm@headfont' => $_[1]); });
DefMacro('\theoremseparator{}', sub {
AssignRegister('\thm@headpunct' => $_[1]); });
DefMacro('\theoremsymbol{}', sub {
AssignRegister('\thm@symbol' => $_[1]); });
# ???
DefMacro('\theoremprework{}', sub {
AssignRegister('\thm@prework' => $_[1]); });
DefMacro('\theorempostwork{}', sub {
AssignRegister('\thm@postwork' => $_[1]); });
DefMacro('\theoremnumbering{}', sub {
AssignRegister('\thm@numbering' => T_CS('\\' . ToString($_[1]))); });
# This should turn on the same parameters as the env,
# much like \theoremstyle{style} does, givcen a theoremstyle
DefPrimitive('\theoremclass{}', sub {
return; });
#======================================================================
# ???
###DefMacro('\TheoremSymbol','');
# need some styling here to put at right...
DefMacro('\TheoremSymbol', '\@qedbox{\the\thm@symbol}');
DefConstructor('\@qedbox{}', "<ltx:text class='ltx_align_floatright'>#1</ltx:text>");
RawTeX('\newif\ifsetendmark\setendmarktrue');
DefMacro('\NoEndMark', '\global\setendmarkfalse');
DefMacroI('\thm@doendmark', undef, '\ifsetendmark\TheoremSymbol\fi');
DefRegister('\qedsymbol' => Tokens());
DefMacro('\qed', '\@qedbox{\the\qedsymbol}');
#======================================================================
Let('\orig@newtheorem', '\newtheorem');
# This defines BOTH thm & thm* envs, but note that the *'d form of theorem uses same counter!
DefMacro('\newtheorem OptionalMatch:* {}[]{}[]',
'\orig@newtheorem#1{#2}[#3]{#4}[#5]'
. '\ifx.#3.\orig@newtheorem#1{#2*}[#2]{#4}[#5]'
. '\else\orig@newtheorem#1{#2*}[#3]{#4}[#5]\fi'
);
DefMacro('\Theoremname', '\lx@thistheorem');
Let('\renewtheorem', '\newtheorem');
#======================================================================
# do something about recording & adding frame
# This needs to tie into framed.sty!!!!
# Really should execute \theoremframecommand in isolation,
# then copy the relevant attributes (framing, spacing, color, ...) to the theorem!
### NEEDS TO integrate with framed.sty better
### AND in the meantime, this needs a better API
DefConstructorI('\lx@addframing', undef, sub {
my ($doc, %props) = @_;
my $node = $doc->getElement;
$doc->setAttribute($node, framed => 'rectangle');
my $css = $node->getAttribute('cssstyle');
my $pad = 'padding:' . $props{margin} . 'pt;';
$doc->setAttribute($node, cssstyle => ($css ? $css . ';' . $pad : $pad)); },
properties => sub { (framecolor => Black,
margin => LookupRegister('\FrameSep')->ptValue); });
# Since \theoremframecommand can be defined to be pretty much anything,
# we don't have a good handle on what colors, etc, it may use.
# Here we try something pretty bizarre:
# We execute the theoremframecommand on some dummy text, capture the result,
# and copy the relevent attributes to the theorem.
DefMacroI('\lx@snapshot@framing', undef, '\lx@@snapshot@framing{\theoremframecommand{foo}}');
DefConstructor('\lx@@snapshot@framing{}', sub {
my ($document, $framebox) = @_;
my $theorem = $document->getElement;
my $capture = $document->openElement('_Capture_');
my ($frame, @rest) = $document->absorb($framebox);
$document->closeElement('_Capture_');
if (my $c = join(' ', grep { $_ } $theorem->getAttribute('class'), $frame->getAttribute('class'))) {
$document->setAttribute($theorem, class => $c); }
if (my $c = join(';', grep { $_ } $theorem->getAttribute('cssstyle'),
$frame->getAttribute('cssstyle'))) {
$document->setAttribute($theorem, cssstyle => $c); }
if (my $b = $frame->getAttribute('backgroundcolor')
|| $document->getNodeFont($frame)->getBackground) {
$document->setAttribute($theorem, backgroundcolor => $b); }
foreach my $attr (qw(framed framecolor)) {
if (my $v = $frame->getAttribute($attr)) {
$document->setAttribute($theorem, $attr => $v); } }
$document->removeNode($capture);
},
reversion => '');
DefMacro('\newframedtheorem{}[]{}[]',
'\begingroup'
. '\thm@styling{\lx@addframing}'
. '\newtheorem{#1}[#2]{#3}[#4]'
. '\endgroup');
DefMacro('\newshadedtheorem{}[]{}[]',
'\begingroup'
. '\ifx\theoremframecommand\relax'
. '\def\theoremframecommand{\colorbox{shadecolor}}\fi'
. '\thm@styling{\lx@snapshot@framing}'
. '\newtheorem{#1}[#2]{#3}[#4]'
. '\endgroup');
#======================================================================
DefPrimitive('\lx@ntheorem@newtheoremstyle{}{}{}{}{}{}', sub {
my ($stomach, $name, $headfont, $bodyfont, $headstyle, $swap, $numbering) = @_;
$name = ToString($name);
saveTheoremStyle($name,
'\thm@bodyfont' => $bodyfont,
'\thm@headfont' => $headfont,
'\thm@headstyling' => $headstyle,
'thm@swap' => ToString($swap) eq 'S',
'\thm@numbering' => $numbering,
'\thm@symbol' => LookupRegister('\thm@symbol'),
);
DefMacroI(T_CS('\th@' . $name), undef, sub { useTheoremStyle($name); });
return; });
RawTeX(<<'EoTeX');
\lx@ntheorem@newtheoremstyle{plain}{\bfseries}{\itshape}{\lx@makerunin}{N}{\arabic}
\lx@ntheorem@newtheoremstyle{break}{\bfseries}{\slshape}{}{N}{\arabic}
\lx@ntheorem@newtheoremstyle{change}{\bfseries}{\slshape}{\lx@makerunin}{S}{\arabic}
\lx@ntheorem@newtheoremstyle{margin}{\bfseries}{\slshape}{\lx@makerunin\lx@makeoutdent}{S}{\arabic}
\lx@ntheorem@newtheoremstyle{marginbreak}{\bfseries}{\slshape}{\lx@makeoutdent}{S}{\arabic}
\lx@ntheorem@newtheoremstyle{changebreak}{\bfseries}{\slshape}{}{S}{\arabic}
\lx@ntheorem@newtheoremstyle{nonumberplain}{\bfseries}{\itshape}{\lx@makerunin}{N}{}
\lx@ntheorem@newtheoremstyle{nonumberbreak}{\bfseries}{\slshape}{}{N}{}
\lx@ntheorem@newtheoremstyle{empty}{}{}{\lx@makerunin}{N}{}
\lx@ntheorem@newtheoremstyle{emptybreak}{}{}{}{N}{}
EoTeX
# Load the other styles from the ntheorem's standard defintions
InputDefinitions('ntheorem.std') if LookupValue('thm@usestd');
# Start off as plain style.
useTheoremStyle('plain');
#======================================================================
# Lists of Theorems.
DefMacro('\addtheoremline OptionalMatch:* {}{}', '');
DefMacro('\addtotheoremfile[]{}', '');
DefMacro('\theoremlisttype{}', '');
DefMacro('\newtheoremlisttype{}{}{}{}', '');
DefMacro('\renewtheoremlisttype{}{}{}{}', '');
# This is Wrong!
# It should list only specific subsets
# TOC needs to be generalized to allow more flexiblity, maybe XPath?
# Should accept comma separated list of theorem classes, including 'all'
# (theorem class being the 1st arg to \newtheorem)
DefConstructor('\listtheorems{}',
"<ltx:TOC lists='#lists' name='#name'/>",
properties => sub {
my @types = split(/\s*,\s*/, ToString($_[1]));
(lists => join(' ', map { ($_ eq 'all' ? 'thm' : 'theorem:' . $_) } @types));
});
# \theoremlistdo,
# Presumably a user never needs to call these?
# [they implement the predefined theorem list types]
DefMacro('\theoremlistall', '');
DefMacro('\theoremlistallname', '');
DefMacro('\theoremlistalloptional', '');
DefMacro('\theoremlistalloptname', '');
#======================================================================
# Add capability for greek numbering
DefMacro('\greek{}', sub {
ExplodeText(radix_greek(CounterValue(ToString(Expand($_[1])))->valueOf)); });
DefMacro('\Greek{}', sub {
ExplodeText(radix_Greek(CounterValue(ToString(Expand($_[1])))->valueOf)); });
#======================================================================
1;