From d7b224d6928fc7a939bf57dcb700e01035db58ad Mon Sep 17 00:00:00 2001 From: Georg Baum Date: Thu, 6 Jan 2005 13:22:20 +0000 Subject: [PATCH] fix bug 1750 git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@9444 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/tex2lyx/ChangeLog | 14 +++++++++++ src/tex2lyx/preamble.C | 9 +++++-- src/tex2lyx/tex2lyx.C | 33 ++++++++++++++++++++++++++ src/tex2lyx/tex2lyx.h | 9 +++++++ src/tex2lyx/texparser.C | 28 +++++++++++++++++----- src/tex2lyx/texparser.h | 22 ++++++++++++++++- src/tex2lyx/text.C | 52 +++++++++++++++++++++++++---------------- 7 files changed, 138 insertions(+), 29 deletions(-) diff --git a/src/tex2lyx/ChangeLog b/src/tex2lyx/ChangeLog index 3755bf9c85..40b8d8b5ea 100644 --- a/src/tex2lyx/ChangeLog +++ b/src/tex2lyx/ChangeLog @@ -1,3 +1,17 @@ +2005-01-04 Georg Baum + + * preamble.C (parse_preamble): handle second optional arg of + \newcommand etc. and add the command to the known commands (fixes + bug 1750) + * texparser.[Ch] (getFullArg): new, like getArg but distinguish + between empty arguments and no argument found + * texparser.[Ch] (getFullOpt): new, like getOpt but distinguish + between empty arguments and no argument found + * tex2lyx.[Ch]: (add_known_command): new + * text.C (parse_text): handle \newcommand etc. (see above) + * text.C (parse_text): add comment about \underline + * text.C (getCiteArguments): use getFullOpt + 2004-12-15 Georg Baum * table.C (ColInfo, LTRowType, RowInfo, CellInfo, verbose_align): diff --git a/src/tex2lyx/preamble.C b/src/tex2lyx/preamble.C index c9b4011e19..449d9b9c26 100644 --- a/src/tex2lyx/preamble.C +++ b/src/tex2lyx/preamble.C @@ -329,7 +329,8 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & force star = true; } string const name = p.verbatim_item(); - string const opts = p.getOpt(); + string const opt1 = p.getOpt(); + string const opt2 = p.getFullOpt(); string const body = p.verbatim_item(); // only non-lyxspecific stuff if ( name != "\\noun" @@ -345,8 +346,12 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & force ss << '\\' << t.cs(); if (star) ss << '*'; - ss << '{' << name << '}' << opts << '{' << body << "}"; + ss << '{' << name << '}' << opt1 << opt2 + << '{' << body << "}"; h_preamble << ss.str(); + + // Add the command to the known commands + add_known_command(name, opt1, !opt2.empty()); /* ostream & out = in_preamble ? h_preamble : os; out << "\\" << t.cs() << "{" << name << "}" diff --git a/src/tex2lyx/tex2lyx.C b/src/tex2lyx/tex2lyx.C index 963f544951..62c99b4922 100644 --- a/src/tex2lyx/tex2lyx.C +++ b/src/tex2lyx/tex2lyx.C @@ -19,6 +19,7 @@ #include "lyxtextclass.h" #include "support/path_defines.h" #include "support/filetools.h" +#include "support/lstrings.h" #include "support/lyxlib.h" #include "support/os.h" @@ -46,6 +47,10 @@ using std::string; using std::vector; using std::map; +using lyx::support::isStrUnsignedInt; +using lyx::support::ltrim; +using lyx::support::rtrim; +using lyx::support::strToUnsignedInt; using lyx::support::system_lyxdir; using lyx::support::user_lyxdir; using lyx::support::IsFileReadable; @@ -119,6 +124,34 @@ string active_environment() map > known_commands; +void add_known_command(string const & command, string const & o1, + bool o2) +{ + // We have to handle the following cases: + // definition o1 o2 invocation result + // \newcommand{\foo}{bar} "" false \foo bar + // \newcommand{\foo}[1]{bar #1} "[1]" false \foo{x} bar x + // \newcommand{\foo}[1][]{bar #1} "[1]" true \foo bar + // \newcommand{\foo}[1][]{bar #1} "[1]" true \foo[x] bar x + // \newcommand{\foo}[1][x]{bar #1} "[1]" true \foo[x] bar x + unsigned int nargs = 0; + vector arguments; + string const opt1 = rtrim(ltrim(o1, "["), "]"); + if (isStrUnsignedInt(opt1)) { + // The command has arguments + nargs = strToUnsignedInt(opt1); + if (nargs > 0 && o2) { + // The first argument is optional + arguments.push_back(optional); + --nargs; + } + } + for (unsigned int i = 0; i < nargs; ++i) + arguments.push_back(required); + known_commands[command] = arguments; +} + + namespace { diff --git a/src/tex2lyx/tex2lyx.h b/src/tex2lyx/tex2lyx.h index 37df126868..adf77034a5 100644 --- a/src/tex2lyx/tex2lyx.h +++ b/src/tex2lyx/tex2lyx.h @@ -62,6 +62,15 @@ std::string join(std::vector const & input, bool is_math_env(std::string const & name); char const * const * is_known(std::string const &, char const * const *); +/*! + * Adds the command \p command to the list of known commands. + * \param o1 first optional parameter to the latex command \newcommand + * (with brackets), or the empty string if there were no optional arguments. + * \param o2 wether \newcommand had a second optional parameter + */ +void add_known_command(std::string const & command, std::string const & o1, + bool o2); + // Access to environment stack extern std::vector active_environments; std::string active_environment(); diff --git a/src/tex2lyx/texparser.C b/src/tex2lyx/texparser.C index 014c9a798f..8a17a47d33 100644 --- a/src/tex2lyx/texparser.C +++ b/src/tex2lyx/texparser.C @@ -271,21 +271,22 @@ char Parser::getChar() } -string Parser::getArg(char left, char right) +Parser::Arg Parser::getFullArg(char left, char right) { skip_spaces(true); // This is needed if a partial file ends with a command without arguments, // e. g. \medskip if (! good()) - return string(); + return std::make_pair(false, string()); string result; char c = getChar(); - if (c != left) + if (c != left) { putback(); - else + return std::make_pair(false, string()); + } else while ((c = getChar()) != right && good()) { // Ignore comments if (curr_token().cat() == catComment) { @@ -296,14 +297,29 @@ string Parser::getArg(char left, char right) result += curr_token().asInput(); } - return result; + return std::make_pair(true, result); +} + + +string Parser::getArg(char left, char right) +{ + return getFullArg(left, right).second; +} + + +string Parser::getFullOpt() +{ + Arg arg = getFullArg('[', ']'); + if (arg.first) + return '[' + arg.second + ']'; + return arg.second; } string Parser::getOpt() { string const res = getArg('[', ']'); - return res.size() ? '[' + res + ']' : string(); + return res.empty() ? string() : '[' + res + ']'; } diff --git a/src/tex2lyx/texparser.h b/src/tex2lyx/texparser.h index 6ab9946bbb..0fc250e14f 100644 --- a/src/tex2lyx/texparser.h +++ b/src/tex2lyx/texparser.h @@ -14,6 +14,7 @@ #include #include +#include enum mode_type {UNDECIDED_MODE, TEXT_MODE, MATH_MODE, MATHTEXT_MODE, TABLE_MODE}; @@ -127,8 +128,27 @@ public: void dump() const; /// + typedef std::pair Arg; + /*! + * Get an argument enclosed by \p left and \p right. + * \returns wether an argument was found in \p Arg.first and the + * argument in \p Arg.second. \see getArg(). + */ + Arg getFullArg(char left, char right); + /*! + * Get an argument enclosed by \p left and \p right. + * \returns the argument (without \p left and \p right) or the empty + * string if the next non-space token is not \p left. Use + * getFullArg() if you need to know wether there was an empty + * argument or no argument at all. + */ std::string getArg(char left, char right); - /// getArg('[', ']') including the brackets + /*! + * \returns getFullArg('[', ']') including the brackets or the + * empty string if no argument was found. + */ + std::string getFullOpt(); + /// \returns getArg('[', ']') including the brackets std::string getOpt(); /// Returns the character of the current token and increments the token position. char getChar(); diff --git a/src/tex2lyx/text.C b/src/tex2lyx/text.C index d1244bdd1e..1002b99b4b 100644 --- a/src/tex2lyx/text.C +++ b/src/tex2lyx/text.C @@ -848,29 +848,19 @@ void parse_text_attributes(Parser & p, ostream & os, unsigned flags, bool outer, /// get the arguments of a natbib or jurabib citation command -std::pair getCiteArguments(Parser & p, ostream & os, - Context & context, bool natbibOrder) +std::pair getCiteArguments(Parser & p, bool natbibOrder) { // We need to distinguish "" and "[]", so we can't use p.getOpt(). // text before the citation string before; // text after the citation - string after; + string after = p.getFullOpt(); - eat_whitespace(p, os, context, false); - if (p.next_token().asInput() == "[") { - after = '[' + p.getArg('[', ']') + ']'; - eat_whitespace(p, os, context, false); - if (natbibOrder) { - if (p.next_token().asInput() == "[") { - before = after; - after = '[' + p.getArg('[', ']') + ']'; - } - } else { - if (p.next_token().asInput() == "[") - before = '[' + p.getArg('[', ']') + ']'; - } + if (!after.empty()) { + before = p.getFullOpt(); + if (natbibOrder && !before.empty()) + std::swap(before, after); } return std::make_pair(before, after); } @@ -1445,6 +1435,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else if (t.cs() == "underbar") { + // Do NOT handle \underline. + // \underbar cuts through y, g, q, p etc., + // \underline does not. context.check_layout(os); os << "\n\\bar under\n"; parse_text_snippet(p, os, FLAG_ITEM, outer, context); @@ -1484,8 +1477,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // text after the citation string after; - boost::tie(before, after) = - getCiteArguments(p, os, context, true); + boost::tie(before, after) = getCiteArguments(p, true); if (command == "\\cite") { // \cite without optional argument means // \citet, \cite with at least one optional @@ -1528,8 +1520,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, string after; boost::tie(before, after) = - getCiteArguments(p, os, context, - argumentOrder != 'j'); + getCiteArguments(p, argumentOrder != 'j'); string const citation = p.verbatim_item(); if (!before.empty() && argumentOrder == '\0') { cerr << "Warning: Assuming argument order " @@ -1851,6 +1842,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, skip_braces(p); } + else if (t.cs() == "newcommand" || + t.cs() == "providecommand" || + t.cs() == "renewcommand") { + // these could be handled by parse_command(), but + // we need to call add_known_command() here. + string name = t.asInput(); + if (p.next_token().asInput() == "*") { + // Starred form. Eat '*' + p.get_token(); + name += '*'; + } + string const command = p.verbatim_item(); + string const opt1 = p.getOpt(); + string const opt2 = p.getFullOpt(); + add_known_command(command, opt1, !opt2.empty()); + string const ert = name + '{' + command + '}' + + opt1 + opt2 + + '{' + p.verbatim_item() + '}'; + handle_ert(os, ert, context); + } + else if (t.cs() == "vspace") { bool starred = false; if (p.next_token().asInput() == "*") { -- 2.39.2