2 * \file InsetCommandParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
14 #include "InsetCommandParams.h"
20 #include "support/ExceptionMessage.h"
21 #include "support/lstrings.h"
23 #include <boost/assert.hpp>
28 using support::findToken;
34 using support::ExceptionMessage;
35 using support::WarningException;
37 InsetCommandParams::InsetCommandParams(string const & name)
38 : name_(name), preview_(false)
40 info_ = findInfo(name);
42 params_.resize(info_->n);
46 InsetCommandParams::CommandInfo const *
47 InsetCommandParams::findInfo(std::string const & name)
49 // No parameter may be named "preview", because that is a required
50 // flag for all commands.
53 if (name == "bibitem") {
54 static const char * const paramnames[] = {"label", "key", ""};
55 static const bool isoptional[] = {true, false};
56 static const CommandInfo info = {2, paramnames, isoptional};
61 if (name == "bibtex") {
62 static const char * const paramnames[] =
63 {"options", "btprint", "bibfiles", ""};
64 static const bool isoptional[] = {true, true, false};
65 static const CommandInfo info = {3, paramnames, isoptional};
70 // FIXME: Use is_possible_cite_command() in
71 // InsetCitation, see comment in src/factory.cpp.
72 if (name == "cite" || name == "citet" || name == "citep" || name == "citealt" ||
73 name == "citealp" || name == "citeauthor" || name == "citeyear" ||
74 name == "citeyearpar" || name == "citet*" || name == "citep*" ||
75 name == "citealt*" || name == "citealp*" ||
76 name == "citeauthor*" || name == "Citet" || name == "Citep" ||
77 name == "Citealt" || name == "Citealp" || name == "Citeauthor" ||
78 name == "Citet*" || name == "Citep*" || name == "Citealt*" ||
79 name == "Citealp*" || name == "Citeauthor*" ||
80 name == "citefield" || name == "citetitle" || name == "cite*") {
81 // standard cite does only take one argument if jurabib is
82 // not used, but jurabib extends this to two arguments, so
83 // we have to allow both here. InsetCitation takes care that
84 // LaTeX output is nevertheless correct.
85 static const char * const paramnames[] =
86 {"after", "before", "key", ""};
87 static const bool isoptional[] = {true, true, false};
88 static const CommandInfo info = {3, paramnames, isoptional};
93 if (name == "floatlist") {
94 static const char * const paramnames[] = {"type", ""};
95 static const bool isoptional[] = {false};
96 static const CommandInfo info = {1, paramnames, isoptional};
101 if (name == "hfill") {
102 static const char * const paramnames[] = {""};
103 static const CommandInfo info = {0, paramnames, 0};
108 if (name == "include" || name == "input" || name == "verbatiminput" ||
109 name == "verbatiminput*") {
110 static const char * const paramnames[] = {"filename", ""};
111 static const bool isoptional[] = {false};
112 static const CommandInfo info = {1, paramnames, isoptional};
116 if (name == "lstinputlisting") {
117 static const char * const paramnames[] = {"filename", "lstparams", ""};
118 static const bool isoptional[] = {false, true};
119 static const CommandInfo info = {2, paramnames, isoptional};
123 // InsetIndex, InsetPrintIndex, InsetLabel
124 if (name == "index" || name == "printindex" || name == "label") {
125 static const char * const paramnames[] = {"name", ""};
126 static const bool isoptional[] = {false};
127 static const CommandInfo info = {1, paramnames, isoptional};
132 if (name == "nomenclature") {
133 static const char * const paramnames[] = {"prefix", "symbol", "description", ""};
134 static const bool isoptional[] = {true, false, false};
135 static const CommandInfo info = {3, paramnames, isoptional};
140 if (name == "printnomenclature") {
141 static const char * const paramnames[] = {"labelwidth", ""};
142 static const bool isoptional[] = {true};
143 static const CommandInfo info = {1, paramnames, isoptional};
148 if (name == "eqref" || name == "pageref" || name == "vpageref" ||
149 name == "vref" || name == "prettyref" || name == "ref") {
150 static const char * const paramnames[] =
151 {"name", "reference", ""};
152 static const bool isoptional[] = {true, false};
153 static const CommandInfo info = {2, paramnames, isoptional};
158 if (name == "tableofcontents") {
159 static const char * const paramnames[] = {"type", ""};
160 static const bool isoptional[] = {false};
161 static const CommandInfo info = {1, paramnames, isoptional};
166 if (name == "htmlurl" || name == "url") {
167 static const char * const paramnames[] =
168 {"name", "target", ""};
169 static const bool isoptional[] = {true, false};
170 static const CommandInfo info = {2, paramnames, isoptional};
178 void InsetCommandParams::setCmdName(string const & name)
181 CommandInfo const * const info = findInfo(name);
183 ParamVector params(info->n);
184 // Overtake parameters with the same name
185 for (size_t i = 0; i < info_->n; ++i) {
186 int j = findToken(info->paramnames, info_->paramnames[i]);
188 params[j] = params_[i];
191 std::swap(params, params_);
195 void InsetCommandParams::scanCommand(string const & cmd)
197 string tcmdname, toptions, tsecoptions, tcontents;
199 if (cmd.empty()) return;
201 enum { WS, CMDNAME, OPTION, SECOPTION, CONTENT } state = WS;
203 // Used to handle things like \command[foo[bar]]{foo{bar}}
206 for (string::size_type i = 0; i < cmd.length(); ++i) {
207 char const c = cmd[i];
208 if ((state == CMDNAME && c == ' ') ||
209 (state == CMDNAME && c == '[') ||
210 (state == CMDNAME && c == '{')) {
213 if ((state == OPTION && c == ']') ||
214 (state == SECOPTION && c == ']') ||
215 (state == CONTENT && c == '}')) {
216 if (nestdepth == 0) {
222 if ((state == OPTION && c == '[') ||
223 (state == SECOPTION && c == '[') ||
224 (state == CONTENT && c == '{')) {
228 case CMDNAME: tcmdname += c; break;
229 case OPTION: toptions += c; break;
230 case SECOPTION: tsecoptions += c; break;
231 case CONTENT: tcontents += c; break;
233 char const b = i? cmd[i-1]: 0;
236 } else if (c == '[' && b != ']') {
238 nestdepth = 0; // Just to be sure
239 } else if (c == '[' && b == ']') {
241 nestdepth = 0; // Just to be sure
242 } else if (c == '{') {
244 nestdepth = 0; // Just to be sure
251 // Don't mess with this.
252 if (!tcmdname.empty()) setCmdName(tcmdname);
253 if (!toptions.empty()) setOptions(toptions);
254 if (!tsecoptions.empty()) setSecOptions(tsecoptions);
255 if (!tcontents.empty()) setContents(tcontents);
257 LYXERR(Debug::PARSER) << "Command <" << cmd
258 << "> == <" << to_utf8(getCommand())
259 << "> == <" << getCmdName()
260 << '|' << getContents()
261 << '|' << getOptions()
262 << '|' << getSecOptions() << '>' << endl;
266 void InsetCommandParams::read(Lexer & lex)
270 name_ = lex.getString();
271 info_ = findInfo(name_);
273 lex.printError("InsetCommand: Unknown inset name `$$Token'");
274 throw ExceptionMessage(WarningException,
275 _("Unknown inset name: "),
283 token = lex.getString();
284 if (token == "\\end_inset")
286 // FIXME Why is preview_ read but not written?
287 if (token == "preview") {
289 preview_ = lex.getBool();
292 int const i = findToken(info_->paramnames, token);
295 params_[i] = lex.getDocString();
297 lex.printError("Unknown parameter name `$$Token' for command " + name_);
298 throw ExceptionMessage(WarningException,
299 _("Inset Command: ") + from_ascii(name_),
300 _("Unknown parameter name: ") + from_utf8(token));
303 if (token != "\\end_inset") {
304 lex.printError("Missing \\end_inset at this point. "
306 throw ExceptionMessage(WarningException,
307 _("Missing \\end_inset at this point."),
313 void InsetCommandParams::write(ostream & os) const
315 os << "LatexCommand " << name_ << '\n';
316 for (size_t i = 0; i < info_->n; ++i)
317 if (!params_[i].empty())
319 os << info_->paramnames[i] << ' '
320 << Lexer::quoteString(to_utf8(params_[i]))
325 docstring const InsetCommandParams::getCommand() const
327 docstring s = '\\' + from_ascii(name_);
329 for (size_t i = 0; i < info_->n; ++i) {
330 if (info_->optional[i]) {
331 if (params_[i].empty()) {
332 // We need to write this parameter even if
333 // it is empty if nonempty optional parameters
334 // follow before the next required parameter.
335 for (size_t j = i + 1; j < info_->n; ++j) {
336 if (!info_->optional[j])
338 if (!params_[j].empty()) {
345 s += '[' + params_[i] + ']';
349 s += '{' + params_[i] + '}';
354 // Make sure that following stuff does not change the
361 std::string const InsetCommandParams::getOptions() const
363 for (size_t i = 0; i < info_->n; ++i)
364 if (info_->optional[i])
365 return to_utf8(params_[i]);
366 lyxerr << "Programming error: get nonexisting option in "
367 << name_ << " inset." << endl;;
372 std::string const InsetCommandParams::getSecOptions() const
375 for (size_t i = 0; i < info_->n; ++i)
376 if (info_->optional[i]) {
380 return to_utf8(params_[i]);
382 // Happens in InsetCitation
383 lyxerr << "Programming error: get nonexisting second option in "
384 << name_ << " inset." << endl;;
389 std::string const InsetCommandParams::getContents() const
391 for (size_t i = 0; i < info_->n; ++i)
392 if (!info_->optional[i])
393 return to_utf8(params_[i]);
399 void InsetCommandParams::setOptions(std::string const & o)
401 for (size_t i = 0; i < info_->n; ++i)
402 if (info_->optional[i]) {
403 params_[i] = from_utf8(o);
406 lyxerr << "Programming error: set nonexisting option in "
407 << name_ << " inset." << endl;;
411 void InsetCommandParams::setSecOptions(std::string const & s)
414 for (size_t i = 0; i < info_->n; ++i)
415 if (info_->optional[i]) {
419 params_[i] = from_utf8(s);
423 // Happens in InsetCitation
424 lyxerr << "Programming error: set nonexisting second option in "
425 << name_ << " inset." << endl;;
429 void InsetCommandParams::setContents(std::string const & c)
431 for (size_t i = 0; i < info_->n; ++i)
432 if (!info_->optional[i]) {
433 params_[i] = from_utf8(c);
440 docstring const & InsetCommandParams::operator[](string const & name) const
442 int const i = findToken(info_->paramnames, name);
443 BOOST_ASSERT(i >= 0);
448 docstring & InsetCommandParams::operator[](string const & name)
450 int const i = findToken(info_->paramnames, name);
451 BOOST_ASSERT(i >= 0);
456 void InsetCommandParams::clear()
458 for (size_t i = 0; i < info_->n; ++i)
463 bool operator==(InsetCommandParams const & o1,
464 InsetCommandParams const & o2)
466 return o1.name_ == o2.name_ &&
467 o1.info_ == o2.info_ &&
468 o1.params_ == o2.params_ &&
469 o1.preview_ == o2.preview_;
473 bool operator!=(InsetCommandParams const & o1,
474 InsetCommandParams const & o2)