diff --git a/lib/syntax.default b/lib/syntax.default index 9f7cb271b2..59ac2dae1b 100644 --- a/lib/syntax.default +++ b/lib/syntax.default @@ -629,7 +629,16 @@ $$ \textcircled{translate} \textcolor[]{,,}{translate} %\textcolor{}{} -\textnormal{translate} +\textbf{translate} % hardcoded, but needed nevertheless for \let\xyz\textbf +\textnormal{translate} % hardcoded, but needed nevertheless for \let\xyz\textnormal +\textmd{translate} % hardcoded, but needed nevertheless for \let\xyz\textmd +\textit{translate} % hardcoded, but needed nevertheless for \let\xyz\textit +\textrm{translate} % hardcoded, but needed nevertheless for \let\xyz\textrm +\textsc{translate} % hardcoded, but needed nevertheless for \let\xyz\textsc +\textsf{translate} % hardcoded, but needed nevertheless for \let\xyz\textsf +\textsl{translate} % hardcoded, but needed nevertheless for \let\xyz\textsl +\texttt{translate} % hardcoded, but needed nevertheless for \let\xyz\texttt +\textup{translate} % hardcoded, but needed nevertheless for \let\xyz\textup \textfraction \thanks{translate} \thicklines diff --git a/src/tex2lyx/Parser.cpp b/src/tex2lyx/Parser.cpp index 1d698cc44c..1242b67ff2 100644 --- a/src/tex2lyx/Parser.cpp +++ b/src/tex2lyx/Parser.cpp @@ -293,6 +293,38 @@ char Parser::getChar() } +bool Parser::hasOpt() +{ + // An optional argument can occur in any of the following forms: + // - \foo[bar] + // - \foo [bar] + // - \foo + // [bar] + // - \foo %comment + // [bar] + + // remember current position + unsigned int oldpos = pos_; + // skip spaces and comments + while (good()) { + get_token(); + if (isParagraph()) { + putback(); + break; + } + if (curr_token().cat() == catSpace || + curr_token().cat() == catNewline || + curr_token().cat() == catComment) + continue; + putback(); + break; + } + bool const retval = (next_token().asInput() == "["); + pos_ = oldpos; + return retval; +} + + Parser::Arg Parser::getFullArg(char left, char right) { skip_spaces(true); diff --git a/src/tex2lyx/Parser.h b/src/tex2lyx/Parser.h index 546b3ff72d..51c063ebf7 100644 --- a/src/tex2lyx/Parser.h +++ b/src/tex2lyx/Parser.h @@ -131,6 +131,8 @@ public: /// dump contents to screen void dump() const; + /// Does an optional argument follow after the current token? + bool hasOpt(); /// typedef std::pair Arg; /*! diff --git a/src/tex2lyx/table.cpp b/src/tex2lyx/table.cpp index 987dc87a21..de4e7bd9ec 100644 --- a/src/tex2lyx/table.cpp +++ b/src/tex2lyx/table.cpp @@ -968,6 +968,7 @@ void handle_tabular(Parser & p, ostream & os, bool is_long_tabular, // special cell properties alignment vector t; handle_colalign(p, t, ColInfo()); + p.skip_spaces(true); ColInfo & ci = t.front(); // The logic of LyX for multicolumn vertical diff --git a/src/tex2lyx/test/test-insets.tex b/src/tex2lyx/test/test-insets.tex index 5f6ef3739d..d4df53a127 100644 --- a/src/tex2lyx/test/test-insets.tex +++ b/src/tex2lyx/test/test-insets.tex @@ -32,7 +32,6 @@ \newcommand{\lyxarrow}{\leavevmode\,$\triangleright$\,\allowbreak} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. -\usepackage{doc} \usepackage{subscript} % user specified as long as tex2lyx % produces a format less than 408 @@ -94,7 +93,8 @@ Now the natbib things: \textbackslash{}nocite: \nocite{article-crossref} \bibliographystyle{unsrt} -\bibliography{xampl} +% Remove duplicate call of \bibliography since LaTeX throws an error. +% \bibliography{xampl} With \textbackslash{}nocite\{{*}\}: \bibliographystyle{unsrt} @@ -129,12 +129,13 @@ There is also some basic support for graphics, in the form \section{Tables\index{Tables}} The following example is stolen from the longtable documentation. +Since tex2lyx does not understand the special verbatim code that +was used in the original some lines have been rewritten using +\textbackslash textbackslash etc. \let\package\textsf \let\env\textsf +\let\code\texttt \providecommand\finalclearpage{\clearpage} -\DeleteShortVerb{\|} -\MakeShortVerb{\"} -\def\v{\char`} \begin{longtable}{@{*}r||p{1in}@{*}} KILLED & LINE!!!! \kill @@ -166,28 +167,28 @@ at the end& of the table\\ \endlastfoot \env{longtable} columns are specified& in the \\ same way as in the \env{tabular}& environment.\\ -"@{*}r||p{1in}@{*}"& in this case.\\ -Each row ends with a& "\\" command.\\ -The "\\" command has an& optional\\ +%\code{@\{*\}r||p\{1in\}@\{*\}}& in this case.\\ +Each row ends with a& \code{\textbackslash\textbackslash} command.\\ +The \code{\textbackslash\textbackslash} command has an& optional\\ argument, just as in& the\\ \env{tabular}&environment.\\[10pt] -See the effect of "\\[10pt]"&?\\ +See the effect of \code{\textbackslash\textbackslash[10pt]}&?\\ Lots of lines& like this.\\ Lots of lines& like this.\\ Lots of lines& like this.\\ Lots of lines& like this.\\ -Also "\hline" may be used,& as in \env{tabular}.\\ +Also \code{\textbackslash hline} may be used,& as in \env{tabular}.\\ \hline -That was a "\hline"&.\\ +That was a \code{\textbackslash hline}&.\\ \hline\hline -That was "\hline\hline"&.\\ +That was \code{\textbackslash hline\textbackslash hline}&.\\ \multicolumn{2}{||c||}% -{This is a \ttfamily\v\\multicolumn\v{2\v}\v{||c||\v}}\\ -If a page break occurs at a "\hline" then& a line is drawn\\ +{This is a \code{\textbackslash multicolumn\{2\}\{||c||\}}}\\ +If a page break occurs at a \code{\textbackslash hline} then& a line is drawn\\ at the bottom of one page and at the& top of the next.\\ \hline -The "[t] [b] [c]" argument of \env{tabular}& can not be used.\\ -The optional argument may be one of& "[l] [r] [c]"\\ +The \code{[t] [b] [c]} argument of \env{tabular}& can not be used.\\ +The optional argument may be one of& \code{[l] [r] [c]}\\ to specify whether the table should be& adjusted\\ to the left, right& or centrally.\\ \hline\hline @@ -215,7 +216,7 @@ Some lines may take up a lot of space, like this: & \raggedleft This last column is a ``p'' column so this ``row'' of the table can take up several lines. Note however that \TeX\ will never break a page within such a row. Page breaks only - occur between rows of the table or at "\hline" commands. + occur between rows of the table or at \code{\textbackslash hline} commands. \tabularnewline Lots of lines& like this.\\ Lots of lines& like this.\\ @@ -268,9 +269,13 @@ test \subsection{Line breaks} They can also or be broken by a newline\\ -or a newline command \newline +or by a starred newline \\* +or by a newline with space, comment and argument \\ %hu +[3cm] +or by a newline command \newline or by a line break \linebreak -or by a defined line break \linebreak[4] +or by a defined line break \linebreak % again with a comment + [4] There are even newlines with weird arguments, but these are not handled by LyX\\*[1cm] @@ -280,7 +285,8 @@ so we try to use ERT in this case. They can also or be broken by a newpage \newpage or by a page break \pagebreak -or by a defined page break \pagebreak[4] +or by a defined page break \pagebreak % again with a comment + [4] \section{Special characters\index{Special characters}} diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 122aa3c074..4543c488ab 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -455,7 +455,7 @@ void eat_whitespace(Parser &, ostream &, Context &, bool); * This should be called after a command has been parsed that is not put into * ERT, and where LyX adds "{}" if needed. */ -void skip_spaces_braces(Parser & p) +void skip_spaces_braces(Parser & p, bool keepws = false) { /* The following four examples produce the same typeset output and should be handled by this function: @@ -471,7 +471,7 @@ void skip_spaces_braces(Parser & p) // results in different output in some cases. bool const skipped_spaces = p.skip_spaces(true); bool const skipped_braces = skip_braces(p); - if (skipped_spaces && !skipped_braces) + if (keepws && skipped_spaces && !skipped_braces) // put back the space (it is better handled by check_space) p.unskip_spaces(true); } @@ -643,17 +643,17 @@ void parse_box(Parser & p, ostream & os, unsigned flags, bool outer, string height_unit = "in"; string height_special = "totalheight"; string latex_height; - if (p.next_token().asInput() == "[") { + if (p.hasOpt()) { position = p.getArg('[', ']'); if (position != "t" && position != "c" && position != "b") { position = "c"; cerr << "invalid position for minipage/parbox" << endl; } - if (p.next_token().asInput() == "[") { + if (p.hasOpt()) { latex_height = p.getArg('[', ']'); translate_box_len(latex_height, height_value, height_unit, height_special); - if (p.next_token().asInput() == "[") { + if (p.hasOpt()) { inner_pos = p.getArg('[', ']'); if (inner_pos != "c" && inner_pos != "t" && inner_pos != "b" && inner_pos != "s") { @@ -794,9 +794,8 @@ void parse_environment(Parser & p, ostream & os, bool outer, eat_whitespace(p, os, parent_context, false); parent_context.check_layout(os); begin_inset(os, "Float " + unstarred_name + "\n"); - if (p.next_token().asInput() == "[") { + if (p.hasOpt()) os << "placement " << p.getArg('[', ']') << '\n'; - } os << "wide " << convert(is_starred) << "\nsideways false" << "\nstatus open\n\n"; @@ -2464,19 +2463,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.setEncoding(enc); } - else if (t.cs() == "LyX" || t.cs() == "TeX" - || t.cs() == "LaTeX") { - context.check_layout(os); - os << t.cs(); - skip_spaces_braces(p); - } - - else if (t.cs() == "LaTeXe") { - context.check_layout(os); - os << "LaTeX2e"; - skip_spaces_braces(p); - } - else if (t.cs() == "ldots") { context.check_layout(os); os << "\\SpecialChar \\ldots{}\n"; @@ -2603,11 +2589,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (t.cs() == "\\") { context.check_layout(os); - string const next = p.next_token().asInput(); - if (next == "[") + if (p.hasOpt()) handle_ert(os, "\\\\" + p.getOpt(), context); - else if (next == "*") { + else if (p.next_token().asInput() == "*") { p.get_token(); + // getOpt() eats the following space if there + // is no optional argument, but that is OK + // here since it has no effect in the output. handle_ert(os, "\\\\*" + p.getOpt(), context); } else { @@ -2617,8 +2605,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else if (t.cs() == "newline" || - (t.cs() == "linebreak" && - p.next_token().asInput() != "[")) { + (t.cs() == "linebreak" && !p.hasOpt())) { context.check_layout(os); begin_inset(os, "Newline "); os << t.cs(); @@ -2804,8 +2791,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else if (t.cs() == "newpage" || - (t.cs() == "pagebreak" && - p.next_token().asInput() != "[") || + (t.cs() == "pagebreak" && !p.hasOpt()) || t.cs() == "clearpage" || t.cs() == "cleardoublepage") { context.check_layout(os); @@ -2843,7 +2829,38 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); } } - + + else if (t.cs() == "let" && p.next_token().asInput() != "*") { + // let could be handled by parse_command(), + // but we need to call add_known_command() here. + string ert = t.asInput(); + string name; + p.skip_spaces(); + if (p.next_token().cat() == catBegin) { + name = p.verbatim_item(); + ert += '{' + name + '}'; + } else { + name = p.verbatim_item(); + ert += name; + } + string command; + p.skip_spaces(); + if (p.next_token().cat() == catBegin) { + command = p.verbatim_item(); + ert += '{' + command + '}'; + } else { + command = p.verbatim_item(); + ert += command; + } + // If command is known, make name known too, to parse + // its arguments correctly. For this reason we also + // have commands in syntax.default that are hardcoded. + CommandMap::iterator it = known_commands.find(command); + if (it != known_commands.end()) + known_commands[t.asInput()] = it->second; + handle_ert(os, ert, context); + } + else if (t.cs() == "hspace" || t.cs() == "vspace") { bool starred = false; if (p.next_token().asInput() == "*") {