X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetCommandParams.cpp;h=24d1afad883008cac73637bfdf2251b5aa28b376;hb=de67b68b1dc140321e5d0e2e6b4507c972703744;hp=2162c98666c43c2208de76fae948c6aebfe458a0;hpb=9b4a26a252b2da164fcd6aa84feed0a738b16c10;p=lyx.git diff --git a/src/insets/InsetCommandParams.cpp b/src/insets/InsetCommandParams.cpp index 2162c98666..24d1afad88 100644 --- a/src/insets/InsetCommandParams.cpp +++ b/src/insets/InsetCommandParams.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "InsetCommandParams.h" @@ -23,11 +25,17 @@ #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" @@ -44,7 +52,6 @@ using namespace lyx::support; namespace lyx { /// Get information for \p code and command \p cmdName. -/// Returns 0 if the combination is not known. [FIXME: 0?] /// 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) @@ -55,7 +62,7 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) case BIBTEX_CODE: return InsetBibtex::findInfo(cmdName); case CITE_CODE: - return InsetCitation::findInfo(cmdName); + return InsetCitation::findInfo(cmdName); case FLOAT_LIST_CODE: return InsetFloatList::findInfo(cmdName); case HYPERLINK_CODE: @@ -65,7 +72,9 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) case INDEX_PRINT_CODE: return InsetPrintIndex::findInfo(cmdName); case LABEL_CODE: - return InsetLabel::findInfo(cmdName); + return InsetLabel::findInfo(cmdName); + case LINE_CODE: + return InsetLine::findInfo(cmdName); case NOMENCL_CODE: return InsetNomencl::findInfo(cmdName); case NOMENCL_PRINT_CODE: @@ -75,10 +84,11 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) case TOC_CODE: return InsetTOC::findInfo(cmdName); default: - LASSERT(false, /**/); + LATTEST(false); + // fall through in release mode } static const ParamInfo pi; - return pi; // to silence the warning + return pi; } @@ -88,8 +98,11 @@ static ParamInfo const & findInfo(InsetCode code, string const & cmdName) // ///////////////////////////////////////////////////////////////////// -ParamInfo::ParamData::ParamData(std::string const & s, ParamType t) - : name_(s), type_(t) +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) {} @@ -101,7 +114,8 @@ bool ParamInfo::ParamData::isOptional() const bool ParamInfo::ParamData::operator==(ParamInfo::ParamData const & rhs) const { - return name() == rhs.name() && type() == rhs.type(); + return name() == rhs.name() && type() == rhs.type() + && handling() == rhs.handling(); } @@ -117,9 +131,11 @@ bool ParamInfo::hasParam(std::string const & name) const } -void ParamInfo::add(std::string const & name, ParamType type) -{ - info_.push_back(ParamData(name, type)); +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)); } @@ -131,17 +147,19 @@ bool ParamInfo::operator==(ParamInfo const & rhs) const } -ParamInfo::ParamData const & +ParamInfo::ParamData const & ParamInfo::operator[](std::string const & name) const { - LASSERT(hasParam(name), /**/); const_iterator it = begin(); const_iterator last = end(); for (; it != last; ++it) { if (it->name() == name) return *it; } - return *it; // silence warning + LATTEST(false); + // we will try to continue in release mode + static const ParamData pd("asdfghjkl", LYX_INTERNAL); + return pd; } @@ -177,7 +195,7 @@ 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(); @@ -193,6 +211,8 @@ string InsetCommandParams::getDefaultCmd(InsetCode 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: @@ -202,16 +222,17 @@ string InsetCommandParams::getDefaultCmd(InsetCode code) case TOC_CODE: return InsetTOC::defaultCommand(); default: - LASSERT(false, /**/); + LATTEST(false); + // fall through in release mode } - return string(); // silence the warning + return string(); } 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); @@ -227,6 +248,8 @@ bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s) 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: @@ -235,17 +258,18 @@ bool InsetCommandParams::isCompatibleCommand(InsetCode code, string const & s) return InsetRef::isCompatibleCommand(s); case TOC_CODE: return InsetTOC::isCompatibleCommand(s); - default: - LASSERT(false, /**/); + default: + LATTEST(false); + // fall through in release mode } - return false; // silence the warning + return false; } void InsetCommandParams::setCmdName(string const & name) { - if (!isCompatibleCommand(insetCode_, cmdName_)) { - LYXERR0("InsetCommand: Incompatible command name " << + if (!isCompatibleCommand(insetCode_, name)) { + LYXERR0("InsetCommand: Incompatible command name " << name << "."); throw ExceptionMessage(WarningException, _("InsetCommand Error: "), _("Incompatible command name.")); @@ -257,6 +281,12 @@ void InsetCommandParams::setCmdName(string const & name) void InsetCommandParams::read(Lexer & lex) +{ + Read(lex, 0); +} + + +void InsetCommandParams::Read(Lexer & lex, Buffer const * buffer) { lex.setContext("InsetCommandParams::read"); lex >> insetName(insetCode_).c_str(); @@ -269,7 +299,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(); @@ -283,7 +318,25 @@ void InsetCommandParams::read(Lexer & lex) } if (info_.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, @@ -295,13 +348,19 @@ void InsetCommandParams::read(Lexer & 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 +{ + Write(os, 0); +} + + +void InsetCommandParams::Write(ostream & os, Buffer const * buffer) const { os << "CommandInset " << insetType() << '\n'; os << "LatexCommand " << cmdName_ << '\n'; @@ -310,12 +369,31 @@ void InsetCommandParams::write(ostream & os) const ParamInfo::const_iterator it = info_.begin(); ParamInfo::const_iterator end = info_.end(); for (; it != end; ++it) { - std::string const & name = it->name(); - docstring const & data = (*this)[name]; + if (it->ignore()) + continue; + string const & name = it->name(); + string data = to_utf8((*this)[name]); if (!data.empty()) { - // FIXME UNICODE + // 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); + } + data = newdata; + } else if (buffer && name == "options") { + data = buffer->includedFilePath(data, "bst"); + } os << name << ' ' - << Lexer::quoteString(to_utf8(data)) + << Lexer::quoteString(data) << '\n'; } } @@ -324,8 +402,8 @@ void InsetCommandParams::write(ostream & os) const bool InsetCommandParams::writeEmptyOptional(ParamInfo::const_iterator ci) const { - if (!ci->isOptional()) - LASSERT(false, /**/); + LASSERT(ci->isOptional(), return false); + ++ci; // we want to start with the next one ParamInfo::const_iterator end = info_.end(); for (; ci != end; ++ci) { @@ -350,7 +428,93 @@ bool InsetCommandParams::writeEmptyOptional(ParamInfo::const_iterator ci) const } -docstring InsetCommandParams::getCommand() const +docstring InsetCommandParams::prepareCommand(OutputParams const & runparams, + docstring const & command, + ParamInfo::ParamHandling handling) const +{ + 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]); + } + } + + return ltrimmed ? ltrim(result) : result; +} + + +docstring InsetCommandParams::getCommand(OutputParams const & runparams) const { docstring s = '\\' + from_ascii(cmdName_); bool noparam = true; @@ -363,22 +527,24 @@ docstring InsetCommandParams::getCommand() const break; case ParamInfo::LATEX_REQUIRED: { - docstring const & data = (*this)[name]; + docstring const data = + prepareCommand(runparams, (*this)[name], it->handling()); s += '{' + data + '}'; noparam = false; break; } case ParamInfo::LATEX_OPTIONAL: { - docstring const & data = (*this)[name]; + 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) @@ -391,29 +557,35 @@ docstring InsetCommandParams::getCommand() const docstring InsetCommandParams::getFirstNonOptParam() const { - ParamInfo::const_iterator it = - find_if(info_.begin(), info_.end(), + ParamInfo::const_iterator it = + find_if(info_.begin(), info_.end(), not1(mem_fun_ref(&ParamInfo::ParamData::isOptional))); - if (it == info_.end()) - LASSERT(false, return docstring()); + LASSERT(it != info_.end(), return docstring()); return (*this)[it->name()]; } docstring const & InsetCommandParams::operator[](string const & name) const { - static const docstring dummy; //so we don't return a ref to temporary + 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) { - LASSERT(info_.hasParam(name), /**/); + 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]; }