X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferParams.cpp;h=f7516fc0269019a98133fb3166a1f1fe29cc9257;hb=293b8dbe67dc025d03d0523d0079f71f5ab62ce3;hp=93a539833bfe93088061cd218baa31d2e4d1054a;hpb=057753dc7549743a826d52b301eb846cb419b2b9;p=features.git diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 93a539833b..f7516fc026 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -341,6 +341,7 @@ public: AuthorList authorlist; BranchList branchlist; + WordLangTable spellignore; Bullet temp_bullets[4]; Bullet user_defined_bullets[4]; IndicesList indiceslist; @@ -462,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]; @@ -475,6 +478,7 @@ BufferParams::BufferParams() 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; @@ -598,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]); @@ -702,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(); @@ -773,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") { @@ -990,19 +1026,13 @@ string BufferParams::readToken(Lexer & lex, string const & token, } if (tok == "\\color") { lex.eatLine(); - string color = lex.getString(); - if (branch_ptr) { - branch_ptr->setColor(color); - if (branch_ptr->color() == "none") - color = lcolor.getX11HexName(Color_background); - } - // Update also the Color table: - if (color == "none") - color = lcolor.getX11HexName(Color_background); - else if (color.size() != 7 || color[0] != '#') - color = lcolor.getFromLyXName(color); - // FIXME UNICODE - lcolor.setColor(to_utf8(branch), color); + 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->setColors(lmcolor, dmcolor); } } } else if (token == "\\index") { @@ -1032,9 +1062,17 @@ string BufferParams::readToken(Lexer & lex, string const & token, 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()); @@ -1058,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") { @@ -1147,6 +1191,10 @@ string BufferParams::readToken(Lexer & lex, string const & token, 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") { @@ -1209,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 @@ -1383,16 +1440,16 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n'; 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 " << br.color() + << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor() << "\n\\end_branch" << "\n"; } @@ -1405,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'; @@ -1505,6 +1568,7 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << "\\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'; @@ -1635,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 @@ -1794,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"; @@ -1834,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 @@ -1864,6 +1979,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, if (!features.runparams().includeall && !included_children_.empty()) { os << "\\includeonly{"; bool first = true; + // we do not use "auto const &" here, because incfile is modified later + // coverity[auto_causes_copy] for (auto incfile : included_children_) { FileName inc = makeAbsPath(incfile, filepath.absFileName()); string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")). @@ -2076,7 +2193,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, os << from_utf8(output_sync_macro) +"\n"; else if (features.runparams().flavor == Flavor::LaTeX) os << "\\usepackage[active]{srcltx}\n"; - else if (features.runparams().flavor == Flavor::PdfLaTeX) + else os << "\\synctex=-1\n"; } @@ -2160,7 +2277,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, if (!tmppreamble.str.empty()) atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " "LyX specific LaTeX commands.\n" - << move(tmppreamble) + << std::move(tmppreamble) << '\n'; } // the text class specific preamble @@ -2827,6 +2944,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" : @@ -3182,12 +3309,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(); } @@ -3202,9 +3330,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); @@ -3313,8 +3442,20 @@ void BufferParams::writeEncodingPreamble(otexstream & os, if (features.isRequired("japanese") || features.isProvided("inputenc")) break; - os << "\\usepackage[" << from_ascii(encoding().latexName()); - if (features.runparams().flavor == Flavor::LuaTeX + 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 @@ -3456,7 +3597,8 @@ 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() != "auto"); @@ -3559,11 +3701,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) @@ -3583,7 +3785,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()) { @@ -3617,6 +3819,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);