]> git.lyx.org Git - features.git/commitdiff
fix bug 1750
authorGeorg Baum <Georg.Baum@post.rwth-aachen.de>
Thu, 6 Jan 2005 13:22:20 +0000 (13:22 +0000)
committerGeorg Baum <Georg.Baum@post.rwth-aachen.de>
Thu, 6 Jan 2005 13:22:20 +0000 (13:22 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@9444 a592a061-630c-0410-9148-cb99ea01b6c8

src/tex2lyx/ChangeLog
src/tex2lyx/preamble.C
src/tex2lyx/tex2lyx.C
src/tex2lyx/tex2lyx.h
src/tex2lyx/texparser.C
src/tex2lyx/texparser.h
src/tex2lyx/text.C

index 3755bf9c85898b302b4bbf2508d04a718a5f235b..40b8d8b5ea53294065b1d8938ff69a89321a0a2b 100644 (file)
@@ -1,3 +1,17 @@
+2005-01-04  Georg Baum  <Georg.Baum@post.rwth-aachen.de>
+
+       * 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  <Georg.Baum@post.rwth-aachen.de>
 
        * table.C (ColInfo, LTRowType, RowInfo, CellInfo, verbose_align):
index c9b4011e194cbc14eb81eef4b5d18e5b8463ead6..449d9b9c26460068709a68257a8fae4d431b654c 100644 (file)
@@ -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 << "}"
index 963f544951612d5be39e4388e872d52f348e84c4..62c99b4922f3f737b040a1383d66f8121bf396ce 100644 (file)
@@ -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<string, vector<ArgumentType> > 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<ArgumentType> 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 {
 
 
index 37df12686895a7f57bdbf3863e102c2c61e7405c..adf77034a58c78fecba10d9df9774214de2f25b3 100644 (file)
@@ -62,6 +62,15 @@ std::string join(std::vector<std::string> 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<std::string> active_environments;
 std::string active_environment();
index 014c9a798f06edad9d82f01af3b8ae0881f79e2e..8a17a47d33b897e9cd34a09e17790148c87cf153 100644 (file)
@@ -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 + ']';
 }
 
 
index 6ab9946bbb4b9c3bc0b606c0b4a7327044a367cd..0fc250e14f11a29b0c1aa463705c4b968b6d194a 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <vector>
 #include <string>
+#include <utility>
 
 
 enum mode_type {UNDECIDED_MODE, TEXT_MODE, MATH_MODE, MATHTEXT_MODE, TABLE_MODE};
@@ -127,8 +128,27 @@ public:
        void dump() const;
 
        ///
+       typedef std::pair<bool, std::string> 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();
index d1244bdd1ec3fee234afb773907fe1e411a61174..1002b99b4b7014b97bbbc36cbd32b9d56525db9c 100644 (file)
@@ -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<string, string> getCiteArguments(Parser & p, ostream & os,
-                                          Context & context, bool natbibOrder)
+std::pair<string, string> 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() == "*") {