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.
7 # This package reads a LaTeX preamble (everything before \begin{document}
8 # and translates it to LaTeX.
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)
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);
25 # Was -d option given?
26 $debug_on = (defined($main::opt_d) && $main::opt_d);
28 $true_class = defined($main::opt_c) ? $main::opt_c : "";
30 ? " from LaTeX file $InFileName into $PreambleName and $OutFileName"
32 warn "Splitting Preamble$zzz\n";
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";
39 # Copy everything up to "\begin{document}" into the preamble
41 if (s/\Q\begin{document}\E//) {
42 ($a, $b, $c) = ($`, $&, $'); # save for later
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/;
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}!
55 print "Put preamble into file $PreambleName\n" if $debug_on;
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
62 last if $_ =~ /^[^%]*\Q\end{document}\E/;
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
72 # Actually translate a LaTeX preamble (in a file) into a LyX preamble.
74 # First argument is the name of the file containing *only* the preamble
75 # Second argument is the LyX format (e.g., "2.15")
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)
81 sub translate_preamble {
82 my $PreambleName = 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");
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",
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",
105 "twoside" => "\\papersides 2",
106 "oneside" => "\\papersides 1",
108 "landscape" => "\\paperorientation landscape",
110 "onecolumn" => "\\papercolumns 1",
111 "twocolumn" => "\\papercolumns 2",
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");
120 next if(/^\#/); #ignore comments
121 my @lang_field = split(/\s+/);
122 $Languages_Table{$lang_field[1]} = $lang_field[1];
127 # This is the string in which we're concatenating everything we translate
128 my $LyX_Preamble = "";
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.]+/) {
140 # die "Need \\lyxformat command in first line of default lyx file!";
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;
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";
155 $LyX_Preamble .= "\\lyxformat $Format\n";
157 # Ignore everything up to the \documentclass
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
165 warn "Uncommented text before \\documentclass command ignored!\n"if $ignore;
166 print "Ignored text was\n------\n$ignore------\n" if $debug_on && $ignore;
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
175 } # end loop; check the now longer $_ for a brace
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 [])
184 s/^\s*//; # there might be space before args
185 s/$Text::TeX::optionalArgument//;
186 $extra_options = $1 if $&;
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
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;
198 # Analyze the extra options, and remove those we know about
199 if ($extra_options) {
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;
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.
211 foreach $op (split(/\s*,\s*/,$extra_options)) {
212 if (exists $Languages_Table{$op}) {
214 $extra_options =~ s/\b$op\b//;
215 print "Document language $op\n" if $debug_on;
219 $LyX_Preamble .= "\\language $language\n";
221 $extra_options =~ s/^,+|,+(?=,)|,+$//g; # extra commas
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;
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
234 $Latex_Preamble .= $_;
237 # Process $Latex_Preamble, and try to extract as much as possible to
238 # $Lyx_Preamble (jamatos 2001/07/21)
240 # Deal with counters, for now just "tocdepth" and "secnumdepth"
241 my %Counter_Table = (
242 "secnumdepth" => "\\secnumdepth",
243 "tocdepth" => "\\tocdepth"
247 foreach $ct (keys %Counter_Table) {
248 $Latex_Preamble =~ s/\\setcounter\{$ct\}\{(.*)\}\s*// && do {
249 $LyX_Preamble .= "$Counter_Table{$ct} $1\n";
253 if($Latex_Preamble =~ s/\\pagestyle\{(.*)\}\s*//) {
254 $LyX_Preamble .= "\\paperpagestyle $1\n";
256 if($Latex_Preamble =~ s/\\usepackage\[(.*)\]\{inputenc\}\s*//) {
257 $LyX_Preamble .= "\\inputencoding $1\n";
259 $Latex_Preamble =~ s/\\usepackage\[.*\]\{fontenc\}\s*//;
261 ## Deal with \usepackage{} cases, no optional argument
262 my %Usepackage_Table = (
263 "amsmath" => "\\use_amsmath 1",
266 "geometry" => "\\use_geometry 1",
270 "pslatex" => "\\fontscheme pslatex",
271 "ae" => "\\fontscheme ae",
273 "times" => "\\fontscheme times",
274 "palatino" => "\\fontscheme palatino",
275 "helvet" => "\\fontscheme helvet",
276 "avant" => "\\fontscheme avant",
277 "newcent" => "\\fontscheme newcent",
278 "bookman" => "\\fontscheme bookman",
280 "a4wide" => "\\paperpackage widemarginsa4",
281 "a4" => "\\paperpackage a4wide",
283 "graphics" => "\\graphics default",
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";
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 "");
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";
308 $LyX_Preamble .= "\\use_natbib 0\n\\use_numerical_citations 0\n";
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 "" },
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" },
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" }
335 if( $Latex_Preamble =~ /\\geometry\{(.*)\}/) {
336 my $geom_options = $1;
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;
344 $geom_options =~ s/^,+|,+(?=,)|,+$//g; # extra commas
345 if( $geom_options =~ /\s*/) {
346 $Latex_Preamble =~ s/\\geometry\{(.*)\}//;
349 $Latex_Preamble =~ s/\\geometry\{(.*)\}/\\geometry\{$geom_options\}/;
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";
361 if ( $Latex_Preamble =~ s/\\(\w*)spacing//) {
362 $LyX_Preamble .= "\\spacing $1\n";
365 ## remove LyX specific stuff
366 $Latex_Preamble =~ s/\\IfFileExists\{url.sty\}\{\\usepackage\{url\}\}\s*\{\\newcommand\{\\url\}\{\\texttt\}\}\s*//;
368 ## this two need probably a more fine grained control
369 $Latex_Preamble =~ s/\\makeatletter\s*//;
370 $Latex_Preamble =~ s/\\makeatother\s*//;
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;
379 #warn "Done creating LyX Preamble\n";
380 return ($class, $LyX_Preamble, $Latex_Preamble);
383 1; # return true value to calling program