2 * \file insetcommandparams.C
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"
19 #include "support/lstrings.h"
21 #include <boost/assert.hpp>
25 using lyx::support::findToken;
32 InsetCommandParams::InsetCommandParams(string const & name)
33 : name_(name), preview_(false)
35 info_ = findInfo(name);
37 params_.resize(info_->n);
41 InsetCommandParams::CommandInfo const *
42 InsetCommandParams::findInfo(std::string const & name)
44 // No parameter may be named "preview", because that is a required
45 // flag for all commands.
48 if (name == "bibitem") {
49 static const char * const paramnames[] = {"label", "key", ""};
50 static const bool isoptional[] = {true, false};
51 static const CommandInfo info = {2, paramnames, isoptional};
56 if (name == "bibtex") {
57 static const char * const paramnames[] =
58 {"options", "btprint", "bibfiles", ""};
59 static const bool isoptional[] = {true, true, false};
60 static const CommandInfo info = {3, paramnames, isoptional};
65 // FIXME: Use is_possible_cite_command() in
66 // src/frontends/controllers/biblio.C, see comment in src/factory.C.
67 if (name == "cite" || name == "citet" || name == "citep" || name == "citealt" ||
68 name == "citealp" || name == "citeauthor" || name == "citeyear" ||
69 name == "citeyearpar" || name == "citet*" || name == "citep*" ||
70 name == "citealt*" || name == "citealp*" ||
71 name == "citeauthor*" || name == "Citet" || name == "Citep" ||
72 name == "Citealt" || name == "Citealp" || name == "Citeauthor" ||
73 name == "Citet*" || name == "Citep*" || name == "Citealt*" ||
74 name == "Citealp*" || name == "Citeauthor*" ||
75 name == "citefield" || name == "citetitle" || name == "cite*") {
76 // standard cite does only take one argument if jurabib is
77 // not used, but jurabib extends this to two arguments, so
78 // we have to allow both here. InsetCitation takes care that
79 // LaTeX output is nevertheless correct.
80 static const char * const paramnames[] =
81 {"after", "before", "key", ""};
82 static const bool isoptional[] = {true, true, false};
83 static const CommandInfo info = {3, paramnames, isoptional};
88 if (name == "floatlist") {
89 static const char * const paramnames[] = {"type", ""};
90 static const bool isoptional[] = {false};
91 static const CommandInfo info = {1, paramnames, isoptional};
96 if (name == "hfill") {
97 static const char * const paramnames[] = {""};
98 static const CommandInfo info = {0, paramnames, 0};
103 if (name == "include" || name == "input" || name == "verbatiminput" ||
104 name == "verbatiminput*") {
105 static const char * const paramnames[] = {"filename", ""};
106 static const bool isoptional[] = {false};
107 static const CommandInfo info = {1, paramnames, isoptional};
111 // InsetIndex, InsetPrintIndex, InsetLabel
112 if (name == "index" || name == "printindex" || name == "label") {
113 static const char * const paramnames[] = {"name", ""};
114 static const bool isoptional[] = {false};
115 static const CommandInfo info = {1, paramnames, isoptional};
120 if (name == "eqref" || name == "pageref" || name == "vpageref" ||
121 name == "vref" || name == "prettyref" || name == "ref") {
122 static const char * const paramnames[] =
123 {"name", "reference", ""};
124 static const bool isoptional[] = {true, false};
125 static const CommandInfo info = {2, paramnames, isoptional};
130 if (name == "tableofcontents") {
131 static const char * const paramnames[] = {"type", ""};
132 static const bool isoptional[] = {false};
133 static const CommandInfo info = {1, paramnames, isoptional};
138 if (name == "htmlurl" || name == "url") {
139 static const char * const paramnames[] =
140 {"name", "target", ""};
141 static const bool isoptional[] = {true, false};
142 static const CommandInfo info = {2, paramnames, isoptional};
150 void InsetCommandParams::setCmdName(string const & name)
153 CommandInfo const * const info = findInfo(name);
155 ParamVector params(info->n);
156 // Overtake parameters with the same name
157 for (size_t i = 0; i < info_->n; ++i) {
158 int j = findToken(info->paramnames, info_->paramnames[i]);
160 params[j] = params_[i];
163 std::swap(params, params_);
167 void InsetCommandParams::scanCommand(string const & cmd)
169 string tcmdname, toptions, tsecoptions, tcontents;
171 if (cmd.empty()) return;
173 enum { WS, CMDNAME, OPTION, SECOPTION, CONTENT } state = WS;
175 // Used to handle things like \command[foo[bar]]{foo{bar}}
178 for (string::size_type i = 0; i < cmd.length(); ++i) {
179 char const c = cmd[i];
180 if ((state == CMDNAME && c == ' ') ||
181 (state == CMDNAME && c == '[') ||
182 (state == CMDNAME && c == '{')) {
185 if ((state == OPTION && c == ']') ||
186 (state == SECOPTION && c == ']') ||
187 (state == CONTENT && c == '}')) {
188 if (nestdepth == 0) {
194 if ((state == OPTION && c == '[') ||
195 (state == SECOPTION && c == '[') ||
196 (state == CONTENT && c == '{')) {
200 case CMDNAME: tcmdname += c; break;
201 case OPTION: toptions += c; break;
202 case SECOPTION: tsecoptions += c; break;
203 case CONTENT: tcontents += c; break;
205 char const b = i? cmd[i-1]: 0;
208 } else if (c == '[' && b != ']') {
210 nestdepth = 0; // Just to be sure
211 } else if (c == '[' && b == ']') {
213 nestdepth = 0; // Just to be sure
214 } else if (c == '{') {
216 nestdepth = 0; // Just to be sure
223 // Don't mess with this.
224 if (!tcmdname.empty()) setCmdName(tcmdname);
225 if (!toptions.empty()) setOptions(toptions);
226 if (!tsecoptions.empty()) setSecOptions(tsecoptions);
227 if (!tcontents.empty()) setContents(tcontents);
229 if (lyxerr.debugging(Debug::PARSER))
230 lyxerr << "Command <" << cmd
231 << "> == <" << lyx::to_utf8(getCommand())
232 << "> == <" << getCmdName()
233 << '|' << getContents()
234 << '|' << getOptions()
235 << '|' << getSecOptions() << '>' << endl;
239 void InsetCommandParams::read(LyXLex & lex)
243 name_ = lex.getString();
244 info_ = findInfo(name_);
246 lex.printError("InsetCommand: Unknown inset name `$$Token'");
252 token = lex.getString();
253 if (token == "\\end_inset")
255 // FIXME Why is preview_ read but not written?
256 if (token == "preview") {
258 preview_ = lex.getBool();
261 int const i = findToken(info_->paramnames, token);
264 params_[i] = lex.getDocString();
266 lex.printError("Unknown parameter name `$$Token' for command " + name_);
268 if (token != "\\end_inset") {
269 lex.printError("Missing \\end_inset at this point. "
275 void InsetCommandParams::write(ostream & os) const
277 os << "LatexCommand " << name_ << '\n';
278 for (size_t i = 0; i < info_->n; ++i)
279 if (!params_[i].empty())
281 os << info_->paramnames[i] << ' '
282 << LyXLex::quoteString(lyx::to_utf8(params_[i]))
287 docstring const InsetCommandParams::getCommand() const
289 docstring s = '\\' + lyx::from_ascii(name_);
290 for (size_t i = 0; i < info_->n; ++i) {
291 if (info_->optional[i]) {
292 if (params_[i].empty()) {
293 // We need to write this parameter even if
294 // it is empty if nonempty optional parameters
295 // follow before the next required parameter.
296 for (size_t j = i + 1; j < info_->n; ++j) {
297 if (!info_->optional[j])
299 if (!params_[j].empty()) {
305 s += '[' + params_[i] + ']';
307 s += '{' + params_[i] + '}';
313 std::string const InsetCommandParams::getOptions() const
315 for (size_t i = 0; i < info_->n; ++i)
316 if (info_->optional[i])
317 return lyx::to_utf8(params_[i]);
318 lyxerr << "Programming error: get nonexisting option in "
319 << name_ << " inset." << endl;;
324 std::string const InsetCommandParams::getSecOptions() const
327 for (size_t i = 0; i < info_->n; ++i)
328 if (info_->optional[i]) {
332 return lyx::to_utf8(params_[i]);
334 // Happens in InsetCitation
335 lyxerr << "Programming error: get nonexisting second option in "
336 << name_ << " inset." << endl;;
341 std::string const InsetCommandParams::getContents() const
343 for (size_t i = 0; i < info_->n; ++i)
344 if (!info_->optional[i])
345 return lyx::to_utf8(params_[i]);
351 void InsetCommandParams::setOptions(std::string const & o)
353 for (size_t i = 0; i < info_->n; ++i)
354 if (info_->optional[i]) {
355 params_[i] = lyx::from_utf8(o);
358 lyxerr << "Programming error: set nonexisting option in "
359 << name_ << " inset." << endl;;
363 void InsetCommandParams::setSecOptions(std::string const & s)
366 for (size_t i = 0; i < info_->n; ++i)
367 if (info_->optional[i]) {
371 params_[i] = lyx::from_utf8(s);
375 // Happens in InsetCitation
376 lyxerr << "Programming error: set nonexisting second option in "
377 << name_ << " inset." << endl;;
381 void InsetCommandParams::setContents(std::string const & c)
383 for (size_t i = 0; i < info_->n; ++i)
384 if (!info_->optional[i]) {
385 params_[i] = lyx::from_utf8(c);
392 docstring const & InsetCommandParams::operator[](string const & name) const
394 int const i = findToken(info_->paramnames, name);
395 BOOST_ASSERT(i >= 0);
400 docstring & InsetCommandParams::operator[](string const & name)
402 int const i = findToken(info_->paramnames, name);
403 BOOST_ASSERT(i >= 0);
408 void InsetCommandParams::clear()
410 for (size_t i = 0; i < info_->n; ++i)
415 bool operator==(InsetCommandParams const & o1,
416 InsetCommandParams const & o2)
418 return o1.name_ == o2.name_ &&
419 o1.info_ == o2.info_ &&
420 o1.params_ == o2.params_ &&
421 o1.preview_ == o2.preview_;
425 bool operator!=(InsetCommandParams const & o1,
426 InsetCommandParams const & o2)