X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetCommandParams.cpp;h=24d1afad883008cac73637bfdf2251b5aa28b376;hb=de67b68b1dc140321e5d0e2e6b4507c972703744;hp=d246d62bcab1f33f185e548da68281b558c6b757;hpb=65d89a8af302a1774558a3292e6fa486e09f571c;p=lyx.git diff --git a/src/insets/InsetCommandParams.cpp b/src/insets/InsetCommandParams.cpp index d246d62bca..24d1afad88 100644 --- a/src/insets/InsetCommandParams.cpp +++ b/src/insets/InsetCommandParams.cpp @@ -5,291 +5,342 @@ * * \author Angus Leeming * \author Georg Baum + * \author Richard Heck * * Full author contact details are available in file CREDITS. */ #include +#include +#include -#include "InsetCommandParams.h" -#include "debug.h" -#include "gettext.h" -#include "lyxlex.h" +#include "InsetCommandParams.h" +#include "InsetBibitem.h" +#include "InsetBibtex.h" +#include "InsetCitation.h" +#include "InsetFloatList.h" +#include "InsetHyperlink.h" +#include "InsetInclude.h" +#include "InsetIndex.h" +#include "InsetLabel.h" +#include "InsetLine.h" +#include "InsetNomencl.h" +#include "InsetRef.h" +#include "InsetTOC.h" + +#include "Buffer.h" +#include "Encoding.h" +#include "Lexer.h" +#include "OutputParams.h" + +#include "frontends/alert.h" + +#include "support/debug.h" +#include "support/docstream.h" #include "support/ExceptionMessage.h" +#include "support/gettext.h" #include "support/lstrings.h" -#include +#include "support/lassert.h" + +using namespace std; +using namespace lyx::support; namespace lyx { -using support::findToken; +/// Get information for \p code and command \p cmdName. +/// Don't call this without first making sure the command name is +/// acceptable to the inset. +static ParamInfo const & findInfo(InsetCode code, string const & cmdName) +{ + switch (code) { + case BIBITEM_CODE: + return InsetBibitem::findInfo(cmdName); + case BIBTEX_CODE: + return InsetBibtex::findInfo(cmdName); + case CITE_CODE: + return InsetCitation::findInfo(cmdName); + case FLOAT_LIST_CODE: + return InsetFloatList::findInfo(cmdName); + case HYPERLINK_CODE: + return InsetHyperlink::findInfo(cmdName); + case INCLUDE_CODE: + return InsetInclude::findInfo(cmdName); + case INDEX_PRINT_CODE: + return InsetPrintIndex::findInfo(cmdName); + case LABEL_CODE: + return InsetLabel::findInfo(cmdName); + case LINE_CODE: + return InsetLine::findInfo(cmdName); + case NOMENCL_CODE: + return InsetNomencl::findInfo(cmdName); + case NOMENCL_PRINT_CODE: + return InsetPrintNomencl::findInfo(cmdName); + case REF_CODE: + return InsetRef::findInfo(cmdName); + case TOC_CODE: + return InsetTOC::findInfo(cmdName); + default: + LATTEST(false); + // fall through in release mode + } + static const ParamInfo pi; + return pi; +} + -using std::string; -using std::endl; -using std::ostream; +///////////////////////////////////////////////////////////////////// +// +// ParamInfo::ParamData +// +///////////////////////////////////////////////////////////////////// -using support::ExceptionMessage; -using support::WarningException; +ParamInfo::ParamData::ParamData(std::string const & s, ParamType t, + ParamHandling h, bool ignore, + docstring default_value) + : name_(s), type_(t), handling_(h), ignore_(ignore), + default_value_(default_value) +{} -InsetCommandParams::InsetCommandParams(string const & name) - : name_(name), preview_(false) + +bool ParamInfo::ParamData::isOptional() const { - info_ = findInfo(name); - BOOST_ASSERT(info_); - params_.resize(info_->n); + return type_ == ParamInfo::LATEX_OPTIONAL; } -InsetCommandParams::CommandInfo const * -InsetCommandParams::findInfo(std::string const & name) +bool ParamInfo::ParamData::operator==(ParamInfo::ParamData const & rhs) const { - // No parameter may be named "preview", because that is a required - // flag for all commands. - - // InsetBibitem - if (name == "bibitem") { - static const char * const paramnames[] = {"label", "key", ""}; - static const bool isoptional[] = {true, false}; - static const CommandInfo info = {2, paramnames, isoptional}; - return &info; - } + return name() == rhs.name() && type() == rhs.type() + && handling() == rhs.handling(); +} - // InsetBibtex - if (name == "bibtex") { - static const char * const paramnames[] = - {"options", "btprint", "bibfiles", ""}; - static const bool isoptional[] = {true, true, false}; - static const CommandInfo info = {3, paramnames, isoptional}; - return &info; - } - // InsetCitation - // FIXME: Use is_possible_cite_command() in - // src/frontends/controllers/frontend_helpers.cpp, see comment in src/factory.C. - if (name == "cite" || name == "citet" || name == "citep" || name == "citealt" || - name == "citealp" || name == "citeauthor" || name == "citeyear" || - name == "citeyearpar" || name == "citet*" || name == "citep*" || - name == "citealt*" || name == "citealp*" || - name == "citeauthor*" || name == "Citet" || name == "Citep" || - name == "Citealt" || name == "Citealp" || name == "Citeauthor" || - name == "Citet*" || name == "Citep*" || name == "Citealt*" || - name == "Citealp*" || name == "Citeauthor*" || - name == "citefield" || name == "citetitle" || name == "cite*") { - // standard cite does only take one argument if jurabib is - // not used, but jurabib extends this to two arguments, so - // we have to allow both here. InsetCitation takes care that - // LaTeX output is nevertheless correct. - static const char * const paramnames[] = - {"after", "before", "key", ""}; - static const bool isoptional[] = {true, true, false}; - static const CommandInfo info = {3, paramnames, isoptional}; - return &info; +bool ParamInfo::hasParam(std::string const & name) const +{ + const_iterator it = begin(); + const_iterator last = end(); + for (; it != last; ++it) { + if (it->name() == name) + return true; } + return false; +} - // InsetFloatlist - if (name == "floatlist") { - static const char * const paramnames[] = {"type", ""}; - static const bool isoptional[] = {false}; - static const CommandInfo info = {1, paramnames, isoptional}; - return &info; - } - // InsetHfill - if (name == "hfill") { - static const char * const paramnames[] = {""}; - static const CommandInfo info = {0, paramnames, 0}; - return &info; - } +void ParamInfo::add(std::string const & name, ParamType type, + ParamHandling handling, bool ignoreval, + docstring default_value) +{ + info_.push_back(ParamData(name, type, handling, ignoreval, default_value)); +} - // InsetInclude - if (name == "include" || name == "input" || name == "verbatiminput" || - name == "verbatiminput*") { - static const char * const paramnames[] = {"filename", ""}; - static const bool isoptional[] = {false}; - static const CommandInfo info = {1, paramnames, isoptional}; - return &info; - } - // InsetIndex, InsetPrintIndex, InsetLabel - if (name == "index" || name == "printindex" || name == "label") { - static const char * const paramnames[] = {"name", ""}; - static const bool isoptional[] = {false}; - static const CommandInfo info = {1, paramnames, isoptional}; - return &info; - } +bool ParamInfo::operator==(ParamInfo const & rhs) const +{ + if (size() != rhs.size()) + return false; + return equal(begin(), end(), rhs.begin()); +} - // InsetNomencl - if (name == "nomenclature") { - static const char * const paramnames[] = {"prefix", "symbol", "description", ""}; - static const bool isoptional[] = {true, false, false}; - static const CommandInfo info = {3, paramnames, isoptional}; - return &info; - } - // InsetPrintNomencl - if (name == "printnomenclature") { - static const char * const paramnames[] = {"labelwidth", ""}; - static const bool isoptional[] = {true}; - static const CommandInfo info = {1, paramnames, isoptional}; - return &info; +ParamInfo::ParamData const & + ParamInfo::operator[](std::string const & name) const +{ + const_iterator it = begin(); + const_iterator last = end(); + for (; it != last; ++it) { + if (it->name() == name) + return *it; } + LATTEST(false); + // we will try to continue in release mode + static const ParamData pd("asdfghjkl", LYX_INTERNAL); + return pd; +} - // InsetRef - if (name == "eqref" || name == "pageref" || name == "vpageref" || - name == "vref" || name == "prettyref" || name == "ref") { - static const char * const paramnames[] = - {"name", "reference", ""}; - static const bool isoptional[] = {true, false}; - static const CommandInfo info = {2, paramnames, isoptional}; - return &info; - } - // InsetTOC - if (name == "tableofcontents") { - static const char * const paramnames[] = {"type", ""}; - static const bool isoptional[] = {false}; - static const CommandInfo info = {1, paramnames, isoptional}; - return &info; - } +///////////////////////////////////////////////////////////////////// +// +// InsetCommandParams +// +///////////////////////////////////////////////////////////////////// - // InsetUrl - if (name == "htmlurl" || name == "url") { - static const char * const paramnames[] = - {"name", "target", ""}; - static const bool isoptional[] = {true, false}; - static const CommandInfo info = {2, paramnames, isoptional}; - return &info; - } - return 0; +InsetCommandParams::InsetCommandParams(InsetCode code) + : insetCode_(code), preview_(false) +{ + cmdName_ = getDefaultCmd(code); + info_ = findInfo(code, cmdName_); } -void InsetCommandParams::setCmdName(string const & name) +InsetCommandParams::InsetCommandParams(InsetCode code, + string const & cmdName) + : insetCode_(code), cmdName_(cmdName), preview_(false) { - name_ = name; - CommandInfo const * const info = findInfo(name); - BOOST_ASSERT(info); - ParamVector params(info->n); - // Overtake parameters with the same name - for (size_t i = 0; i < info_->n; ++i) { - int j = findToken(info->paramnames, info_->paramnames[i]); - if (j >= 0) - params[j] = params_[i]; - } - info_ = info; - std::swap(params, params_); + info_ = findInfo(code, cmdName); } -void InsetCommandParams::scanCommand(string const & cmd) +std::string InsetCommandParams::insetType() const { - string tcmdname, toptions, tsecoptions, tcontents; + return insetName(insetCode_); +} - if (cmd.empty()) return; - enum { WS, CMDNAME, OPTION, SECOPTION, CONTENT } state = WS; +string InsetCommandParams::getDefaultCmd(InsetCode code) +{ + switch (code) { + case BIBITEM_CODE: + return InsetBibitem::defaultCommand(); + case BIBTEX_CODE: + return InsetBibtex::defaultCommand(); + case CITE_CODE: + return InsetCitation::defaultCommand(); + case FLOAT_LIST_CODE: + return InsetFloatList::defaultCommand(); + case HYPERLINK_CODE: + return InsetHyperlink::defaultCommand(); + case INCLUDE_CODE: + return InsetInclude::defaultCommand(); + case INDEX_PRINT_CODE: + return InsetPrintIndex::defaultCommand(); + case LABEL_CODE: + return InsetLabel::defaultCommand(); + case LINE_CODE: + return InsetLine::defaultCommand(); + case NOMENCL_CODE: + return InsetNomencl::defaultCommand(); + case NOMENCL_PRINT_CODE: + return InsetPrintNomencl::defaultCommand(); + case REF_CODE: + return InsetRef::defaultCommand(); + case TOC_CODE: + return InsetTOC::defaultCommand(); + default: + LATTEST(false); + // fall through in release mode + } + return string(); +} - // Used to handle things like \command[foo[bar]]{foo{bar}} - int nestdepth = 0; - for (string::size_type i = 0; i < cmd.length(); ++i) { - char const c = cmd[i]; - if ((state == CMDNAME && c == ' ') || - (state == CMDNAME && c == '[') || - (state == CMDNAME && c == '{')) { - state = WS; - } - if ((state == OPTION && c == ']') || - (state == SECOPTION && c == ']') || - (state == CONTENT && c == '}')) { - if (nestdepth == 0) { - state = WS; - } else { - --nestdepth; - } - } - if ((state == OPTION && c == '[') || - (state == SECOPTION && c == '[') || - (state == CONTENT && c == '{')) { - ++nestdepth; - } - switch (state) { - case CMDNAME: tcmdname += c; break; - case OPTION: toptions += c; break; - case SECOPTION: tsecoptions += c; break; - case CONTENT: tcontents += c; break; - case WS: { - char const b = i? cmd[i-1]: 0; - if (c == '\\') { - state = CMDNAME; - } else if (c == '[' && b != ']') { - state = OPTION; - nestdepth = 0; // Just to be sure - } else if (c == '[' && b == ']') { - state = SECOPTION; - nestdepth = 0; // Just to be sure - } else if (c == '{') { - state = CONTENT; - nestdepth = 0; // Just to be sure - } - break; - } - } +bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s) +{ + switch (code) { + case BIBITEM_CODE: + return InsetBibitem::isCompatibleCommand(s); + case BIBTEX_CODE: + return InsetBibtex::isCompatibleCommand(s); + case CITE_CODE: + return InsetCitation::isCompatibleCommand(s); + case FLOAT_LIST_CODE: + return InsetFloatList::isCompatibleCommand(s); + case HYPERLINK_CODE: + return InsetHyperlink::isCompatibleCommand(s); + case INCLUDE_CODE: + return InsetInclude::isCompatibleCommand(s); + case INDEX_PRINT_CODE: + return InsetPrintIndex::isCompatibleCommand(s); + case LABEL_CODE: + return InsetLabel::isCompatibleCommand(s); + case LINE_CODE: + return InsetLine::isCompatibleCommand(s); + case NOMENCL_CODE: + return InsetNomencl::isCompatibleCommand(s); + case NOMENCL_PRINT_CODE: + return InsetPrintNomencl::isCompatibleCommand(s); + case REF_CODE: + return InsetRef::isCompatibleCommand(s); + case TOC_CODE: + return InsetTOC::isCompatibleCommand(s); + default: + LATTEST(false); + // fall through in release mode } + return false; +} - // Don't mess with this. - if (!tcmdname.empty()) setCmdName(tcmdname); - if (!toptions.empty()) setOptions(toptions); - if (!tsecoptions.empty()) setSecOptions(tsecoptions); - if (!tcontents.empty()) setContents(tcontents); - - LYXERR(Debug::PARSER) << "Command <" << cmd - << "> == <" << to_utf8(getCommand()) - << "> == <" << getCmdName() - << '|' << getContents() - << '|' << getOptions() - << '|' << getSecOptions() << '>' << endl; + +void InsetCommandParams::setCmdName(string const & name) +{ + if (!isCompatibleCommand(insetCode_, name)) { + LYXERR0("InsetCommand: Incompatible command name " << + name << "."); + throw ExceptionMessage(WarningException, _("InsetCommand Error: "), + _("Incompatible command name.")); + } + + cmdName_ = name; + info_ = findInfo(insetCode_, cmdName_); } -void InsetCommandParams::read(LyXLex & lex) +void InsetCommandParams::read(Lexer & lex) { - if (lex.isOK()) { - lex.next(); - name_ = lex.getString(); - info_ = findInfo(name_); - if (!info_) { - lex.printError("InsetCommand: Unknown inset name `$$Token'"); - throw ExceptionMessage(WarningException, - _("Unknown inset name: "), - from_utf8(name_)); - } + Read(lex, 0); +} + + +void InsetCommandParams::Read(Lexer & lex, Buffer const * buffer) +{ + lex.setContext("InsetCommandParams::read"); + lex >> insetName(insetCode_).c_str(); + lex >> "LatexCommand"; + lex >> cmdName_; + if (!isCompatibleCommand(insetCode_, cmdName_)) { + lex.printError("Incompatible command name " + cmdName_ + "."); + throw ExceptionMessage(WarningException, _("InsetCommandParams Error: "), + _("Incompatible command name.")); } + info_ = findInfo(insetCode_, cmdName_); + + for (ParamInfo::ParamData const & param : info_) + if (param.ignore()) { + params_[param.name()] = param.defaultValue(); + } + string token; while (lex.isOK()) { lex.next(); token = lex.getString(); if (token == "\\end_inset") break; - // FIXME Why is preview_ read but not written? if (token == "preview") { lex.next(); preview_ = lex.getBool(); continue; } - int const i = findToken(info_->paramnames, token); - if (i >= 0) { + if (info_.hasParam(token)) { lex.next(true); - params_[i] = lex.getDocString(); + docstring data = lex.getDocString(); + if (buffer && token == "filename") { + data = from_utf8(buffer->includedFilePath(to_utf8(data))); + } else if (buffer && token == "bibfiles") { + int i = 0; + docstring newdata; + docstring bib = support::token(data, ',', i); + while (!bib.empty()) { + bib = from_utf8(buffer->includedFilePath(to_utf8(bib), "bib")); + if (!newdata.empty()) + newdata.append(1, ','); + newdata.append(bib); + bib = support::token(data, ',', ++i); + } + data = newdata; + } else if (buffer && token == "options") { + data = from_utf8(buffer->includedFilePath(to_utf8(data), "bst")); + } + params_[token] = data; } else { - lex.printError("Unknown parameter name `$$Token' for command " + name_); + lex.printError("Unknown parameter name `$$Token' for command " + cmdName_); throw ExceptionMessage(WarningException, - _("Inset Command: ") + from_ascii(name_), + _("InsetCommandParams: ") + from_ascii(cmdName_), _("Unknown parameter name: ") + from_utf8(token)); } } @@ -297,174 +348,265 @@ void InsetCommandParams::read(LyXLex & lex) lex.printError("Missing \\end_inset at this point. " "Read: `$$Token'"); throw ExceptionMessage(WarningException, - _("Missing \\end_inset at this point."), - from_utf8(token)); + _("InsetCommandParams Error: "), + _("Missing \\end_inset at this point: ") + from_utf8(token)); } } void InsetCommandParams::write(ostream & os) const { - os << "LatexCommand " << name_ << '\n'; - for (size_t i = 0; i < info_->n; ++i) - if (!params_[i].empty()) - // FIXME UNICODE - os << info_->paramnames[i] << ' ' - << LyXLex::quoteString(to_utf8(params_[i])) - << '\n'; + Write(os, 0); } -docstring const InsetCommandParams::getCommand() const +void InsetCommandParams::Write(ostream & os, Buffer const * buffer) const { - docstring s = '\\' + from_ascii(name_); - bool noparam = true; - for (size_t i = 0; i < info_->n; ++i) { - if (info_->optional[i]) { - if (params_[i].empty()) { - // We need to write this parameter even if - // it is empty if nonempty optional parameters - // follow before the next required parameter. - for (size_t j = i + 1; j < info_->n; ++j) { - if (!info_->optional[j]) - break; - if (!params_[j].empty()) { - s += "[]"; - noparam = false; - break; - } + os << "CommandInset " << insetType() << '\n'; + os << "LatexCommand " << cmdName_ << '\n'; + if (preview_) + os << "preview true\n"; + ParamInfo::const_iterator it = info_.begin(); + ParamInfo::const_iterator end = info_.end(); + for (; it != end; ++it) { + if (it->ignore()) + continue; + string const & name = it->name(); + string data = to_utf8((*this)[name]); + if (!data.empty()) { + // Adjust path of files if document was moved + if (buffer && name == "filename") { + data = buffer->includedFilePath(data); + } else if (buffer && name == "bibfiles") { + int i = 0; + string newdata; + string bib = token(data, ',', i); + while (!bib.empty()) { + bib = buffer->includedFilePath(bib, "bib"); + if (!newdata.empty()) + newdata.append(1, ','); + newdata.append(bib); + bib = token(data, ',', ++i); } - } else { - s += '[' + params_[i] + ']'; - noparam = false; + data = newdata; + } else if (buffer && name == "options") { + data = buffer->includedFilePath(data, "bst"); } - } else { - s += '{' + params_[i] + '}'; - noparam = false; + os << name << ' ' + << Lexer::quoteString(data) + << '\n'; } } - if (noparam) - // Make sure that following stuff does not change the - // command name. - s += "{}"; - return s; } -std::string const InsetCommandParams::getOptions() const +bool InsetCommandParams::writeEmptyOptional(ParamInfo::const_iterator ci) const { - for (size_t i = 0; i < info_->n; ++i) - if (info_->optional[i]) - return to_utf8(params_[i]); - lyxerr << "Programming error: get nonexisting option in " - << name_ << " inset." << endl;; - return string(); -} + LASSERT(ci->isOptional(), return false); + ++ci; // we want to start with the next one + ParamInfo::const_iterator end = info_.end(); + for (; ci != end; ++ci) { + switch (ci->type()) { + case ParamInfo::LYX_INTERNAL: + break; -std::string const InsetCommandParams::getSecOptions() const -{ - bool first = true; - for (size_t i = 0; i < info_->n; ++i) - if (info_->optional[i]) { - if (first) - first = false; - else - return to_utf8(params_[i]); - } - // Happens in InsetCitation - lyxerr << "Programming error: get nonexisting second option in " - << name_ << " inset." << endl;; - return string(); -} + case ParamInfo::LATEX_REQUIRED: + return false; + case ParamInfo::LATEX_OPTIONAL: { + std::string const & name = ci->name(); + docstring const & data = (*this)[name]; + if (!data.empty()) + return true; + break; + } -std::string const InsetCommandParams::getContents() const -{ - for (size_t i = 0; i < info_->n; ++i) - if (!info_->optional[i]) - return to_utf8(params_[i]); - BOOST_ASSERT(false); - return string(); + } //end switch + } + return false; } -void InsetCommandParams::setOptions(std::string const & o) +docstring InsetCommandParams::prepareCommand(OutputParams const & runparams, + docstring const & command, + ParamInfo::ParamHandling handling) const { - for (size_t i = 0; i < info_->n; ++i) - if (info_->optional[i]) { - params_[i] = from_utf8(o); - return; + docstring result; + bool ltrimmed = false; + // Trimming can be done on top of any of the other handlings + // We check this here since handling might be changed below. + if (handling & ParamInfo::HANDLING_LTRIM) { + // this is used if no other handling is done + result = command; + ltrimmed = true; + } + if (handling & ParamInfo::HANDLING_LATEXIFY + || handling & ParamInfo::HANDLING_INDEX_ESCAPE) + if ((*this)["literal"] == "true") + handling = ParamInfo::HANDLING_NONE; + + // LATEXIFY, ESCAPE and NONE are mutually exclusive + if (handling & ParamInfo::HANDLING_LATEXIFY) { + // First handle backslash + result = subst(command, from_ascii("\\"), from_ascii("\\textbackslash{}")); + // Then get LaTeX macros + pair command_latexed = + runparams.encoding->latexString(result, runparams.dryrun); + result = command_latexed.first; + if (!command_latexed.second.empty()) { + // Issue a warning about omitted characters + // FIXME: should be passed to the error dialog + frontend::Alert::warning(_("Uncodable characters"), + bformat(_("The following characters that are used in the inset %1$s are not\n" + "representable in the current encoding and therefore have been omitted:\n%2$s."), + from_utf8(insetType()), command_latexed.second)); + } + // Now escape special commands + static docstring const backslash = from_ascii("\\"); + int const nchars_escape = 8; + static char_type const chars_escape[nchars_escape] = { + '&', '_', '$', '%', '#', '^', '{', '}'}; + + if (!result.empty()) { + int previous; + // The characters in chars_name[] need to be changed to a command when + // they are LaTeXified. + for (int k = 0; k < nchars_escape; k++) + for (size_t i = 0, pos; + (pos = result.find(chars_escape[k], i)) != string::npos; + i = pos + 2) { + //(Only) \\^ needs to be terminated + docstring const term = (k == 5) ? from_ascii("{}") : docstring(); + if (pos == 0) + previous = 0; + else + previous = pos - 1; + // only if not already escaped + if (result[previous] != '\\') + result.replace(pos, 1, backslash + chars_escape[k] + term); + } + } + } + else if (handling & ParamInfo::HANDLING_ESCAPE) + result = escape(command); + else if (handling & ParamInfo::HANDLING_NONE) + result = command; + // INDEX_ESCAPE is independent of the others + if (handling & ParamInfo::HANDLING_INDEX_ESCAPE) { + // Now escape special commands + static docstring const quote = from_ascii("\""); + int const nchars_escape = 4; + static char_type const chars_escape[nchars_escape] = { '"', '@', '|', '!' }; + + if (!result.empty()) { + // The characters in chars_name[] need to be changed to a command when + // they are LaTeXified. + for (int k = 0; k < nchars_escape; k++) + for (size_t i = 0, pos; + (pos = result.find(chars_escape[k], i)) != string::npos; + i = pos + 2) + result.replace(pos, 1, quote + chars_escape[k]); } - lyxerr << "Programming error: set nonexisting option in " - << name_ << " inset." << endl;; + } + + return ltrimmed ? ltrim(result) : result; } -void InsetCommandParams::setSecOptions(std::string const & s) +docstring InsetCommandParams::getCommand(OutputParams const & runparams) const { - bool first = true; - for (size_t i = 0; i < info_->n; ++i) - if (info_->optional[i]) { - if (first) - first = false; - else { - params_[i] = from_utf8(s); - return; + docstring s = '\\' + from_ascii(cmdName_); + bool noparam = true; + ParamInfo::const_iterator it = info_.begin(); + ParamInfo::const_iterator end = info_.end(); + for (; it != end; ++it) { + std::string const & name = it->name(); + switch (it->type()) { + case ParamInfo::LYX_INTERNAL: + break; + + case ParamInfo::LATEX_REQUIRED: { + docstring const data = + prepareCommand(runparams, (*this)[name], it->handling()); + s += '{' + data + '}'; + noparam = false; + break; + } + case ParamInfo::LATEX_OPTIONAL: { + docstring data = + prepareCommand(runparams, (*this)[name], it->handling()); + if (!data.empty()) { + s += '[' + protectArgument(data) + ']'; + noparam = false; + } else if (writeEmptyOptional(it)) { + s += "[]"; + noparam = false; } + break; } - // Happens in InsetCitation - lyxerr << "Programming error: set nonexisting second option in " - << name_ << " inset." << endl;; + } //end switch + } + if (noparam) + // Make sure that following stuff does not change the + // command name. + s += "{}"; + return s; } -void InsetCommandParams::setContents(std::string const & c) +docstring InsetCommandParams::getFirstNonOptParam() const { - for (size_t i = 0; i < info_->n; ++i) - if (!info_->optional[i]) { - params_[i] = from_utf8(c); - return; - } - BOOST_ASSERT(false); + ParamInfo::const_iterator it = + find_if(info_.begin(), info_.end(), + not1(mem_fun_ref(&ParamInfo::ParamData::isOptional))); + LASSERT(it != info_.end(), return docstring()); + return (*this)[it->name()]; } docstring const & InsetCommandParams::operator[](string const & name) const { - int const i = findToken(info_->paramnames, name); - BOOST_ASSERT(i >= 0); - return params_[i]; + static const docstring dummy; + LASSERT(info_.hasParam(name), return dummy); + ParamMap::const_iterator data = params_.find(name); + if (data == params_.end() || data->second.empty()) + return dummy; + ParamInfo::ParamData const & param = info_[name]; + if (param.ignore()) + return param.defaultValue(); + return data->second; } docstring & InsetCommandParams::operator[](string const & name) { - int const i = findToken(info_->paramnames, name); - BOOST_ASSERT(i >= 0); - return params_[i]; + LATTEST(info_.hasParam(name)); + // this will add the name in release mode + ParamInfo::ParamData const & param = info_[name]; + if (param.ignore()) + params_[name] = param.defaultValue(); + return params_[name]; } void InsetCommandParams::clear() { - for (size_t i = 0; i < info_->n; ++i) - params_[i].clear(); + params_.clear(); } -bool operator==(InsetCommandParams const & o1, - InsetCommandParams const & o2) +bool operator==(InsetCommandParams const & o1, InsetCommandParams const & o2) { - return o1.name_ == o2.name_ && - o1.info_ == o2.info_ && - o1.params_ == o2.params_ && - o1.preview_ == o2.preview_; + return o1.insetCode_ == o2.insetCode_ + && o1.cmdName_ == o2.cmdName_ + && o1.info_ == o2.info_ + && o1.params_ == o2.params_ + && o1.preview_ == o2.preview_; } -bool operator!=(InsetCommandParams const & o1, - InsetCommandParams const & o2) +bool operator!=(InsetCommandParams const & o1, InsetCommandParams const & o2) { return !(o1 == o2); }