summaryrefslogtreecommitdiff
path: root/macros/generic/misc/mathlig.tex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/misc/mathlig.tex
Initial commit
Diffstat (limited to 'macros/generic/misc/mathlig.tex')
-rw-r--r--macros/generic/misc/mathlig.tex131
1 files changed, 131 insertions, 0 deletions
diff --git a/macros/generic/misc/mathlig.tex b/macros/generic/misc/mathlig.tex
new file mode 100644
index 0000000000..04194b8493
--- /dev/null
+++ b/macros/generic/misc/mathlig.tex
@@ -0,0 +1,131 @@
+%
+% mathlig.tex
+%
+% (c) 2001 Jules Bean <jules@jellybean.co.uk>
+% Permission is granted to freely use, copy, and distribute
+% without restriction. Permission is also granted to distribute
+% modified versions and incorporate into your own macro packages
+% if a brief acknowledgement is given.
+%
+% Version 1.0 11 May 2001
+
+% Define 'mathmode' ligatures, as in
+%
+%\mathlig{->}{\rightarrow}
+%\mathlig{<-}{\leftarrow}
+%\mathlig{<->}{\leftrightarrow}
+%
+% Works even if they have common prefixes (takes the longest match,
+% then backtracks).
+%
+% Can be used to create ligatures even if the second
+% and subsequent characters have weird catcodes, but I don't recommend
+% it.
+
+\count255\catcode`@
+\catcode`@=11
+\chardef\mathlig@atcode\count255
+
+% Let or def an 'active' version of a token. Thanks to Donald
+% Arseneau and groups.google.com
+\def\actively#1#2{\begingroup\uccode`\~=`#2\relax\uppercase{\endgroup#1~}}
+% Eat the next token, and then pass control to mathlig@next@cmd
+\def\mathlig@gobble{\afterassignment\mathlig@next@cmd\let\mathlig@next= }
+% Used to delimit delimited arguments, and ifx tests for emptyness.
+\def\mathlig@delim{\mathlig@delim}
+% Some macros to help dealing with 'computed names' (csnames).
+% Just like def, but first parameter is evaluated as a csname
+\def\mathlig@defcs#1{\expandafter\def\csname#1\endcsname}
+% A version of \let <normal cs><computed cs>
+\def\mathlig@let@cs#1#2{\expandafter\let\expandafter#1\csname#2\endcsname}
+% Maintain a 'list' of tokens as a macro which expands to them
+\def\mathlig@appendcs#1#2{\expandafter\edef\csname#1\endcsname{\csname#1\endcsname#2}}
+
+% The main externally visible macro.
+% Defines '#1' as a 'ligature' to expand to #2
+% First uses \mathlig@checklig to make sure that all initial segments of
+% #1 as set up as ligatures.
+% Then sets the ligature #1 to expand to #2.
+\def\mathlig#1#2{\mathlig@checklig#1\mathlig@end\mathlig@defcs{mathlig@back@#1}{#2}\ignorespaces}
+
+% All the @check macros should be idempotent: they set up the definitions
+% only if it hasn't already been done.
+
+%Check #1#2 can be a ligature:
+% Check #1 is math-active.
+% If not, save the mathcode, set the macros #1
+%Now check the suffix tables with \checkrest
+\def\mathlig@checklig#1#2\mathlig@end{%
+ \expandafter\ifx\csname mathlig@forw@#1\endcsname\relax
+ \expandafter\mathchardef\csname mathlig@back@#1\endcsname=\mathcode`#1%
+ \mathcode`#1"8000\actively\def#1{\csname mathlig@look@#1\endcsname}%
+ \mathlig@dolig#1\mathlig@delim
+\fi
+\mathlig@checksuffix#1#2\mathlig@end
+}
+
+%Two-part macro.
+%Check suffix tables. If #2 is empty, no suffix!
+%Otherwise, we make sure #2 is a valid suffix for #1,
+%then recurse for #3 on #1#2
+\def\mathlig@checksuffix#1#2\mathlig@end{%
+\ifx\mathlig@delim#2\mathlig@delim\relax\else\mathlig@checksuffix@{#1}#2\mathlig@end\fi
+}
+\def\mathlig@checksuffix@#1#2#3\mathlig@end{%
+\expandafter\ifx\csname mathlig@forw@#1#2\endcsname\relax\mathlig@dosuffix{#1}{#2}\fi
+\mathlig@checksuffix{#1#2}#3\mathlig@end
+}
+
+% The do macros should not be called more than once for a given ligature.
+
+% Add #2 to the list of valid suffixes for #1
+% Then make the ligature for #1#2 one which only backtracks, for now
+\def\mathlig@dosuffix#1#2{%
+\mathlig@appendcs{mathlig@toks@#1}{#2}%
+\mathlig@dolig{#1}{#2}\mathlig@delim
+}
+
+% Setup #1#2 so that ligatures beginning #1#2 work.
+% Such ligatures will look at what's coming next (in case
+% of a longer ligature) and, failing that,
+% backtrack to just #1
+
+\def\mathlig@dolig#1#2\mathlig@delim{%
+%The look macro just \futurelets what's coming up and
+%then passes control to forw
+ \mathlig@defcs{mathlig@look@#1#2}{%
+ \mathlig@let@cs\mathlig@next{mathlig@forw@#1#2}\futurelet\mathlig@next@tok\mathlig@next}%
+%The forw macro uses chck to try all possible suffixes, passing control
+%either to one of those, or to the back macro
+ \mathlig@defcs{mathlig@forw@#1#2}{%
+ \mathlig@let@cs\mathlig@next{mathlig@back@#1#2}%
+ \mathlig@let@cs\checker{mathlig@chck@#1#2}%
+ \mathlig@let@cs\mathligtoks{mathlig@toks@#1#2}%
+ \expandafter\ifx\expandafter\mathlig@delim\mathligtoks\mathlig@delim\relax\else
+ \expandafter\checker\mathligtoks\mathlig@delim\fi
+ \mathlig@next
+ }%
+%The toks macro just stores the suffixes
+ \mathlig@defcs{mathlig@toks@#1#2}{}%
+%The chk macro goes through the suffixes one by one
+%tail recursing until it runs out, or finds one.
+ \mathlig@defcs{mathlig@chck@#1#2}##1##2\mathlig@delim{%
+ %\message{Lig so far '#1#2', checking for '##1'}%
+ \ifx\mathlig@next@tok##1%
+ \mathlig@let@cs\mathlig@next@cmd{mathlig@look@#1#2##1}\let\mathlig@next\mathlig@gobble
+ \fi
+ \ifx\mathlig@delim##2\mathlig@delim\relax\else
+ \csname mathlig@chck@#1#2\endcsname##2\mathlig@delim
+ \fi
+ }%
+%
+% The back macro, defined only if this is a ligature of at least
+% two characters, is a default fallback: go back to the previous char.
+% (If this is a ligature of only one character, the mathcode will have
+% been saved and set as the fallback elsewhere)
+ \ifx\mathlig@delim#2\mathlig@delim\else
+ \mathlig@defcs{mathlig@back@#1#2}{\csname mathlig@back@#1\endcsname #2}%
+ \fi
+}%
+
+\catcode`@\mathlig@atcode