# -*- mode: Perl -*-
# /=====================================================================\ #
# | verbatim | #
# | 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;
#======================================================================
# Note that we CAN process the verbatim.sty file and that works,
# although the xml it generates is pretty pointless
### InputDefinitions('verbatim', type => 'sty', noltxml => 1);
#======================================================================
# Thus, we set out to define the essentials, but keep as close
# to verbatim's internals as we can
# Since LaTeX.pool has already defined {verbatim} as an environment,
# (so that \begin{verbatim} takes precedence over \verbatim!)
# we have to be more forceful so that \verbatim & \endverbatim
# are even seen!
$STATE->assignMeaning(T_CS('\begin{verbatim}'), undef);
$STATE->assignMeaning(T_CS('\begin{verbatim*}'), undef);
$STATE->assignMeaning(T_CS('\end{verbatim}'), undef);
$STATE->assignMeaning(T_CS('\end{verbatim*}'), undef);
DefRegister('\every@verbatim' => Tokens());
DefRegister('\verbatim@line' => Tokens());
#======================================================================
# Mostly simplified versions of what's in verbatim....
DefMacro('\verbatim@startline', '\verbatim@line{}');
DefMacro('\verbatim@addtoline{}', '\verbatim@line\expandafter{\the\verbatim@line#1}');
DefMacro('\verbatim@processline', '\the\verbatim@line\par');
DefMacro('\verbatim@font', '\normalfont\ttfamily\hyphenchar\font\m@ne\@noligs');
DefMacro('\@verbatim',
'\the\every@verbatim'
. '\obeylines'
. '\let\do\@makeother \dospecials'
. '\verbatim@font');
DefConstructor('\lx@verbatim@',
"<ltx:verbatim font='#font'>",
beforeDigest => sub { Let('\par', T_CR); },
beforeConstruct => sub { $_[0]->maybeCloseElement('ltx:p'); });
# We HAVE to get this guy in, to close the <ltx:verbatim>"
DefConstructor('\lx@end@verbatim@{}',
"</ltx:verbatim>");
DefMacroI('\verbatim', undef,
'\begingroup\@verbatim\frenchspacing\@vobeyspaces\verbatim@start');
DefMacroI('\verbatim*', undef,
'\begingroup\@verbatim\verbatim@start');
DefMacroI('\endverbatim', undef, '\lx@end@verbatim@\endgroup');
DefMacroI('\endverbatim*', undef, '\lx@end@verbatim@\endgroup');
DefMacroI('\comment', undef,
'\let\do\@makeother\dospecials\catcode`\^^M\active'
. '\let\verbatim@startline\relax'
. '\let\verbatim@addtoline\@gobble'
. '\let\verbatim@processline\relax'
. '\verbatim@');
DefMacroI('\endcomment', undef, '');
DefMacro('\verbatim@start', '\lx@verbatim@\verbatim@');
#======================================================================
# Here's the interesting bit.
# Why do things the hard way, when we can pull lines out of the Mouth
# and match them as text ?
# Well, we have to dance a bit...
# NOTE: the part AFTER the \end{whatever}, should be lost (and message about it!)
DefMacro('\verbatim@', sub {
my ($gullet) = @_;
my $env = LookupValue('current_environment');
# Note: This should allow a regexp, since there can be spaces between \end and { !!!
my @lines = ();
while (defined(my $line = $gullet->readRawLine)) {
if ($line =~ /^(.*)\\end\s*\{\Q$env\E\}(.*)$/) {
push(@lines, $1);
Info('unexpected', 'stuff', $gullet, "Characters dropped after '\\end{$env}'") if $2;
last; }
else {
push(@lines, $line); } }
pop(@lines) if $lines[-1] eq '';
my @tokens = ();
foreach my $line (@lines) {
push(@tokens,
T_CS('\verbatim@startline'),
Invocation(T_CS('\verbatim@addtoline'), Tokens(ExplodeText($line))),
T_CS('\verbatim@processline')); }
(@tokens, Invocation(T_CS('\end'), $env)); });
#======================================================================
# Read verbatim material from file.
DefMacro('\verbatiminput {}', sub {
my ($gullet, $file) = @_;
my $path = FindFile($file);
$gullet->readingFromMouth(LaTeXML::Core::Mouth->create(ToString($path)), sub {
my ($igullet) = @_;
my @tokens;
while (defined(my $line = $igullet->readRawLine)) {
push(@tokens,
T_CS('\verbatim@startline'),
Invocation(T_CS('\verbatim@addtoline'), Tokens(ExplodeText($line))),
T_CS('\verbatim@processline')); }
(T_CS('\begingroup'), T_CS('\@verbatim'), T_CS('\frenchspacing'), T_CS('\@vobeyspaces'),
T_CS('\lx@verbatim@'), @tokens, T_CS('\lx@end@verbatim@'), T_CS('\endgroup')); }); });
#======================================================================
# Getting verbatim text into arguments
DefPrimitive('\newverbtext DefToken', sub {
my ($stomach, $cs) = @_;
my $gullet = $stomach->getGullet;
my ($init, $body);
StartSemiverbatim();
AssignCatcode('\\', CC_OTHER);
AssignCatcode('{', CC_OTHER);
AssignCatcode('}', CC_OTHER);
$init = $gullet->readToken;
$init = $gullet->readToken if ToString($init) eq '*'; # Should I bother handling \verb* ?
if (!$init) { # typically read too far, got \verb and the content is somewhere else..?
Error('expected', 'delimiter', $stomach,
"Verbatim argument lost", "Bindings for preceding code is probably broken");
EndSemiverbatim();
return (); }
$body = $gullet->readUntil($init);
EndSemiverbatim();
DefMacroI($cs, undef, $body);
return; });
#**********************************************************************
1;