fix bug 1750

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@9444 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Georg Baum 2005-01-06 13:22:20 +00:00
parent 46756fd9e4
commit d7b224d692
7 changed files with 138 additions and 29 deletions

View 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):

View 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 << "}"

View 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 {

View 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();

View 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 + ']';
}

View 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();

View 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() == "*") {