X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferParams.cpp;h=d25dd05bac2e55da31f0afe52be4446e7a0e0fb1;hb=e6b93f7489fc0738b6097d49cb7b16eed2b4fb1e;hp=4a70ed884db1ae8ebda0713f15226a52b3a3f8ef;hpb=3c094c739ba38f43edf9698ac37dd9eee62080b1;p=lyx.git diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 4a70ed884d..d25dd05bac 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -21,19 +21,17 @@ #include "LayoutFile.h" #include "BranchList.h" #include "Buffer.h" -#include "buffer_funcs.h" #include "Bullet.h" #include "CiteEnginesList.h" #include "Color.h" #include "ColorSet.h" #include "Converter.h" #include "Encoding.h" +#include "Format.h" #include "IndicesList.h" #include "Language.h" #include "LaTeXFeatures.h" #include "LaTeXFonts.h" -#include "Length.h" -#include "ModuleList.h" #include "Font.h" #include "Lexer.h" #include "LyXRC.h" @@ -47,13 +45,14 @@ #include "frontends/alert.h" #include "insets/InsetListingsParams.h" +#include "insets/InsetQuotes.h" #include "support/convert.h" #include "support/debug.h" -#include "support/docstream.h" #include "support/FileName.h" #include "support/filetools.h" #include "support/gettext.h" +#include "support/Length.h" #include "support/Messages.h" #include "support/mutex.h" #include "support/Package.h" @@ -74,7 +73,8 @@ static char const * const string_paragraph_separation[] = { static char const * const string_quotes_style[] = { "english", "swedish", "german", "polish", "swiss", "danish", "plain", - "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", "" + "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", + "hungarian", "" }; @@ -137,26 +137,27 @@ ParSepTranslator const & parseptranslator() // Quotes style -typedef Translator QuotesStyleTranslator; +typedef Translator QuotesStyleTranslator; QuotesStyleTranslator const init_quotesstyletranslator() { QuotesStyleTranslator translator - (string_quotes_style[0], InsetQuotesParams::EnglishQuotes); - translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes); - translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes); - translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes); - translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes); - translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes); - translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes); - translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes); - translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes); - translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes); - translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes); - translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes); - translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes); - translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes); + (string_quotes_style[0], QuoteStyle::English); + translator.addPair(string_quotes_style[1], QuoteStyle::Swedish); + translator.addPair(string_quotes_style[2], QuoteStyle::German); + translator.addPair(string_quotes_style[3], QuoteStyle::Polish); + translator.addPair(string_quotes_style[4], QuoteStyle::Swiss); + translator.addPair(string_quotes_style[5], QuoteStyle::Danish); + translator.addPair(string_quotes_style[6], QuoteStyle::Plain); + translator.addPair(string_quotes_style[7], QuoteStyle::British); + translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG); + translator.addPair(string_quotes_style[9], QuoteStyle::French); + translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN); + translator.addPair(string_quotes_style[11], QuoteStyle::Russian); + translator.addPair(string_quotes_style[12], QuoteStyle::CJK); + translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle); + translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian); return translator; } @@ -340,6 +341,7 @@ public: AuthorList authorlist; BranchList branchlist; + WordLangTable spellignore; Bullet temp_bullets[4]; Bullet user_defined_bullets[4]; IndicesList indiceslist; @@ -395,7 +397,7 @@ BufferParams::BufferParams() paragraph_separation = ParagraphIndentSeparation; is_math_indent = false; math_numbering_side = DEFAULT; - quotes_style = InsetQuotesParams::EnglishQuotes; + quotes_style = QuoteStyle::English; dynamic_quotes = false; fontsize = "default"; @@ -449,6 +451,8 @@ BufferParams::BufferParams() listings_params = string(); pagestyle = "default"; tablestyle = "default"; + float_alignment = "class"; + float_placement = "class"; suppress_date = false; justification = true; // no color is the default (white) @@ -459,7 +463,9 @@ BufferParams::BufferParams() isfontcolor = false; // light gray is the default font color for greyed-out notes notefontcolor = lyx::rgbFromHexName("#cccccc"); + isnotefontcolor = false; boxbgcolor = lyx::rgbFromHexName("#ff0000"); + isboxbgcolor = false; compressed = lyxrc.save_compressed; for (int iter = 0; iter < 4; ++iter) { user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter]; @@ -471,6 +477,8 @@ BufferParams::BufferParams() html_math_output = MathML; html_math_img_scale = 1.0; html_css_as_file = false; + docbook_table_output = HTMLTable; + docbook_mathml_prefix = MPrefix; display_pixel_ratio = 1.0; shell_escape = false; @@ -564,7 +572,7 @@ AuthorList const & BufferParams::authors() const } -void BufferParams::addAuthor(Author a) +void BufferParams::addAuthor(Author const & a) { author_map_[a.bufferId()] = pimpl_->authorlist.record(a); } @@ -594,6 +602,35 @@ IndicesList const & BufferParams::indiceslist() const } +WordLangTable & BufferParams::spellignore() +{ + return pimpl_->spellignore; +} + + +WordLangTable const & BufferParams::spellignore() const +{ + return pimpl_->spellignore; +} + + +bool BufferParams::spellignored(WordLangTuple const & wl) const +{ + bool has_item = false; + vector il = spellignore(); + vector::const_iterator it = il.begin(); + for (; it != il.end(); ++it) { + if (it->lang()->code() != wl.lang()->code()) + continue; + if (it->word() == wl.word()) { + has_item = true; + break; + } + } + return has_item; +} + + Bullet & BufferParams::temp_bullet(lyx::size_type const index) { LASSERT(index < 4, return pimpl_->temp_bullets[0]); @@ -698,9 +735,10 @@ BufferParams::MathNumber BufferParams::getMathNumber() const string BufferParams::readToken(Lexer & lex, string const & token, - FileName const & filepath) + FileName const & filename) { string result; + FileName const & filepath = filename.onlyPath(); if (token == "\\textclass") { lex.next(); @@ -769,6 +807,8 @@ string BufferParams::readToken(Lexer & lex, string const & token, origin.replace(0, sysdirprefix.length() - 1, package().system_support().absFileName()); } + } else if (token == "\\begin_metadata") { + readDocumentMetadata(lex); } else if (token == "\\begin_preamble") { readPreamble(lex); } else if (token == "\\begin_local_layout") { @@ -986,14 +1026,13 @@ string BufferParams::readToken(Lexer & lex, string const & token, } if (tok == "\\color") { lex.eatLine(); - string color = lex.getString(); + vector const colors = getVectorFromString(lex.getString(), " "); + string const lmcolor = colors.front(); + string dmcolor; + if (colors.size() > 1) + dmcolor = colors.back(); if (branch_ptr) - branch_ptr->setColor(color); - // Update also the Color table: - if (color == "none") - color = lcolor.getX11Name(Color_background); - // FIXME UNICODE - lcolor.setColor(to_utf8(branch), color); + branch_ptr->setColors(lmcolor, dmcolor); } } } else if (token == "\\index") { @@ -1020,12 +1059,20 @@ string BufferParams::readToken(Lexer & lex, string const & token, index_ptr->setColor(color); // Update also the Color table: if (color == "none") - color = lcolor.getX11Name(Color_background); + color = lcolor.getX11HexName(Color_background); // FIXME UNICODE if (!shortcut.empty()) - lcolor.setColor(to_utf8(shortcut), color); + lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color); } } + } else if (token == "\\spellchecker_ignore") { + lex.eatLine(); + docstring wl = lex.getDocString(); + docstring language; + docstring word = split(wl, language, ' '); + Language const * lang = languages.getLanguage(to_ascii(language)); + if (lang) + spellignore().push_back(WordLangTuple(word, lang)); } else if (token == "\\author") { lex.eatLine(); istringstream ss(lex.getString()); @@ -1049,11 +1096,17 @@ string BufferParams::readToken(Lexer & lex, string const & token, string color = lex.getString(); notefontcolor = lyx::rgbFromHexName(color); lcolor.setColor("notefontcolor", color); + lcolor.setLaTeXName("notefontcolor", "note_fontcolor"); + lcolor.setGUIName("notefontcolor", N_("greyedout inset text")); + // set a local name for the painter + lcolor.setColor("notefontcolor@" + filename.absFileName(), color); + isnotefontcolor = true; } else if (token == "\\boxbgcolor") { lex.eatLine(); string color = lex.getString(); boxbgcolor = lyx::rgbFromHexName(color); - lcolor.setColor("boxbgcolor", color); + lcolor.setColor("boxbgcolor@" + filename.absFileName(), color); + isboxbgcolor = true; } else if (token == "\\paperwidth") { lex >> paperwidth; } else if (token == "\\paperheight") { @@ -1134,6 +1187,14 @@ string BufferParams::readToken(Lexer & lex, string const & token, } else if (token == "\\html_latex_end") { lex.eatLine(); html_latex_end = lex.getString(); + } else if (token == "\\docbook_table_output") { + int temp; + lex >> temp; + docbook_table_output = static_cast(temp); + } else if (token == "\\docbook_mathml_prefix") { + int temp; + lex >> temp; + docbook_mathml_prefix = static_cast(temp); } else if (token == "\\output_sync") { lex >> output_sync; } else if (token == "\\output_sync_macro") { @@ -1196,6 +1257,15 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const baseClass()->name()), "layout")) << '\n'; + // then document metadata + if (!document_metadata.empty()) { + // remove '\n' from the end of document_metadata + docstring const tmpmd = rtrim(document_metadata, "\n"); + os << "\\begin_metadata\n" + << to_utf8(tmpmd) + << "\n\\end_metadata\n"; + } + // then the preamble if (!preamble.empty()) { // remove '\n' from the end of preamble @@ -1366,20 +1436,20 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const if (!lineno_opts.empty()) os << "\\lineno_options " << lineno_opts << '\n'; - if (isbackgroundcolor == true) + if (isbackgroundcolor) os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n'; - if (isfontcolor == true) + if (isfontcolor) os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n'; - if (notefontcolor != lyx::rgbFromHexName("#cccccc")) + if (isnotefontcolor) os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n'; - if (boxbgcolor != lyx::rgbFromHexName("#ff0000")) + if (isboxbgcolor) os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n'; for (auto const & br : branchlist()) { os << "\\branch " << to_utf8(br.branch()) << "\n\\selected " << br.isSelected() << "\n\\filename_suffix " << br.hasFileNameSuffix() - << "\n\\color " << lyx::X11hexname(br.color()) + << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor() << "\n\\end_branch" << "\n"; } @@ -1392,6 +1462,12 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << "\n"; } + for (auto const & si : spellignore()) { + os << "\\spellchecker_ignore " << si.lang()->lang() + << " " << to_utf8(si.word()) + << "\n"; + } + if (!paperwidth.empty()) os << "\\paperwidth " << VSpace(paperwidth).asLyXCommand() << '\n'; @@ -1447,7 +1523,7 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const os << "default"; } os << "\n\\quotes_style " - << string_quotes_style[quotes_style] + << string_quotes_style[static_cast(quotes_style)] << "\n\\dynamic_quotes " << dynamic_quotes << "\n\\papercolumns " << columns << "\n\\papersides " << sides @@ -1491,6 +1567,9 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << "\\html_css_as_file " << html_css_as_file << '\n' << "\\html_be_strict " << convert(html_be_strict) << '\n'; + os << "\\docbook_table_output " << docbook_table_output << '\n'; + os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n'; + if (html_math_img_scale != 1.0) os << "\\html_math_img_scale " << convert(html_math_img_scale) << '\n'; if (!html_latex_start.empty()) @@ -1514,8 +1593,8 @@ void BufferParams::validate(LaTeXFeatures & features) const LaTeXFeatures::isAvailable("xcolor"); switch (features.runparams().flavor) { - case OutputParams::LATEX: - case OutputParams::DVILUATEX: + case Flavor::LaTeX: + case Flavor::DviLuaTeX: if (xcolorulem) { features.require("ct-xcolor-ulem"); features.require("ulem"); @@ -1524,9 +1603,9 @@ void BufferParams::validate(LaTeXFeatures & features) const features.require("ct-none"); } break; - case OutputParams::LUATEX: - case OutputParams::PDFLATEX: - case OutputParams::XETEX: + case Flavor::LuaTeX: + case Flavor::PdfLaTeX: + case Flavor::XeTeX: if (xcolorulem) { features.require("ct-xcolor-ulem"); features.require("ulem"); @@ -1620,6 +1699,56 @@ void BufferParams::validate(LaTeXFeatures & features) const bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, FileName const & filepath) const { + // DocumentMetadata must come before anything else + if (features.isAvailable("LaTeX-2022/06/01") + && !containsOnly(document_metadata, " \n\t")) { + // Check if the user preamble contains uncodable glyphs + odocstringstream doc_metadata; + docstring uncodable_glyphs; + Encoding const * const enc = features.runparams().encoding; + if (enc) { + for (char_type c : document_metadata) { + if (!enc->encodable(c)) { + docstring const glyph(1, c); + LYXERR0("Uncodable character '" + << glyph + << "' in document metadata!"); + uncodable_glyphs += glyph; + if (features.runparams().dryrun) { + doc_metadata << "<" << _("LyX Warning: ") + << _("uncodable character") << " '"; + doc_metadata.put(c); + doc_metadata << "'>"; + } + } else + doc_metadata.put(c); + } + } else + doc_metadata << document_metadata; + + // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs + if (!features.runparams().dryrun && !uncodable_glyphs.empty()) { + frontend::Alert::warning( + _("Uncodable character in document metadata"), + support::bformat( + _("The metadata of your document contains glyphs " + "that are unknown in the current document encoding " + "(namely %1$s).\nThese glyphs are omitted " + " from the output, which may result in " + "incomplete output." + "\n\nPlease select an appropriate " + "document encoding\n" + "(such as utf8) or change the " + "preamble code accordingly."), + uncodable_glyphs)); + } + if (!doc_metadata.str().empty()) { + os << "\\DocumentMetadata{\n" + << doc_metadata.str() + << "}\n"; + } + } + // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf // !! To use the Fix-cm package, load it before \documentclass, and use the command // \RequirePackage to do so, rather than the normal \usepackage @@ -1732,8 +1861,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, docstring options_encodable; Encoding const * const enc = features.runparams().encoding; if (enc) { - for (size_t n = 0; n < strOptions.size(); ++n) { - char_type c = strOptions[n]; + for (char_type c : strOptions) { if (!enc->encodable(c)) { docstring const glyph(1, c); LYXERR0("Uncodable character '" @@ -1780,7 +1908,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // if we use fontspec or newtxmath, we have to load the AMS packages here string const ams = features.loadAMSPackages(); - bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1"); + string const main_font_enc = features.runparams().main_fontenc; + bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1"); bool const use_newtxmath = theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage( ot1, false, false) == "newtxmath"; @@ -1820,7 +1949,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // set font encoding // non-TeX fonts use font encoding TU (set by fontspec) if (!useNonTeXFonts && !features.isProvided("fontenc") - && main_font_encoding() != "default") { + && main_font_enc != "default") { // get main font encodings vector fontencs = font_encodings(); // get font encodings of secondary languages @@ -1970,7 +2099,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, } // only output when the background color is not default - if (isbackgroundcolor == true) { + if (isbackgroundcolor) { // only require color here, the background color will be defined // in LaTeXFeatures.cpp to avoid interferences with the LaTeX // package pdfpages @@ -1979,7 +2108,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, } // only output when the font color is not default - if (isfontcolor == true) { + if (isfontcolor) { // only require color here, the font color will be defined // in LaTeXFeatures.cpp to avoid interferences with the LaTeX // package pdfpages @@ -2060,9 +2189,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, if (output_sync) { if (!output_sync_macro.empty()) os << from_utf8(output_sync_macro) +"\n"; - else if (features.runparams().flavor == OutputParams::LATEX) + else if (features.runparams().flavor == Flavor::LaTeX) os << "\\usepackage[active]{srcltx}\n"; - else if (features.runparams().flavor == OutputParams::PDFLATEX) + else os << "\\synctex=-1\n"; } @@ -2175,8 +2304,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, docstring uncodable_glyphs; Encoding const * const enc = features.runparams().encoding; if (enc) { - for (size_t n = 0; n < preamble.size(); ++n) { - char_type c = preamble[n]; + for (char_type c : preamble) { if (!enc->encodable(c)) { docstring const glyph(1, c); LYXERR0("Uncodable character '" @@ -2232,8 +2360,10 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // use \PassOptionsToPackage here because the user could have // already loaded subfig in the preamble. if (features.mustProvide("subfig")) - atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n" - " \\PassOptionsToPackage{caption=false}{subfig}}\n" + atlyxpreamble << "\\ifdefined\\showcaptionsetup\n" + " % Caption package is used. Advise subfig not to load it again.\n" + " \\PassOptionsToPackage{caption=false}{subfig}\n" + "\\fi\n" "\\usepackage{subfig}\n"; // Itemize bullet settings need to be last in case the user @@ -2340,7 +2470,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, && !features.isProvided("xunicode")) { // The `xunicode` package officially only supports XeTeX, // but also works with LuaTeX. We work around its XeTeX test. - if (features.runparams().flavor != OutputParams::XETEX) { + if (features.runparams().flavor != Flavor::XeTeX) { os << "% Pretend to xunicode that we are XeTeX\n" << "\\def\\XeTeXpicfile{}\n"; } @@ -2557,7 +2687,7 @@ LayoutFileIndex const & BufferParams::baseClassID() const } -void BufferParams::makeDocumentClass(bool const clone) +void BufferParams::makeDocumentClass(bool clone, bool internal) { if (!baseClass()) return; @@ -2567,7 +2697,7 @@ void BufferParams::makeDocumentClass(bool const clone) for (auto const & mod : layout_modules_) mods.push_back(mod); - doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone); + doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal); TextClass::ReturnValues success = TextClass::OK; if (!forced_local_layout_.empty()) @@ -2653,10 +2783,12 @@ FormatList const & BufferParams::exportableFormats(bool only_viewable) const excludes.insert("xetex"); } - FormatList result; - for (auto const & b : backs) { - FormatList r = - theConverters().getReachable(b, only_viewable, false, excludes); + FormatList result = + theConverters().getReachable(backs[0], only_viewable, true, excludes); + vector::const_iterator it = backs.begin() + 1; + for (; it != backs.end(); ++it) { + FormatList r = theConverters().getReachable(*it, only_viewable, + false, excludes); result.insert(result.end(), r.begin(), r.end()); } sort(result.begin(), result.end(), Format::formatSorter); @@ -2705,7 +2837,7 @@ vector BufferParams::backends() const } -OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const +Flavor BufferParams::getOutputFlavor(string const & format) const { string const dformat = (format.empty() || format == "default") ? getDefaultOutputFormat() : format; @@ -2715,24 +2847,26 @@ OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const if (it != default_flavors_.end()) return it->second; - OutputParams::FLAVOR result = OutputParams::LATEX; + Flavor result = Flavor::LaTeX; // FIXME It'd be better not to hardcode this, but to do // something with formats. if (dformat == "xhtml") - result = OutputParams::HTML; + result = Flavor::Html; + else if (dformat == "docbook5") + result = Flavor::DocBook5; else if (dformat == "text") - result = OutputParams::TEXT; + result = Flavor::Text; else if (dformat == "lyx") - result = OutputParams::LYX; + result = Flavor::LyX; else if (dformat == "pdflatex") - result = OutputParams::PDFLATEX; + result = Flavor::PdfLaTeX; else if (dformat == "xetex") - result = OutputParams::XETEX; + result = Flavor::XeTeX; else if (dformat == "luatex") - result = OutputParams::LUATEX; + result = Flavor::LuaTeX; else if (dformat == "dviluatex") - result = OutputParams::DVILUATEX; + result = Flavor::DviLuaTeX; else { // Try to determine flavor of default output format vector backs = backends(); @@ -2780,7 +2914,7 @@ Font const BufferParams::getFont() const } -InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const +QuoteStyle BufferParams::getQuoteStyle(string const & qs) const { return quotesstyletranslator().find(qs); } @@ -2808,6 +2942,16 @@ void BufferParams::readPreamble(Lexer & lex) } +void BufferParams::readDocumentMetadata(Lexer & lex) +{ + if (lex.getString() != "\\begin_metadata") + lyxerr << "Error (BufferParams::readDocumentMetadata):" + "consistency check failed." << endl; + + document_metadata = lex.getLongString(from_ascii("\\end_metadata")); +} + + void BufferParams::readLocalLayout(Lexer & lex, bool forced) { string const expected = forced ? "\\begin_forced_local_layout" : @@ -3163,12 +3307,13 @@ string const BufferParams::dvips_options() const string const BufferParams::main_font_encoding() const { - if (font_encodings().empty()) { + vector const fencs = font_encodings(); + if (fencs.empty()) { if (ascii_lowercase(language->fontenc(*this)) == "none") return "none"; return "default"; } - return font_encodings().back(); + return fencs.back(); } @@ -3183,9 +3328,10 @@ vector const BufferParams::font_encodings() const if (!doc_fontenc.empty()) // If we have a custom setting, we use only that! return getVectorFromString(doc_fontenc); - if (!language->fontenc(*this).empty() + string const lfe = language->fontenc(*this); + if (!lfe.empty() && ascii_lowercase(language->fontenc(*this)) != "none") { - vector fencs = getVectorFromString(language->fontenc(*this)); + vector fencs = getVectorFromString(lfe); for (auto & fe : fencs) { if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end()) fontencs.push_back(fe); @@ -3246,8 +3392,8 @@ void BufferParams::writeEncodingPreamble(otexstream & os, // Create list of inputenc options: set encoding_set; // luainputenc fails with more than one encoding - if (features.runparams().flavor != OutputParams::LUATEX - && features.runparams().flavor != OutputParams::DVILUATEX) + if (features.runparams().flavor != Flavor::LuaTeX + && features.runparams().flavor != Flavor::DviLuaTeX) // list all input encodings used in the document encoding_set = features.getEncodingSet(doc_encoding); @@ -3271,8 +3417,8 @@ void BufferParams::writeEncodingPreamble(otexstream & os, os << ','; os << from_ascii(doc_encoding); } - if (features.runparams().flavor == OutputParams::LUATEX - || features.runparams().flavor == OutputParams::DVILUATEX) + if (features.runparams().flavor == Flavor::LuaTeX + || features.runparams().flavor == Flavor::DviLuaTeX) os << "]{luainputenc}\n"; else os << "]{inputenc}\n"; @@ -3294,9 +3440,21 @@ void BufferParams::writeEncodingPreamble(otexstream & os, if (features.isRequired("japanese") || features.isProvided("inputenc")) break; - os << "\\usepackage[" << from_ascii(encoding().latexName()); - if (features.runparams().flavor == OutputParams::LUATEX - || features.runparams().flavor == OutputParams::DVILUATEX) + string const doc_encoding = encoding().latexName(); + // The 2022 release of ucs.sty uses the default utf8 + // inputenc encoding with 'utf8x' inputenc if the ucs + // package is not loaded before inputenc. + // This breaks existing documents that use utf8x + // and also makes utf8x redundant. + // Thus we load ucs.sty in order to keep functionality + // that would otherwise be silently dropped. + if (doc_encoding == "utf8x" + && features.isAvailable("ucs-2022/08/07") + && !features.isProvided("ucs")) + os << "\\usepackage{ucs}\n"; + os << "\\usepackage[" << from_ascii(doc_encoding); + if (features.runparams().flavor == Flavor::LuaTeX + || features.runparams().flavor == Flavor::DviLuaTeX) os << "]{luainputenc}\n"; else os << "]{inputenc}\n"; @@ -3357,7 +3515,7 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const bool const babelfonts = features.useBabel() && features.isAvailable("babel-2017/11/03"); string const texmapping = - (features.runparams().flavor == OutputParams::XETEX) ? + (features.runparams().flavor == Flavor::XeTeX) ? "Mapping=tex-text" : "Ligatures=TeX"; if (fontsRoman() != "default") { if (babelfonts) @@ -3437,10 +3595,11 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const } // Tex Fonts - bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1"); + bool const ot1 = (features.runparams().main_fontenc == "default" + || features.runparams().main_fontenc == "OT1"); bool const dryrun = features.runparams().dryrun; bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default"); - bool const nomath = (fontsMath() == "default"); + bool const nomath = (fontsMath() != "auto"); // ROMAN FONTS os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode( @@ -3498,7 +3657,7 @@ string const & BufferParams::defaultBiblioStyle() const } -bool const & BufferParams::fullAuthorList() const +bool BufferParams::fullAuthorList() const { return documentClass().fullAuthorList(); } @@ -3540,11 +3699,71 @@ vector BufferParams::citeStyles() const } -string const BufferParams::bibtexCommand() const +string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const +{ + // split from options + string command_in; + split(cmd, command_in, ' '); + + // Look if the requested command is available. If so, use that. + for (auto const & alts : lyxrc.bibtex_alternatives) { + string command_prov; + split(alts, command_prov, ' '); + if (command_in == command_prov) + return cmd; + } + + // If not, find the most suitable fallback for the current cite framework, + // and warn. Note that we omit options in any such case. + string fallback; + if (useBiblatex()) { + // For Biblatex, we prefer biber (also for Japanese) + // and try to fall back to bibtex8 + if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end()) + fallback = "biber"; + else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end()) + fallback = "bibtex8"; + } + // For classic BibTeX and as last resort for biblatex, try bibtex + if (fallback.empty()) { + if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end()) + fallback = "bibtex"; + } + + if (!warn) + return fallback; + + if (fallback.empty()) { + frontend::Alert::warning( + _("No bibliography processor found!"), + support::bformat( + _("The bibliography processor requested by this document " + "(%1$s) is not available and no appropriate " + "alternative has been found. " + "No bibliography and references will be generated.\n" + "Please fix your installation!"), + from_utf8(cmd))); + } else { + frontend::Alert::warning( + _("Requested bibliography processor not found!"), + support::bformat( + _("The bibliography processor requested by this document " + "(%1$s) is not available. " + "As a fallback, '%2$s' will be used, options are omitted. " + "This might result in errors or unwanted changes in " + "the bibliography. Please check carefully!\n" + "It is suggested to install the missing processor."), + from_utf8(cmd), from_utf8(fallback))); + } + return fallback; +} + + +string const BufferParams::bibtexCommand(bool const warn) const { // Return document-specific setting if available if (bibtex_command != "default") - return bibtex_command; + return getBibtexCommand(bibtex_command, warn); // If we have "default" in document settings, consult the prefs // 1. Japanese (uses a specific processor) @@ -3564,7 +3783,7 @@ string const BufferParams::bibtexCommand() const // 2. All other languages else if (lyxrc.bibtex_command != "automatic") // Return the specified program, if "automatic" is not set - return lyxrc.bibtex_command; + return getBibtexCommand(lyxrc.bibtex_command, warn); // 3. Automatic: find the most suitable for the current cite framework if (useBiblatex()) { @@ -3598,6 +3817,7 @@ void BufferParams::copyForAdvFR(const BufferParams & bp) { string const & lang = bp.language->lang(); setLanguage(lang); + quotes_style = bp.quotes_style; layout_modules_ = bp.layout_modules_; string const & doc_class = bp.documentClass().name(); setBaseClass(doc_class);