X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Finsets%2FInsetQuotes.cpp;h=49922943c255dd6681e155a6fc11110596fa0dc3;hb=88e5e5fd345c280b0927ad84785657cbc9e55f77;hp=bc5d6d527f832a3e57e68c66f893f6d944aa997e;hpb=89ce0c9069d36748bea0701c52225a32d5e5d66b;p=lyx.git diff --git a/src/insets/InsetQuotes.cpp b/src/insets/InsetQuotes.cpp index bc5d6d527f..49922943c2 100644 --- a/src/insets/InsetQuotes.cpp +++ b/src/insets/InsetQuotes.cpp @@ -41,6 +41,7 @@ #include "support/docstream.h" #include "support/gettext.h" #include "support/lstrings.h" +#include "support/textutils.h" #include @@ -74,7 +75,7 @@ char const * const style_char = "esgpcaqbwfirjkx"; char const * const side_char = "lr" ; char const * const level_char = "sd"; -} // namespace anon +} // namespace ///////////////////////////////////////////////////////////////////// @@ -92,6 +93,111 @@ int InsetQuotesParams::stylescount() const } +char InsetQuotesParams::getStyleChar(QuoteStyle const & style) const +{ + return style_char[style]; +} + + +InsetQuotesParams::QuoteStyle InsetQuotesParams::getQuoteStyle(string const & s, + bool const allow_wildcards, QuoteStyle fb) +{ + QuoteStyle res = fb; + + string str = s; + if (str.length() != 3) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad string length."); + str = "eld"; + } + + int i; + + // '.' wildcard means: keep current style + if (!allow_wildcards || str[0] != '.') { + for (i = 0; i < stylescount(); ++i) { + if (str[0] == style_char[i]) { + res = QuoteStyle(i); + break; + } + } + if (i >= stylescount()) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad style specification."); + res = EnglishQuotes; + } + } + + return res; +} + + +InsetQuotesParams::QuoteSide InsetQuotesParams::getQuoteSide(string const & s, + bool const allow_wildcards, QuoteSide fb) +{ + QuoteSide res = fb; + + string str = s; + if (str.length() != 3) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad string length."); + str = "eld"; + } + + int i; + + // '.' wildcard means: keep current side + if (!allow_wildcards || str[1] != '.') { + for (i = 0; i < 2; ++i) { + if (str[1] == side_char[i]) { + res = InsetQuotesParams::QuoteSide(i); + break; + } + } + if (i >= 2) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad side specification."); + res = OpeningQuote; + } + } + + return res; +} + + +InsetQuotesParams::QuoteLevel InsetQuotesParams::getQuoteLevel(string const & s, + bool const allow_wildcards, QuoteLevel fb) +{ + QuoteLevel res = fb; + + string str = s; + if (str.length() != 3) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad string length."); + str = "eld"; + } + + int i; + + // '.' wildcard means: keep current level + if (!allow_wildcards || str[2] != '.') { + for (i = 0; i < 2; ++i) { + if (str[2] == level_char[i]) { + res = InsetQuotesParams::QuoteLevel(i); + break; + } + } + if (i >= 2) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad level specification."); + res = InsetQuotesParams::PrimaryQuotes; + } + } + + return res; +} + + char_type InsetQuotesParams::getQuoteChar(QuoteStyle const & style, QuoteLevel const & level, QuoteSide const & side) const { @@ -346,7 +452,7 @@ docstring InsetQuotesParams::getLaTeXQuote(char_type c, string const & op) const default: break; } - + return from_ascii(res); } @@ -419,7 +525,7 @@ docstring InsetQuotesParams::getHTMLQuote(char_type c) const default: break; } - + return from_ascii(res); } @@ -455,14 +561,36 @@ map InsetQuotesParams::getTypes() const } -docstring const InsetQuotesParams::getGuiLabel(QuoteStyle const & qs) +docstring const InsetQuotesParams::getGuiLabel(QuoteStyle const & qs, bool langdef) +{ + docstring const styledesc = + bformat(_("%1$souter%2$s and %3$sinner%4$s[[quotation marks]]"), + docstring(1, getQuoteChar(qs, PrimaryQuotes, OpeningQuote)), + docstring(1, getQuoteChar(qs, PrimaryQuotes, ClosingQuote)), + docstring(1, getQuoteChar(qs, SecondaryQuotes, OpeningQuote)), + docstring(1, getQuoteChar(qs, SecondaryQuotes, ClosingQuote)) + ); + + if (!langdef) + return styledesc; + + return bformat(_("%1$s[[quot. mark description]] (language default)"), + styledesc); +} + + +docstring const InsetQuotesParams::getShortGuiLabel(docstring const string) { - return bformat(_("%1$souter%2$s and %3$sinner%4$s[[quotation marks]]"), - docstring(1, quoteparams.getQuoteChar(qs, PrimaryQuotes, OpeningQuote)), - docstring(1, quoteparams.getQuoteChar(qs, PrimaryQuotes, ClosingQuote)), - docstring(1, quoteparams.getQuoteChar(qs, SecondaryQuotes, OpeningQuote)), - docstring(1, quoteparams.getQuoteChar(qs, SecondaryQuotes, ClosingQuote)) - ); + std::string const s = to_ascii(string); + QuoteStyle const style = getQuoteStyle(s); + QuoteSide const side = getQuoteSide(s); + QuoteLevel const level = getQuoteLevel(s); + + return (side == OpeningQuote) ? + bformat(_("%1$stext"), + docstring(1, getQuoteChar(style, level, side))) : + bformat(_("text%1$s"), + docstring(1, getQuoteChar(style, level, side))); } @@ -472,12 +600,19 @@ docstring const InsetQuotesParams::getGuiLabel(QuoteStyle const & qs) // /////////////////////////////////////////////////////////////////////// -InsetQuotes::InsetQuotes(Buffer * buf, string const & str) : Inset(buf) +InsetQuotes::InsetQuotes(Buffer * buf, string const & str) + : Inset(buf), + style_(InsetQuotesParams::EnglishQuotes), side_(InsetQuotesParams::OpeningQuote), + pass_thru_(false), internal_fontenc_(false) { - if (buf) + if (buf) { global_style_ = buf->masterBuffer()->params().quotes_style; - else + fontspec_ = buf->masterBuffer()->params().useNonTeXFonts; + } + else { global_style_ = InsetQuotesParams::EnglishQuotes; + fontspec_ = false; + } parseString(str); } @@ -485,17 +620,18 @@ InsetQuotes::InsetQuotes(Buffer * buf, string const & str) : Inset(buf) InsetQuotes::InsetQuotes(Buffer * buf, char_type c, InsetQuotesParams::QuoteLevel level, string const & side, string const & style) - : Inset(buf), level_(level), pass_thru_(false) + : Inset(buf), level_(level), pass_thru_(false), fontspec_(false), internal_fontenc_(false) { bool dynamic = false; if (buf) { global_style_ = buf->masterBuffer()->params().quotes_style; - fontenc_ = (buf->masterBuffer()->params().fontenc == "global") - ? lyxrc.fontenc : buf->params().fontenc; + fontenc_ = buf->masterBuffer()->params().main_font_encoding(); dynamic = buf->masterBuffer()->params().dynamic_quotes; + fontspec_ = buf->masterBuffer()->params().useNonTeXFonts; } else { global_style_ = InsetQuotesParams::EnglishQuotes; - fontenc_ = lyxrc.fontenc; + fontenc_ = "OT1"; + fontspec_ = false; } if (style.empty()) style_ = dynamic ? InsetQuotesParams::DynamicQuotes : global_style_; @@ -520,80 +656,25 @@ docstring InsetQuotes::layoutName() const void InsetQuotes::setSide(char_type c) { // Decide whether opening or closing quote - switch (c) { - case ' ': - case '(': - case '[': + if (lyx::isSpace(c) || isOpenPunctuation(c)) side_ = InsetQuotesParams::OpeningQuote;// opening quote - break; - default: + else side_ = InsetQuotesParams::ClosingQuote;// closing quote - } } void InsetQuotes::parseString(string const & s, bool const allow_wildcards) { - string str = s; - if (str.length() != 3) { - lyxerr << "ERROR (InsetQuotes::InsetQuotes):" - " bad string length." << endl; - str = "eld"; - } - - int i; - - // '.' wildcard means: keep current stylee - if (!allow_wildcards || str[0] != '.') { - for (i = 0; i < quoteparams.stylescount(); ++i) { - if (str[0] == style_char[i]) { - style_ = InsetQuotesParams::QuoteStyle(i); - break; - } - } - if (i >= quoteparams.stylescount()) { - LYXERR0("ERROR (InsetQuotes::InsetQuotes):" - " bad style specification."); - style_ = InsetQuotesParams::EnglishQuotes; - } - } - - // '.' wildcard means: keep current side - if (!allow_wildcards || str[1] != '.') { - for (i = 0; i < 2; ++i) { - if (str[1] == side_char[i]) { - side_ = InsetQuotesParams::QuoteSide(i); - break; - } - } - if (i >= 2) { - LYXERR0("ERROR (InsetQuotes::InsetQuotes):" - " bad side specification."); - side_ = InsetQuotesParams::OpeningQuote; - } - } - - // '.' wildcard means: keep current level - if (!allow_wildcards || str[2] != '.') { - for (i = 0; i < 2; ++i) { - if (str[2] == level_char[i]) { - level_ = InsetQuotesParams::QuoteLevel(i); - break; - } - } - if (i >= 2) { - LYXERR0("ERROR (InsetQuotes::InsetQuotes):" - " bad level specification."); - level_ = InsetQuotesParams::PrimaryQuotes; - } - } + style_ = quoteparams.getQuoteStyle(s, allow_wildcards, style_); + side_ = quoteparams.getQuoteSide(s, allow_wildcards, side_); + level_ = quoteparams.getQuoteLevel(s, allow_wildcards, level_); } InsetQuotesParams::QuoteStyle InsetQuotes::getStyle(string const & s) { InsetQuotesParams::QuoteStyle qs = InsetQuotesParams::EnglishQuotes; - + if (s == "english") qs = InsetQuotesParams::EnglishQuotes; else if (s == "swedish") @@ -719,7 +800,7 @@ void InsetQuotes::doDispatch(Cursor & cur, FuncRequest & cmd) } cur.recordUndoInset(this); parseString(cmd.getArg(1), true); - cur.buffer()->updateBuffer(); + cur.forceBufferUpdate(); break; } default: @@ -761,19 +842,22 @@ void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const // In pass-thru context, we output plain quotes if (runparams.pass_thru) qstr = (level_ == InsetQuotesParams::PrimaryQuotes) ? from_ascii("\"") : from_ascii("'"); - else if (style == InsetQuotesParams::PlainQuotes && runparams.isFullUnicode()) { + else if (style == InsetQuotesParams::PlainQuotes && fontspec_) { // For XeTeX and LuaTeX,we need to disable mapping to get straight // quotes. We define our own commands that do this qstr = (level_ == InsetQuotesParams::PrimaryQuotes) ? from_ascii("\\textquotedblplain") : from_ascii("\\textquotesingleplain"); } else if (runparams.use_polyglossia) { - // For polyglossia, we directly output the respective unicode chars + // For polyglossia, we directly output the respective unicode chars // (spacing and kerning is then handled respectively) qstr = docstring(1, quotechar); } + // The CJK marks are not yet covered by utf8 inputenc (we don't have the entry in + // unicodesymbols, since we don't want to add fake synbols there). else if (style == InsetQuotesParams::CJKQuotes || style == InsetQuotesParams::CJKAngleQuotes) { - if (runparams.encoding && runparams.encoding->encodable(quotechar)) + if (runparams.encoding && runparams.encoding->name() != "utf8" + && runparams.encoding->encodable(quotechar)) qstr = docstring(1, quotechar); else qstr = quoteparams.getLaTeXQuote(quotechar, "int"); @@ -799,10 +883,12 @@ void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const // (ligatures not featured) qstr = quoteparams.getLaTeXQuote(quotechar, "int"); #ifdef DO_USE_DEFAULT_LANGUAGE - } else if (doclang == "default") { + } else if ((doclang == "default" #else - } else if (!runparams.use_babel || runparams.isFullUnicode()) { + } else if ((!runparams.use_babel #endif + || (fontenc_ != "T1" && fontenc_ != "OT1")) + || runparams.isFullUnicode()) { // Standard quotation mark macros // These are also used by babel // without fontenc (XeTeX/LuaTeX) @@ -815,15 +901,21 @@ void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const if (!runparams.pass_thru) { // Guard against unwanted ligatures with preceding text char_type const lastchar = os.lastChar(); + // LuaTeX does not respect {} as ligature breaker by design, + // see https://tex.stackexchange.com/q/349725/19291 + docstring const nolig = + (runparams.flavor == OutputParams::LUATEX + || runparams.flavor == OutputParams::DVILUATEX) ? + from_ascii("\\/") : from_ascii("{}"); // !` ?` => !{}` ?{}` if (prefixIs(qstr, from_ascii("`")) && (lastchar == '!' || lastchar == '?')) - os << "{}"; + os << nolig; // ``` ''' ,,, <<< >>> // => `{}`` '{}'' ,{},, <{}<< >{}>> if (contains(from_ascii(",'`<>"), lastchar) && prefixIs(qstr, lastchar)) - os << "{}"; + os << nolig; } os << qstr; @@ -834,7 +926,7 @@ void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const } -int InsetQuotes::plaintext(odocstringstream & os, +int InsetQuotes::plaintext(odocstringstream & os, OutputParams const &, size_t) const { docstring const str = displayString(); @@ -895,8 +987,10 @@ void InsetQuotes::updateBuffer(ParIterator const & it, UpdateType /* utype*/) BufferParams const & bp = buffer().masterBuffer()->params(); pass_thru_ = it.paragraph().isPassThru(); context_lang_ = it.paragraph().getFontSettings(bp, it.pos()).language()->code(); - fontenc_ = (bp.fontenc == "global") ? lyxrc.fontenc : bp.fontenc; + internal_fontenc_ = it.paragraph().getFontSettings(bp, it.pos()).language()->internalFontEncoding(); + fontenc_ = bp.main_font_encoding(); global_style_ = bp.quotes_style; + fontspec_ = bp.useNonTeXFonts; } @@ -941,23 +1035,25 @@ void InsetQuotes::validate(LaTeXFeatures & features) const // in most output formats switch (type) { case 0x0027: { - if (features.runparams().isFullUnicode()) + if (features.runparams().isFullUnicode() && fontspec_) features.require("textquotesinglep"); else features.require("textcomp"); break; } case 0x0022: { - if (features.runparams().isFullUnicode()) + if (features.runparams().isFullUnicode() && fontspec_) features.require("textquotedblp"); - else if (fontenc_ != "T1") + else if (fontenc_ != "T1" || internal_fontenc_) features.require("textquotedbl"); break; } - // we fake these from math + // we fake these from math (also for utf8 inputenc + // currently; see above) case 0x300e: // LEFT WHITE CORNER BRACKET case 0x300f: // RIGHT WHITE CORNER BRACKET if (!features.runparams().encoding + || features.runparams().encoding->name() == "utf8" || !features.runparams().encoding->encodable(type)) features.require("stmaryrd"); break;