X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetCommandParams.cpp;h=94b9a2c8a2e7897be9fce2d393e36be3ea1db3b0;hb=8124e6c02ea1fd6779bb6c47ffe2bca2c8bd2d97;hp=519e93797d48b25bef86c1d0862b1c4b83bc20e9;hpb=8c351e32be92fca91e2dd1f9ec478d5cb1ce6c8c;p=lyx.git diff --git a/src/insets/InsetCommandParams.cpp b/src/insets/InsetCommandParams.cpp index 519e93797d..94b9a2c8a2 100644 --- a/src/insets/InsetCommandParams.cpp +++ b/src/insets/InsetCommandParams.cpp @@ -5,19 +5,19 @@ * * \author Angus Leeming * \author Georg Baum - * \author Richard Heck + * \author Richard Kimberly Heck * * Full author contact details are available in file CREDITS. */ #include -#include #include "InsetCommandParams.h" #include "InsetBibitem.h" #include "InsetBibtex.h" #include "InsetCitation.h" +#include "InsetCounter.h" #include "InsetFloatList.h" #include "InsetHyperlink.h" #include "InsetInclude.h" @@ -31,7 +31,6 @@ #include "Buffer.h" #include "Encoding.h" #include "Lexer.h" -#include "OutputParams.h" #include "frontends/alert.h" @@ -43,6 +42,9 @@ #include "support/lassert.h" +#include +#include + using namespace std; using namespace lyx::support; @@ -61,6 +63,8 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) return InsetBibtex::findInfo(cmdName); case CITE_CODE: return InsetCitation::findInfo(cmdName); + case COUNTER_CODE: + return InsetCounter::findInfo(cmdName); case FLOAT_LIST_CODE: return InsetFloatList::findInfo(cmdName); case HYPERLINK_CODE: @@ -97,8 +101,10 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) ///////////////////////////////////////////////////////////////////// ParamInfo::ParamData::ParamData(std::string const & s, ParamType t, - ParamHandling h) - : name_(s), type_(t), handling_(h) + ParamHandling h, bool ignore, + docstring default_value) + : name_(s), type_(t), handling_(h), ignore_(ignore), + default_value_(default_value) {} @@ -128,9 +134,10 @@ bool ParamInfo::hasParam(std::string const & name) const void ParamInfo::add(std::string const & name, ParamType type, - ParamHandling handling) -{ - info_.push_back(ParamData(name, type, handling)); + ParamHandling handling, bool ignoreval, + docstring default_value) +{ + info_.push_back(ParamData(name, type, handling, ignoreval, default_value)); } @@ -142,7 +149,7 @@ bool ParamInfo::operator==(ParamInfo const & rhs) const } -ParamInfo::ParamData const & +ParamInfo::ParamData const & ParamInfo::operator[](std::string const & name) const { const_iterator it = begin(); @@ -190,12 +197,14 @@ std::string InsetCommandParams::insetType() const string InsetCommandParams::getDefaultCmd(InsetCode code) { switch (code) { - case BIBITEM_CODE: + case BIBITEM_CODE: return InsetBibitem::defaultCommand(); case BIBTEX_CODE: return InsetBibtex::defaultCommand(); case CITE_CODE: return InsetCitation::defaultCommand(); + case COUNTER_CODE: + return InsetCounter::defaultCommand(); case FLOAT_LIST_CODE: return InsetFloatList::defaultCommand(); case HYPERLINK_CODE: @@ -227,12 +236,14 @@ string InsetCommandParams::getDefaultCmd(InsetCode code) bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s) { switch (code) { - case BIBITEM_CODE: + case BIBITEM_CODE: return InsetBibitem::isCompatibleCommand(s); case BIBTEX_CODE: return InsetBibtex::isCompatibleCommand(s); case CITE_CODE: return InsetCitation::isCompatibleCommand(s); + case COUNTER_CODE: + return InsetCounter::isCompatibleCommand(s); case FLOAT_LIST_CODE: return InsetFloatList::isCompatibleCommand(s); case HYPERLINK_CODE: @@ -264,7 +275,7 @@ bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s) void InsetCommandParams::setCmdName(string const & name) { if (!isCompatibleCommand(insetCode_, name)) { - LYXERR0("InsetCommand: Incompatible command name " << + LYXERR0("InsetCommand: Incompatible command name " << name << "."); throw ExceptionMessage(WarningException, _("InsetCommand Error: "), _("Incompatible command name.")); @@ -276,6 +287,12 @@ void InsetCommandParams::setCmdName(string const & name) void InsetCommandParams::read(Lexer & lex) +{ + Read(lex, nullptr); +} + + +void InsetCommandParams::Read(Lexer & lex, Buffer const * buffer) { lex.setContext("InsetCommandParams::read"); lex >> insetName(insetCode_).c_str(); @@ -288,7 +305,12 @@ void InsetCommandParams::read(Lexer & lex) } 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(); @@ -300,9 +322,27 @@ void InsetCommandParams::read(Lexer & lex) preview_ = lex.getBool(); continue; } - if (info_.hasParam(token)) { + if (hasParam(token)) { lex.next(true); - params_[token] = 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 " + cmdName_); throw ExceptionMessage(WarningException, @@ -322,7 +362,7 @@ void InsetCommandParams::read(Lexer & lex) void InsetCommandParams::write(ostream & os) const { - Write(os, 0); + Write(os, nullptr); } @@ -335,6 +375,8 @@ void InsetCommandParams::Write(ostream & os, Buffer const * buffer) const 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()) { @@ -346,13 +388,15 @@ void InsetCommandParams::Write(ostream & os, Buffer const * buffer) const string newdata; string bib = token(data, ',', i); while (!bib.empty()) { - bib = buffer->includedFilePath(bib); + bib = buffer->includedFilePath(bib, "bib"); if (!newdata.empty()) newdata.append(1, ','); newdata.append(bib); bib = token(data, ',', ++i); } data = newdata; + } else if (buffer && name == "options") { + data = buffer->includedFilePath(data, "bst"); } os << name << ' ' << Lexer::quoteString(data) @@ -395,36 +439,125 @@ docstring InsetCommandParams::prepareCommand(OutputParams const & runparams, ParamInfo::ParamHandling handling) const { docstring result; - switch (handling) { - case ParamInfo::HANDLING_LATEXIFY: { + 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(command, runparams.dryrun); + runparams.encoding->latexString(result, runparams.dryrun); result = command_latexed.first; if (!command_latexed.second.empty()) { - // issue a warning about omitted characters + // 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)); } - break; - } - case ParamInfo::HANDLING_ESCAPE: + // 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); - break; - case ParamInfo::HANDLING_NONE: - result = command; - break; - } // switch + else if (handling & ParamInfo::HANDLING_NONE) { + // we can only output characters covered by the current + // encoding! + docstring uncodable; + for (char_type c : command) { + try { + if (runparams.encoding->encodable(c)) + result += c; + else if (runparams.dryrun) { + result += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + result += docstring(1, c); + result += "'>"; + } else + uncodable += c; + } catch (EncodingException & /* e */) { + if (runparams.dryrun) { + result += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + result += docstring(1, c); + result += "'>"; + } else + uncodable += c; + } + } + if (!uncodable.empty() && !runparams.silent) { + // issue a warning about omitted characters + // FIXME: should be passed to the error dialog + frontend::Alert::warning(_("Uncodable characters in inset"), + bformat(_("The following characters in one of the insets are\n" + "not representable in the current encoding and have been omitted: %1$s.\n" + "Unchecking 'Literal' in the respective inset dialog might help."), + uncodable)); + } + } + // 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]); + } + } - return result; + return ltrimmed ? ltrim(result) : result; } -docstring InsetCommandParams::getCommand(OutputParams const & runparams) const +docstring InsetCommandParams::getCommand(OutputParams const & runparams, bool starred) const { docstring s = '\\' + from_ascii(cmdName_); + if (starred) + s += from_utf8("*"); bool noparam = true; ParamInfo::const_iterator it = info_.begin(); ParamInfo::const_iterator end = info_.end(); @@ -442,17 +575,17 @@ docstring InsetCommandParams::getCommand(OutputParams const & runparams) const break; } case ParamInfo::LATEX_OPTIONAL: { - docstring const data = + docstring data = prepareCommand(runparams, (*this)[name], it->handling()); if (!data.empty()) { - s += '[' + data + ']'; + s += '[' + protectArgument(data) + ']'; noparam = false; } else if (writeEmptyOptional(it)) { s += "[]"; noparam = false; } break; - } + } } //end switch } if (noparam) @@ -465,29 +598,49 @@ docstring InsetCommandParams::getCommand(OutputParams const & runparams) const docstring InsetCommandParams::getFirstNonOptParam() const { - ParamInfo::const_iterator it = - find_if(info_.begin(), info_.end(), - not1(mem_fun_ref(&ParamInfo::ParamData::isOptional))); + ParamInfo::const_iterator it = + find_if(info_.begin(), info_.end(), + [](ParamInfo::ParamData const & d) { return !d.isOptional(); }); LASSERT(it != info_.end(), return docstring()); return (*this)[it->name()]; } +bool InsetCommandParams::hasParam(std::string const & name) const +{ + return info_.hasParam(name); +} + + +docstring const & InsetCommandParams::getParamOr(std::string const & name, docstring const & defaultValue) const +{ + if (hasParam(name)) + return (*this)[name]; + return defaultValue; +} + + docstring const & InsetCommandParams::operator[](string const & name) const { static const docstring dummy; - LASSERT(info_.hasParam(name), return dummy); + LASSERT(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) { - LATTEST(info_.hasParam(name)); + LATTEST(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]; } @@ -495,6 +648,7 @@ docstring & InsetCommandParams::operator[](string const & name) void InsetCommandParams::clear() { params_.clear(); + preview(false); }