]> git.lyx.org Git - lyx.git/blobdiff - lib/reLyX/BasicLyX.pm
just Changelog
[lyx.git] / lib / reLyX / BasicLyX.pm
index 521e7ee056533200e73d4efabfe366eee8ee89c6..0c4e83c9a188b78844972a31e59d11c7ee1569b9 100644 (file)
@@ -214,10 +214,36 @@ my %ExtraArgEnvironments = (
 );
 
 # Math environments are copied verbatim
-my $MathEnvironments = "(math|equation|displaymath|eqnarray(\\*)?)";
+my $MathEnvironments = "(math|displaymath|xxalignat|(equation|eqnarray|align|alignat|xalignat|multline|gather)(\\*)?)";
 # ListLayouts may have standard paragraphs nested inside them.
 my $ListLayouts = "Itemize|Enumerate|Description";
 
+# passed a string and an array
+# returns true if the string is an element of the array.
+sub foundIn {
+    my $name = shift;
+    return grep {$_ eq $name} @_;
+}
+
+my @NatbibCommands = map {"\\$_"} qw(citet citealt citep citealp citeauthor);
+
+# passed a string.
+# returns true if it is a valid natbib citation
+sub isNatbibCitation {
+    my $name = shift;
+
+    # These two have a single form
+    return 1 if ($name eq '\citeyear' or $name eq '\citeyearpar');
+
+    # Natbib citations can start with a 'C' or a 'c'
+    $name =~ s/^\\C/\\c/;
+    # The can end with a '*'
+    $name =~ s/\*$//;
+    # Is this doctored string found in the list of valid commands?
+    return foundIn($name, @NatbibCommands);
+
+}
+
 #####################   PARSER INVOCATION   ##################################
 sub call_parser {
 # This subroutine calls the TeX parser & translator
@@ -238,7 +264,7 @@ sub call_parser {
     #    Type=>report_args and count=>1
     # Note that we don't have to bother putting in tokens which will be simply
     #    translated (e.g., from %TextTokenTransTable).
-    my %MyTokens = ( 
+    my %MyTokens = (
        '{' => $Text::TeX::Tokens{'{'},
        '}' => $Text::TeX::Tokens{'}'},
        '\begin' => $Text::TeX::Tokens{'\begin'},
@@ -264,7 +290,7 @@ sub call_parser {
        # Just pretend they actually ARE new paragraph markers!
        '\maketitle' => {'class' => 'Text::TeX::Paragraph'},
     );
-    
+
     # Now add to MyTokens all of the commands that were read from the
     #    commands file by package ReadCommands
     &ReadCommands::Merge(\%MyTokens);
@@ -290,6 +316,96 @@ sub call_parser {
     return;
 } # end subroutine call_parser
 
+# This is used as a toggle so that we know what to do when basic_lyx is
+# passed a '$' or '$$' token.
+my $inside_math=0;
+
+sub starting_math {
+    my $name = shift;
+
+    if ($name eq '\(' || $name eq '\[' ||
+       # These tokens bound both ends of a math environment so we must check
+       # $inside_math to know what action to take.
+       ($name eq '$' || $name eq '$$') && !$inside_math) {
+
+       $inside_math = 1;
+       return 1;
+    }
+
+    # All other tokens
+    return 0;
+}
+
+sub ending_math {
+    my $name = shift;
+
+    if ($name eq '\)' || $name eq '\]' ||
+       # These tokens bound both ends of a math environment so we must check
+       # $inside_math to know what action to take.
+       ($name eq '$' || $name eq '$$') && $inside_math) {
+
+       $inside_math = 0;
+       return 1;
+    }
+
+    # All other tokens
+    return 0;
+}
+
+
+sub regularizeLatexLength {
+    my $LatexLength = shift;
+
+    # Remove any whitespace
+    $LatexLength =~ s/\s//g;
+    # Remove a leading '+' as unnecessary
+    $LatexLength =~ s/^\+?(\d)/$1/;
+    # Split into value and unit parts
+    my $val;
+    my $unit;
+    if ($LatexLength =~ /(-?\d+[.,]?\d*)(\\?[a-zA-Z]*)$/) {
+       $val  = $1;
+       $unit = $2;
+    }
+    # If the input is invalid, return what we have.
+    return $LatexLength if ($val eq '' || $unit eq '');
+
+    # '4,5' is a valid LaTeX number. Change it to '4.5'
+    $val =~ s/,/./;
+    # If the unit is not a LaTeX macro, then ensure it is lower case
+    if (!($unit =~ /^\\/)) {
+       $unit =~ s/([a-z]*)/\L$1/i;
+    }
+
+    $LatexLength = $val . $unit;
+    return $LatexLength;
+}
+
+
+sub getAsLyXLength {
+    # Straight translation of LaTeX lengths to LyX ones.
+    my %lengthAsLyXString = ('\textwidth'   => 'text%',
+                            '\columnwidth' => 'col%',
+                            '\paperwidth'  => 'page%',
+                            '\linewidth'   => 'line%',
+                            '\paperheight' => 'pheight%',
+                            '\textheight'  => 'theight%');
+
+    my $LatexLength = shift;
+    $LatexLength = regularizeLatexLength($LatexLength);
+
+    my $LyXLength = $LatexLength;
+    # If $LatexLength is something like '4.5\columnwidth', translate into
+    # LyXese.
+    if ($LatexLength =~ /([+-]?\d+\.?\d*)(\\[a-z]*)/) {
+       if (defined($lengthAsLyXString{$2})) {
+           $LyXLength = ($1 * 100) . $lengthAsLyXString{$2};
+       }
+    }
+
+    return $LyXLength;
+}
+
 ##########################   MAIN TRANSLATOR SUBROUTINE   #####################
 sub basic_lyx {
 # This subroutine is called by Text::TeX::process each time subroutine
@@ -347,7 +463,7 @@ sub basic_lyx {
        # If, e.g., there's just a comment in this token, don't do anything
        # This actually shouldn't happen if CleanTeX has already removed them
        last TYPESW if !defined $eaten->print;
-        
+
         # Handle LaTeX tokens
         if (/^Token$/o) {
 
@@ -381,14 +497,15 @@ sub basic_lyx {
                } # end special handling for \@
 
            # Handle tokens that LyX translates as a "LatexCommand" inset
-           } elsif (grep {$_ eq $name} @LatexCommands) {
+           } elsif (foundIn($name, @LatexCommands) ||
+                    isNatbibCitation($name)){
                &CheckForNewParagraph; #Start new paragraph if necessary
                print OUTFILE "$pre_space\n\\begin_inset LatexCommand ",
                               $name,
                              "\n\n\\end_inset \n\n";
 
            # Math -- copy verbatim until you're done
-           } elsif ($name eq '\(' || $name eq '\[') {
+           } elsif (starting_math($name)) {
                print "\nCopying math beginning with '$name'\n" if $debug_on;
                # copy everything until end text
                $dummy = &Verbatim::copy_verbatim($fileobject, $eaten);
@@ -399,14 +516,14 @@ sub basic_lyx {
                print $dummy if $debug_on;
                print OUTFILE $dummy;
 
-           } elsif ($name eq '\)' || $name eq '\]') {
+           } elsif (ending_math($name)) {
                # end math
                print OUTFILE "$name\n\\end_inset \n\n";
                print "\nDone copying math ending with '$name'" if $debug_on;
 
            # Items in list environments
            } elsif ($name eq '\item') {
-               
+
                # What if we had a nested "Standard" paragraph?
                # Then write \end_deeper to finish the standard layout
                #     before we write the new \layout ListEnv command
@@ -417,7 +534,7 @@ sub basic_lyx {
                          if $debug_on;
                } # end deeper if
 
-               # Upcoming text (the item) will be a new paragraph, 
+               # Upcoming text (the item) will be a new paragraph,
                #    requiring a new layout command based on whichever
                #    kind of list environment we're in
                $IsNewParagraph = 1;
@@ -470,7 +587,7 @@ sub basic_lyx {
                    $thistable->nextcol;
                } else {warn "& is illegal outside a table!"}
 
-           } elsif ($name eq '\\\\' || $name eq '\\newline') {
+           } elsif ($name eq '\\\\' || $name eq '\\newline' || $name eq "\\tabularnewline") {
                &CheckForNewParagraph; # could be at beginning of par?
                 print OUTFILE "\n\\newline \n";
 
@@ -508,7 +625,7 @@ sub basic_lyx {
                $length =~ s/\s*$//; # may have \n at end
 
                # If we can't parse the command, print it in tex mode
-               &RelyxFigure::parse_epsfsize($name, $length) or 
+               &RelyxFigure::parse_epsfsize($name, $length) or
                    &print_tex_mode("$name=$length");
 
            # Miscellaneous...
@@ -530,14 +647,14 @@ sub basic_lyx {
 
             last TYPESW;
         }
-        
+
        # Handle tokens that take arguments, like \section{},\section*{}
        if (/^BegArgsToken$/) {
            my $name = $eaten->token_name;
            print "$name" if $debug_on;
 
            # Handle things that LyX translates as a "LatexCommand" inset
-           if (grep {$_ eq $name} @LatexCommands) {
+           if (foundIn($name, @LatexCommands) || isNatbibCitation($name)){
                &CheckForNewParagraph; #Start new paragraph if necessary
 
                print OUTFILE "$pre_space\n\\begin_inset LatexCommand ";
@@ -597,7 +714,7 @@ sub basic_lyx {
                ($dummy, $dum2) = ($command =~ /(\S+)\s+(\w+)/);
 
                # HACK so that "\emph{hi \emph{bye}}" yields unemph'ed "bye"
-               if ( ($dummy eq "\\emph") && 
+               if ( ($dummy eq "\\emph") &&
                     ($CurrentFontStatus->{$dummy}->[-1] eq "on")) {
                       $dum2 = "default"; # "on" instead of default?
                       $command =~ s/on/default/;
@@ -615,7 +732,7 @@ sub basic_lyx {
 
 
            # Handle footnotes and margin notes
-           # Make a new font table & layout stack which will be local to the 
+           # Make a new font table & layout stack which will be local to the
            #    footnote or marginpar
            } elsif (exists $FloatTransTable{$name}) {
                my $command = $FloatTransTable{$name};
@@ -638,7 +755,7 @@ sub basic_lyx {
                $CurrentLayoutStack = ["Standard"];
 
                # Store whether we're at the end of a paragraph or not
-               #    for when we get to end of footnote AND 
+               #    for when we get to end of footnote AND
                # Note that the footnote text will be starting a new paragraph
                # Also store the current alignment (justification)
                $OldINP = $IsNewParagraph; $OldMBD = $MayBeDeeper;
@@ -652,7 +769,7 @@ sub basic_lyx {
                &CheckForNewParagraph; # may be at the beginning of a par
 
                print OUTFILE "$pre_space\n",'\i ',$name,'{'
-           
+
            # Included Postscript Figures
            # Currently, all postscript including commands take one
            # required argument and 0 to 2 optional args, so we can
@@ -755,7 +872,7 @@ sub basic_lyx {
            if ($eaten->base_token == $tok) {
                &copy_latex_known($eaten,$fileobject);
            }
-        
+
            last TYPESW;
        }
 
@@ -772,7 +889,8 @@ sub basic_lyx {
 
            # Handle things that LyX translates as a "LatexCommand" inset
            # or "Include" insets
-           if (grep {$_ eq $name} @LatexCommands, @IncludeCommands) {
+           if (foundIn($name, @LatexCommands, @IncludeCommands) ||
+               isNatbibCitation($name)){
                print OUTFILE "\}\n\n\\end_inset \n\n";
 
            } elsif (exists $ReadCommands::ToLayout->{$name}) {
@@ -811,7 +929,7 @@ sub basic_lyx {
 
            } elsif ($name =~ m/^$AccentTokens$/) {
                print OUTFILE "}\n";
-           
+
            } elsif ($name eq "\\bibitem") {
                print OUTFILE "}\n";
            } # End if on $name
@@ -863,7 +981,7 @@ sub basic_lyx {
         if (/^Begin::Group::Args$/) {
            print $eaten->print," " if $debug_on; # the string "\begin{foo}"
            my $env = $eaten->environment;
-           
+
            # Any environment found in the layouts files
            if (exists $ReadCommands::ToLayout->{$env}) {
                &ConvertToLayout($env);
@@ -947,6 +1065,55 @@ sub basic_lyx {
                $tok = $fileobject->eatGroup;
                new RelyxTable::Table $tok;
 
+           # minipage
+           } elsif ($env eq "minipage") {
+               &CheckForNewParagraph;
+
+               print OUTFILE "\\begin_inset Minipage\n";
+
+               # The minipage environment is defined as:
+               # \begin{minipage}[pos][height][inner-pos]{width} <text>
+               # \end{minipage}
+
+               # Read the position optional argument, if it exists
+               $tok = $fileobject->eatOptionalArgument;
+               my $pos = $tok->print if defined($tok->print);
+
+               my %map = ('t' => '0', 'c' => '1', 'b' => '2');
+               if ($debug_on && $pos ne '' && !defined($map{$pos})) {
+                   print "\nIgnoring unknown positioning arg '$pos'\n";
+               }
+
+               # The minipage is centred by default.
+               $pos = '1' if (!defined($map{$pos}) ||
+                                 ($pos = $map{$pos}) eq '');
+
+               # Read the height optional argument, if it exists
+               my $height = '0pt';
+               $tok = $fileobject->eatOptionalArgument;
+               if (defined($tok->print)) {
+                   $height = getAsLyXLength($tok->print);
+               }
+
+               # Read the inner-pos optional argument, if it exists
+               my $innerpos = $pos;
+               $tok = $fileobject->eatOptionalArgument;
+               if (defined($tok->print)) {
+                   my $arg = $tok->print;
+                   print("\nMinipage inner-pos argument, $arg, is ",
+                         "currently ignored\n");
+               }
+
+               # Read the width as (a reference to) an array of tokens.
+               $tok = $fileobject->eatBalanced;
+               my $width = getAsLyXLength($tok->exact_print);
+
+               print OUTFILE "position $pos\n";
+               print OUTFILE "inner_position $innerpos\n";
+               print OUTFILE "height \"$height\"\n";
+               print OUTFILE "width \"$width\"\n";
+               print OUTFILE "collapsed false\n";
+
            # \begin document
            } elsif ($env eq "document") {
                # do nothing
@@ -971,14 +1138,14 @@ sub basic_lyx {
                $tex_mode_string = "";
                # print "\begin{env}
                # For reLyXskip env, don't print the \begin & \end commands!
-               $tex_mode_string .= $eaten->exact_print 
+               $tex_mode_string .= $eaten->exact_print
                                unless $env eq "reLyXskip";
                $tex_mode_string .=&Verbatim::copy_verbatim($fileobject,$eaten);
            }
 
             last TYPESW;
         }
-        
+
         # Handle \end{foo}
         if (/^End::Group::Args$/) {
            print $eaten->print," " if $debug_on; # the string "\end{foo}"
@@ -1018,6 +1185,13 @@ sub basic_lyx {
                # Anything after a table will be a new paragraph
                $IsNewParagraph = 1; $MayBeDeeper = 1;
 
+           # minipage
+           } elsif ($env eq "minipage") {
+               print OUTFILE "\n\\end_inset \n\n";
+
+               # Next stuff will be new env.
+               # $IsNewParagraph = 1;
+
            } elsif ($env eq "document") {
                print "\nDone with document!" if $debug_on;
 
@@ -1344,7 +1518,7 @@ sub CheckForNewParagraph {
 # If $CurrentAlignment is set, it prints the alignment command for this par.
 # If $MayBeDeeper==1 and we're currently within a list environment,
 #    it starts a "deeper" Standard paragraph
-    my $dummy; 
+    my $dummy;
     my $layout = $$CurrentLayoutStack[-1];
 
     return if &RelyxTable::in_table;
@@ -1499,7 +1673,7 @@ sub fixmath {
                ( ([^A-Za-z] \*?) |    # non-letter (and *) ($4) OR
                  ([A-Za-z]+ \*?)   )  # letters (and *) ($5)
            )//xs) # /x to allow whitespace/comments, /s to copy \n's
-    { 
+    {
        $output .= $1;
        my $tok = $2;
        if (exists $ReadCommands::math_trans{$tok}) {