2
2
################################################################################
3
3
# texdef -- Show definitions of TeX commands
4
# Copyright (c) 2011 Martin Scharrer <martin@scharrer-online.de>
4
# Copyright (c) 2011-2012 Martin Scharrer <martin@scharrer-online.de>
6
6
# This program is free software: you can redistribute it and/or modify
7
7
# it under the terms of the GNU General Public License as published by
103
109
my $BEGINENVSTR = '%s';
104
110
my $ENDENVSTR = '%s';
106
my $VERSION = 'Version 1.4 -- 2011/07/28';
112
my $VERSION = 'Version 1.6 -- 2012/05/02';
109
115
texdef -- Show definitions of TeX commands
110
Version 1.4 -- 2011/07/28
111
Copyright (C) 2011 Martin Scharrer <martin@scharrer-online.de>
116
Version 1.6 -- 2012/05/02
117
Copyright (C) 2011-2012 Martin Scharrer <martin@scharrer-online.de>
112
118
This program comes with ABSOLUTELY NO WARRANTY;
113
119
This is free software, and you are welcome to redistribute it under certain conditions;
119
125
Other program names are possible. See the 'tex' option. Command names do not need to start with `\`.
122
--tex <flv>, -t <flv> : Use given flavour of TeX: 'tex', 'latex', 'context'.
128
--tex <format>, -t <format> : Use given format of TeX: 'tex', 'latex', 'context'.
123
129
Variations of 'tex' and 'latex', like 'luatex', 'lualatex', 'xetex', 'xelatex' are supported.
124
130
The default is given by the used program name: 'texdef' -> 'tex', 'latexdef' -> 'latex', etc.
131
--source, -s : Try to show the original source code of the command definition (L).
125
132
--value, -v : Show value of command instead (i.e. \the\command).
133
--Environment, -E : Every command name is taken as an environment name. This will show the definition of
134
both \Macro\foo and \Macro\endfoo if \texttt{foo} is used as command name (L).
126
135
--preamble, -P : Show definition of the command inside the preamble.
127
136
--beforeclass, -B : Show definition of the command before \documentclass.
128
137
--package <pkg>, -p <pkg> : (M) Load given tex-file, package or module depending on whether '*tex', '*latex'
131
140
--class <class>, -c <class> : (LaTeX only) Load given class instead of default ('article').
132
141
The <class> can start with `[<classs options>]` and end
133
142
with `<classname>` or `{<classname>}`.
134
--environment <env>, -p <env> : (M) Show definition inside the given environment <env>.
143
--environment <env>, -e <env> : (M) Show definition inside the given environment <env>.
135
144
--othercode <code>, -o <code> : (M) Add other code into the preamble before the definition is shown.
136
145
This can be used to e.g. load PGF/TikZ libraries.
137
146
--before <code>, -b <code> : (M) Place <code> before definition is shown.
194
203
push @ENVCODE, [ $opt, $arg ];
206
## Define and process options
198
207
Getopt::Long::Configure ("bundling");
200
209
'value|v!' => \$SHOWVALUE,
210
'Environment|E!' => \$ISENVIRONMENT,
201
211
'version|V!' => \$PRINTVERSION,
202
212
'tempdir=s' => \$TMPDIR,
203
213
'find|f!' => sub { $FINDDEF = 1 },
204
214
'Find|F!' => sub { $FINDDEF = 2 },
215
'source|s!' => \$PRINTORIGDEF,
205
216
'list|l' => sub { $LISTCMD++ },
206
217
'list-def|L' => sub { $LISTCMDDEF++ },
207
218
'list-all' => sub { $LISTCMD=2 },
283
295
usage() if not @cmds;
284
297
my $cwd = getcwd();
285
$ENV{TEXINPUTS} = '.:' . $cwd . ':' . ($ENV{TEXINPUTS} || '');
300
if ($OS =~ /MSWin/) {
305
$ENV{TEXINPUTS} = '.' . $DIRSEP . $cwd . $DIRSEP . ($ENV{TEXINPUTS} || '');
288
308
$TMPDIR = tempdir( 'texdef_XXXXXX', CLEANUP => 1, TMPDIR => 1 );
290
310
chdir $TMPDIR or die "Couldn't change into temporary directory '$TMPDIR'\n";
291
my $TMPFILE = 'texdef.tex';
311
my $TMPFILE = 'texdeftmp.tex';
388
410
print '\makeatletter\expandafter\let\csname ver@kvoptions.sty\endcsname\relax\let\SetupKeyvalOptions\@undefined\let\DeclareBoolOption\@undefined\let\DeclareStringOption\@undefined';
389
411
print '\let\DeclareVoidOption\@undefined\let\ProcessKeyvalOptions\@undefined\makeatother';
413
if ($FINDDEF || $PRINTORIGDEF) {
392
414
print '{\expandafter}\expandafter\ifx\csname ' . $cmd . '\expandafter\endcsname\csname @undefined\endcsname' . "\n";
393
415
print '\AtEndOfFiles{{{\expandafter}\expandafter\ifx\csname ' . $cmd . '\expandafter\endcsname\csname @undefined\endcsname\else' . "\n";
394
416
print ' \ClearHook\AtEndOfFiles{}\relax';
528
open (my $texpipe, '-|', "$TEX '$TMPFILE' ");
550
# Removes all '{' and '}' characters which no real braces.
551
sub remove_invalid_braces {
552
$_[0] =~ s/\\[\\%]//g; # remove \\ and \%
553
$_[0] =~ s/%.*$//; # remove line comments
554
$_[0] =~ s/\\[{}]//g; # remove \{ and \}
559
remove_invalid_braces $line;
560
my $level = shift || 0;
561
my $count = shift || 0;
562
for my $char (split //, $line) {
566
elsif ($char eq '}') {
573
return ($level, $count);
577
my $rmacroname = shift;
581
open (my $fh, '<', $path) or return;
583
^ # Begin of line (no whitespaces!)
585
(?:(?:\\global|\\long|\\protected|\\outer)\s*)* # Prefixes (maybe with whitespace between them)
588
[gex]?def \s* \\ # TeX definitions
589
| (?:new|renew|provide)command\s* \*? \s* {? \s* \\ # LaTeX definitions
590
| (?:new|renew|provide)robustcmd\s* \*? \s* {? \s* \\ # etoolbox definitions
591
| \@namedef{? # Definition by name only
592
| Declare[a-zA-z]+ \s* \*? \s* {? \s* \\ # Declare... definitions
593
| declare[a-zA-z]+ \s* \*? \s* {? \s* \\ # declare... definitions
595
$rmacroname # Macro name without backslash
599
^ # Begin of line (no whitespaces!)
602
(?:(?:\\global)\s*)* # Prefixes (maybe with whitespace between them)
605
$rmacroname # Macro name without backslash
606
\s* =? # Optional '='
607
\s* \\ ([a-zA-Z@]+) # Second macro
610
^\s* # Begin of line (no whitespaces!)
612
(?:new|renew|provide)environment\s* { \s* # LaTeX definitions
614
($rmacroname) # Environment names follow same rules as macro names
615
\s* } # closing brace
618
while (my $line = <$fh>) {
619
if ($line =~ $rmacrodef) {
621
print "% $file, line $.:\n";
623
remove_invalid_braces $line;
624
my $obrace = $line =~ tr/{/{/;
625
my $cbrace = $line =~ tr/}/}/;
626
while ($obrace != $cbrace) {
629
remove_invalid_braces $line;
630
$obrace += $line =~ tr/{/{/;
631
$cbrace += $line =~ tr/}/}/;
636
elsif ($line =~ $rmacrolet) {
639
print "% $file, line $.:\n";
642
unshift @cmds, $letcmd;
645
elsif ($line =~ $renvdef) {
647
print "% $file, line $.:\n";
649
my ($level, $count) = env_braces $line;
653
($level, $count) = env_braces $line, $level, $count;
663
open (my $texpipe, '-|', "$TEX $TEXOPTIONS \"$TMPFILE\" ");
531
666
my $definition = '';
532
667
my $errormsg = '';
668
my $origdeffound = 0;
534
670
while (<$texpipe>) {
535
671
if (/^::\s*(.*)/) {
541
677
$line =~ s/$1/$path/;
681
if ($line =~ /first defined in "(.*)"/) {
683
my $path = `kpsewhich "$file"`;
685
$origdeffound = print_orig_def($cmd, $file, $path);
687
elsif ($line =~ /is defined by \(La\)TeX./) {
688
my $file = 'latex.ltx';
689
my $path = `kpsewhich "$file"`;
691
$file = $path if $FINDDEF > 1;
692
$origdeffound = print_orig_def($cmd, $file, $path);
694
if (!$origdeffound) {
695
print "Source code definition of '$cmd' could not be found.\n";
547
704
if (/^(:TEXDEF:\s*(.*))/) {
809
} elsif (!$PRINTORIGDEF || !$origdeffound) {
653
810
print "\n(in preamble)" if $inpreamble;
654
811
print "\n$name:\n$definition\n\n";
657
814
testdef($origcmd,$definition);
815
if ($ISENVIRONMENT && $origdeffound < 2 && $cmd !~ /^end/) {
816
unshift @cmds, 'end' . $cmd;