+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):
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"
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 << "}"
#include "lyxtextclass.h"
#include "support/path_defines.h"
#include "support/filetools.h"
+#include "support/lstrings.h"
#include "support/lyxlib.h"
#include "support/os.h"
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;
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 {
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();
}
-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) {
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 + ']';
}
#include <vector>
#include <string>
+#include <utility>
enum mode_type {UNDECIDED_MODE, TEXT_MODE, MATH_MODE, MATHTEXT_MODE, TABLE_MODE};
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();
/// 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);
}
}
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);
// 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
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 "
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() == "*") {