]> git.lyx.org Git - lyx.git/blob - lib/reLyX/MakePreamble.pm
just Changelog
[lyx.git] / lib / reLyX / MakePreamble.pm
1 # This file is part of reLyX.
2 # Copyright (c) 1998-9 Amir Karger karger@post.harvard.edu
3 # You are free to use and modify this code under the terms of
4 # the GNU General Public Licence version 2 or later.
5
6 package MakePreamble;
7 # This package reads a LaTeX preamble (everything before \begin{document}
8 #    and translates it to LaTeX.
9
10 use strict;
11
12 my $debug_on; # package-wide variable set if -d option is given
13 my $true_class; # which textclass to use (if -c option is given)
14
15 sub split_preamble {
16 # Split the file into two files, one with just the preamble
17 # Simply copy stuff verbatim, saving translation for later
18 # Skip the LyX-generated portion of the preamble, if any. (Otherwise,
19 #     when you try to "view dvi" in LyX, there will be two copies of the
20 #     preamble matter, which will break LyX.
21     my ($InFileName, $PreambleName, $OutFileName) = (shift, shift, shift);
22     my ($a, $b, $c);
23     my $forget=0;
24
25     # Was -d option given?
26     $debug_on = (defined($main::opt_d) && $main::opt_d);
27     # -c option?
28     $true_class = defined($main::opt_c) ? $main::opt_c : "";
29     my $zzz = $debug_on
30         ? " from LaTeX file $InFileName into $PreambleName and $OutFileName"
31         : "";
32     warn "Splitting Preamble$zzz\n";
33
34     open (INFILE, "<$InFileName") or die "problem opening $InFileName: $!\n";
35     open (PREAMBLE, ">$PreambleName") or
36                 die "problem opening $PreambleName: $!\n";
37     open (OUTFILE, ">$OutFileName") or die "problem opening $OutFileName: $!\n";
38
39     # Copy everything up to "\begin{document}" into the preamble
40     while (<INFILE>) {
41         if (s/\Q\begin{document}\E//) {
42             ($a, $b, $c) = ($`, $&, $'); # save for later
43             last;
44         }
45         # In real life, there should never be Textclass specific stuff unless
46         # there is also LyX specific. But it can't hurt to test for both.
47         $forget=1 if m/%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific/ ||
48                      m/%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific/;
49         print PREAMBLE $_ unless $forget;
50         $forget=0 if m/%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified/;
51     }
52     die "Didn't find \\begin{document} command!" unless defined $b;
53     # There *could* be a preamble command on the same line as \begin{doc}!
54     print PREAMBLE $a;
55     print "Put preamble into file $PreambleName\n" if $debug_on;
56
57     # Copy everything else into another file
58     # Ignore anything after '\end{document}
59     print OUTFILE $b, $c; #'\begin{document}' plus anything else on the line
60     while (<INFILE>) {
61         print OUTFILE $_;
62         last if $_ =~ /^[^%]*\Q\end{document}\E/;
63     }
64
65     print "Put rest of file into $OutFileName\n" if $debug_on;
66     close INFILE; close OUTFILE; close PREAMBLE;
67     #warn "Done splitting preamble\n";
68 } #end sub split_preamble
69
70
71
72 # Actually translate a LaTeX preamble (in a file) into a LyX preamble.
73 # Input:
74 # First argument is the name of the file containing *only* the preamble
75 # Second argument is the LyX format (e.g., "2.15")
76 #
77 # Output: document class, LyX Preamble, LaTeX preamble
78 #    LyX premable contains the LyX options etc.
79 #    LaTeX preamble is stuff that doesn't translate into LyX options)
80 #
81 sub translate_preamble {
82     my $PreambleName = shift;
83     my $Format = shift;
84     $debug_on = (defined($main::opt_d) && $main::opt_d);
85     my $zzz=$debug_on ? " from $PreambleName" :"";
86     warn "Creating LyX preamble$zzz\n";
87     open (PREAMBLE, "<$PreambleName");
88
89     # Translate optional args to \documentclass to LyX preamble statements
90     my %Option_Trans_Table = (
91         "10pt"           => "\\paperfontsize 10",
92         "11pt"           => "\\paperfontsize 11",
93         "12pt"           => "\\paperfontsize 12",
94
95         "letterpaper"    => "\\papersize letterpaper",
96         "legalpaper"     => "\\papersize legalpaper",
97         "executivepaper" => "\\papersize executivepaper",
98         "a3paper"        => "\\papersize a3paper",
99         "a4paper"        => "\\papersize a4paper",
100         "a5paper"        => "\\papersize a5paper",
101         "b3paper"        => "\\papersize b3paper",
102         "b4paper"        => "\\papersize b4paper",
103         "b5paper"        => "\\papersize b5paper",
104
105         "twoside"        => "\\papersides 2",
106         "oneside"        => "\\papersides 1",
107
108         "landscape"      => "\\paperorientation landscape",
109
110         "onecolumn"      => "\\papercolumns 1",
111         "twocolumn"      => "\\papercolumns 2",
112     );
113
114     my %Languages_Table = ();
115     # if the language file is available then added it to the languages table
116     if(-e "$main::lyxdir/languages") {
117         open (LANGUAGES, "<$main::lyxdir/languages");
118
119         while(<LANGUAGES>) {
120             next if(/^\#/); #ignore comments
121             my @lang_field = split(/\s+/);
122             $Languages_Table{$lang_field[1]} = $lang_field[1];
123         }
124         close(LANGUAGES);
125     }
126
127     # This is the string in which we're concatenating everything we translate
128     my $LyX_Preamble = "";
129
130 # It would be nice to read the defaults.lyx file but for now we don't bother
131 #my $default_dir = "templates/";
132 #my $default_name = "defaults.lyx";
133 #my $default_file = $dot_lyxdir . $default_dir . $default_name;
134 #if (-e $default_file) {
135 #    print "Going to open default LyX file $default_file\n";
136 #    open (DEFAULT_LYX,$default_file) or warn "can't find default lyx file!";
137 #       if ($fmt =~ /^\s*\\lyxformat [0-9.]+/) {
138 #           print $fmt
139 #       } else {
140 #           die "Need \\lyxformat command in first line of default lyx file!";
141 #       }
142 #       AFTER printing the preamble, we'd print other commands from defaults.lyx
143 #       while (($line = <DEFAULT_LYX>) !~ /^.*\\layout/) {
144 #           if ($line !~ /^\s*(\#|\\textclass\W)/) { #already printed this line
145 #               print OUTFILE $line;
146 #           }
147 #       }
148 #}
149
150     # Write first line of the lyx file
151     $LyX_Preamble .= "\# The reLyX bundled with LyX 1.3 created this file.\n" .
152         "# For more info see http://www.lyx.org/\n";
153
154     # Print \lyxformat.
155     $LyX_Preamble .= "\\lyxformat $Format\n";
156
157     # Ignore everything up to the \documentclass
158     my $ignore = "";
159     while (<PREAMBLE>) {
160         next if /^\s*$/ || /^\s*%/; # skip whitespace or comment
161         # could just allow 'documentclass' and not support 2.09
162         last if s/^\s*\\document(style|class)//;
163         $ignore .= $_; # concatenate the ignored text
164     } # end while
165     warn "Uncommented text before \\documentclass command ignored!\n"if $ignore;
166     print "Ignored text was\n------\n$ignore------\n" if $debug_on && $ignore;
167
168     # concatenate all the extra options until the required argument to
169     # \documentclass, which will be in braces
170     until (eof(PREAMBLE) || /\{/) {
171         my $instr = <PREAMBLE>;
172         $instr =~ s/\s*%.*$//; # get rid of comments
173         chomp; # remove the \n on $_ prior to concatenating
174         $_ .= $instr;
175     } # end loop; check the now longer $_ for a brace
176
177     # Read optional arguments, which are now guaranteed to be on one line
178     # (They're read here, but printed AFTER the \\textclass command)
179     #    Note: the below pattern match is *always* successful, so $& is always
180     # set, but it will be '' if there are no optional arguments. $1 will be
181     # whatever was inside the brackets (i.e., not including the [])
182     my $extra_options;
183     if (defined($_)) {
184         s/^\s*//; # there might be space before args
185         s/$Text::TeX::optionalArgument//;
186         $extra_options = $1 if $&;
187     }
188
189     # Read the document class, in braces, then convert it to a textclass
190     # However, if the user input a different class with the -c option, use that
191     s/\s*\{(\S+)\s*\}//;
192     my $class = $1;
193     $class = $true_class if $true_class; # override from -c option
194     die "no document class in file, no -c option given\n" unless $class;
195     $LyX_Preamble .= "\\textclass $class\n";
196     print "document class is $class\n" if $debug_on;
197
198     # Analyze the extra options, and remove those we know about
199     if ($extra_options) {
200         my $op;
201         foreach $op (keys %Option_Trans_Table) {
202             $extra_options =~ s/\b$op\b// && do {
203                 $LyX_Preamble .= "$Option_Trans_Table{$op}\n";
204                 print "Document option $op\n" if $debug_on;
205             }
206         }
207         $extra_options =~ s/^,+|,+(?=,)|,+$//g; # extra commas
208         # Analyze further the extra options for languages, the last language
209         # is the document language, so the order matters.
210         my $language ="";
211         foreach $op (split(/\s*,\s*/,$extra_options)) {
212             if (exists $Languages_Table{$op}) {
213                 $language = $op;
214                 $extra_options =~ s/\b$op\b//;
215                 print "Document language $op\n" if $debug_on;
216             }
217         }
218         if ($language) {
219             $LyX_Preamble .= "\\language $language\n";
220         }
221         $extra_options =~ s/^,+|,+(?=,)|,+$//g; # extra commas
222     }
223     # Convert any remaining options to an \options command
224     if ($extra_options) {
225         $LyX_Preamble .= "\\options $extra_options\n";
226         print "extra options: $extra_options\n" if $debug_on;
227     }
228
229     # Now copy the whole preamble into the preamble of the LyX document
230     #     (unless there is no preamble)
231     # Everything until the end of filehandle PREAMBLE is preamble matter
232     my $Latex_Preamble = $_; # there COULD be a preamble command on same line
233     while (<PREAMBLE>) {
234         $Latex_Preamble .= $_;
235     }
236
237     # Process $Latex_Preamble, and try to extract as much as possible to
238     # $Lyx_Preamble (jamatos 2001/07/21)
239
240     # Deal with counters, for now just "tocdepth" and "secnumdepth"
241     my %Counter_Table = (
242         "secnumdepth"   => "\\secnumdepth",
243         "tocdepth"      => "\\tocdepth"
244     );
245
246     my $ct;
247     foreach $ct (keys %Counter_Table) {
248         $Latex_Preamble =~ s/\\setcounter\{$ct\}\{(.*)\}\s*// && do {
249             $LyX_Preamble .= "$Counter_Table{$ct} $1\n";
250         }
251     }
252
253     if($Latex_Preamble =~ s/\\pagestyle\{(.*)\}\s*//) {
254         $LyX_Preamble .= "\\paperpagestyle $1\n";
255     }
256     if($Latex_Preamble =~ s/\\usepackage\[(.*)\]\{inputenc\}\s*//) {
257         $LyX_Preamble .= "\\inputencoding $1\n";
258     }
259     $Latex_Preamble =~ s/\\usepackage\[.*\]\{fontenc\}\s*//;
260
261     ## Deal with \usepackage{} cases, no optional argument
262     my %Usepackage_Table = (
263         "amsmath"       => "\\use_amsmath 1",
264         "amssymb"       => "",
265
266         "geometry"      => "\\use_geometry 1",
267
268         "babel"         => "",
269
270         "pslatex"       => "\\fontscheme pslatex",
271         "ae"            => "\\fontscheme ae",
272         "aecompl"       => "",
273         "times"         => "\\fontscheme times",
274         "palatino"      => "\\fontscheme palatino",
275         "helvet"        => "\\fontscheme helvet",
276         "avant"         => "\\fontscheme avant",
277         "newcent"       => "\\fontscheme newcent",
278         "bookman"       => "\\fontscheme bookman",
279
280         "a4wide"        => "\\paperpackage widemarginsa4",
281         "a4"            => "\\paperpackage a4wide",
282
283         "graphics"      => "\\graphics default",
284         "rotating"      => "",
285         "makeidx"       => ""
286     );
287
288     ## Babel with arguments specifing language
289     if($Latex_Preamble =~ s/\\usepackage\[(.*)\]\{babel\}\s*//) {
290         my @languages = split(',',$1);
291         my $lang = pop @languages;
292         $LyX_Preamble .= "\\language $lang\n";
293     }
294
295     my $up;
296     foreach $up (keys %Usepackage_Table) {
297         $Latex_Preamble =~ s/^\s*\\usepackage\{$up\}\s*// && do {
298             $LyX_Preamble .= "$Usepackage_Table{$up}";
299             $LyX_Preamble .= "\n" unless ($Usepackage_Table{$up} eq "");
300         }
301     }
302
303     # Natbib is a little more complex than that.
304     if ($Latex_Preamble =~ s/\\usepackage(.*)\{natbib\}\s*//) {
305         $LyX_Preamble .= "\\use_natbib 1\n\\use_numerical_citations ";
306         $LyX_Preamble .= ($1 =~ /numbers/) ? "1\n" : "0\n";
307     } else {
308         $LyX_Preamble .= "\\use_natbib 0\n\\use_numerical_citations 0\n";
309     }
310
311     ## Handle geometry options
312     ## The custom paper missing from the options list since it involves two parameters
313     my %Geometry_Options =(
314         'verbose'       => sub { return "" },
315
316         "letterpaper"   => sub { return "\\papersize letterpaper\n" },
317         "legalpaper"    => sub { return "\\papersize legalpaper\n" },
318         "executivepaper"=> sub { return "\\papersize executivepaper\n" },
319         "a3paper"       => sub { return "\\papersize a3paper\n" },
320         "a4paper"       => sub { return "\\papersize a4paper\n" },
321         "a5paper"       => sub { return "\\papersize a5paper\n" },
322         "b3paper"       => sub { return "\\papersize b3paper\n" },
323         "b4paper"       => sub { return "\\papersize b4paper\n" },
324         "b5paper"       => sub { return "\\papersize b5paper\n" },
325
326         'tmargin=(\w*)' => sub { return "\\topmargin $1\n" },
327         'bmargin=(\w*)' => sub { return "\\bottommargin $1\n" },
328         'lmargin=(\w*)' => sub { return "\\leftmargin $1\n" },
329         'rmargin=(\w*)' => sub { return "\\rightmargin $1\n" },
330         'headsep=(\w*)' => sub { return "\\headsep $1\n" },
331         'footskip=(\w*)'        => sub { return "\\footskip $1\n" },
332         'headheight=(\w*)'      => sub { return "\\headheight $1\n" }
333     );
334
335     if( $Latex_Preamble =~ /\\geometry\{(.*)\}/) {
336         my $geom_options = $1;
337         my $op;
338         foreach $op (keys %Geometry_Options) {
339             $geom_options =~ s/$op// && do {
340                 $LyX_Preamble .= &{$Geometry_Options{$op}}();
341                 print "Geometry option $op\n" if $debug_on;
342             }
343         }
344         $geom_options =~ s/^,+|,+(?=,)|,+$//g; # extra commas
345         if( $geom_options =~ /\s*/) {
346             $Latex_Preamble =~ s/\\geometry\{(.*)\}//;
347         }
348         else {
349             $Latex_Preamble =~ s/\\geometry\{(.*)\}/\\geometry\{$geom_options\}/;
350         }
351     }
352
353     ## Paragraph skip or indentation
354     if ( $Latex_Preamble =~
355          s/\\setlength\\parskip\{\\(.*)amount\}\s*\\setlength\\parindent\{0pt\}//) {
356         $LyX_Preamble .= "\\paragraph_separation skip\n";
357         $LyX_Preamble .= "\\defskip $1\n";
358     }
359
360     ## Paragraph spacing
361     if ( $Latex_Preamble =~ s/\\(\w*)spacing//) {
362         $LyX_Preamble .= "\\spacing  $1\n";
363     }
364
365     ## remove LyX specific stuff
366     $Latex_Preamble =~ s/\\IfFileExists\{url.sty\}\{\\usepackage\{url\}\}\s*\{\\newcommand\{\\url\}\{\\texttt\}\}\s*//;
367
368     ##  this two need probably a more fine grained control
369     $Latex_Preamble =~ s/\\makeatletter\s*//;
370     $Latex_Preamble =~ s/\\makeatother\s*//;
371
372     $Latex_Preamble =~ s/^\s*//;
373     print "LaTeX preamble, consists of:\n$Latex_Preamble" if $debug_on;
374     if($Latex_Preamble) {
375         $Latex_Preamble = "\\begin_preamble\n$Latex_Preamble\\end_preamble\n";
376     } #just comments, whitespace. Ignore them
377     print "End of LaTeX preamble\n" if $debug_on;
378
379     #warn "Done creating LyX Preamble\n";
380     return ($class, $LyX_Preamble, $Latex_Preamble);
381 }
382
383 1; # return true value to calling program