X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferParams.cpp;h=d25dd05bac2e55da31f0afe52be4446e7a0e0fb1;hb=0515bfa989474c6dc46256b1bea52cff7f330336;hp=8b2afe15ba5888cefbac0418405f10b1afd367f3;hpb=7a87599a3e050974f915a320c815aa13c5120d22;p=lyx.git diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 8b2afe15ba..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,17 +73,26 @@ 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", "" }; static char const * const string_papersize[] = { + "default", "custom", "letter", "legal", "executive", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", + "b0", "b1", "b2", "b3", "b4", "b5", "b6", + "c0", "c1", "c2", "c3", "c4", "c5", "c6", + "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", "" +}; + + +static char const * const string_papersize_geometry[] = { "default", "custom", "letterpaper", "legalpaper", "executivepaper", - "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", - "a6paper", "b0paper", "b1paper", "b2paper","b3paper", "b4paper", - "b5paper", "b6paper", "c0paper", "c1paper", "c2paper", "c3paper", - "c4paper", "c5paper", "c6paper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", - "b6j", "" + "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper", + "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper", + "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper", + "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", "" }; @@ -104,18 +112,6 @@ static char const * const tex_graphics[] = { namespace lyx { -// XeTeX with TeX fonts: -// run in 8-bit emulation mode and trick `inputenc` into working with XeTeX -static docstring const xetex_pre_inputenc = from_ascii( - "\\XeTeXinputencoding \"bytes\" % current file\n" - "\\XeTeXdefaultencoding \"bytes\" % included files\n" - "\\makeatletter\n" - "\\let\\origUmathchar\\Umathchar\n" - "\\let\\Umathchar\\@undefined\n"); -static docstring const xetex_post_inputenc = from_ascii( - "\\let\\Umathchar\\origUmathchar\n" - "\\makeatother\n"); - // Local translators namespace { @@ -141,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; } @@ -344,6 +341,7 @@ public: AuthorList authorlist; BranchList branchlist; + WordLangTable spellignore; Bullet temp_bullets[4]; Bullet user_defined_bullets[4]; IndicesList indiceslist; @@ -369,7 +367,9 @@ BufferParams::Impl::Impl() { // set initial author // FIXME UNICODE - authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email))); + authorlist.record(Author(from_utf8(lyxrc.user_name), + from_utf8(lyxrc.user_email), + from_utf8(lyxrc.user_initials))); } @@ -397,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"; @@ -412,8 +412,10 @@ BufferParams::BufferParams() save_transient_properties = true; track_changes = false; output_changes = false; + change_bars = false; + postpone_fragile_content = true; use_default_options = true; - maintain_unincluded_children = false; + maintain_unincluded_children = CM_None; secnumdepth = 3; tocdepth = 3; language = default_language; @@ -431,12 +433,14 @@ BufferParams::BufferParams() use_microtype = false; use_dash_ligatures = true; fonts_expert_sc = false; - fonts_old_figures = false; + fonts_roman_osf = false; + fonts_sans_osf = false; + fonts_typewriter_osf = false; fonts_sans_scale[0] = 100; fonts_sans_scale[1] = 100; fonts_typewriter_scale[0] = 100; fonts_typewriter_scale[1] = 100; - inputenc = "auto-legacy"; + inputenc = "utf8"; lang_package = "default"; graphics_driver = "default"; default_output_format = "default"; @@ -447,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) @@ -457,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]; @@ -469,12 +477,15 @@ 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; output_sync = false; use_refstyle = true; use_minted = false; + use_lineno = false; // map current author author_map_[pimpl_->authorlist.get(0).bufferId()] = 0; @@ -561,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); } @@ -591,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]); @@ -695,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(); @@ -766,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") { @@ -779,7 +822,14 @@ string BufferParams::readToken(Lexer & lex, string const & token, } else if (token == "\\begin_includeonly") { readIncludeonly(lex); } else if (token == "\\maintain_unincluded_children") { - lex >> maintain_unincluded_children; + string tmp; + lex >> tmp; + if (tmp == "no") + maintain_unincluded_children = CM_None; + else if (tmp == "mostly") + maintain_unincluded_children = CM_Mostly; + else if (tmp == "strict") + maintain_unincluded_children = CM_Strict; } else if (token == "\\options") { lex.eatLine(); options = lex.getString(); @@ -843,14 +893,24 @@ string BufferParams::readToken(Lexer & lex, string const & token, lex >> useNonTeXFonts; } else if (token == "\\font_sc") { lex >> fonts_expert_sc; - } else if (token == "\\font_osf") { - lex >> fonts_old_figures; + } else if (token == "\\font_roman_osf") { + lex >> fonts_roman_osf; + } else if (token == "\\font_sans_osf") { + lex >> fonts_sans_osf; + } else if (token == "\\font_typewriter_osf") { + lex >> fonts_typewriter_osf; + } else if (token == "\\font_roman_opts") { + lex >> font_roman_opts; } else if (token == "\\font_sf_scale") { lex >> fonts_sans_scale[0]; lex >> fonts_sans_scale[1]; + } else if (token == "\\font_sans_opts") { + lex >> font_sans_opts; } else if (token == "\\font_tt_scale") { lex >> fonts_typewriter_scale[0]; lex >> fonts_typewriter_scale[1]; + } else if (token == "\\font_typewriter_opts") { + lex >> font_typewriter_opts; } else if (token == "\\font_cjk") { lex >> fonts_cjk; } else if (token == "\\use_microtype") { @@ -940,6 +1000,10 @@ string BufferParams::readToken(Lexer & lex, string const & token, lex >> track_changes; } else if (token == "\\output_changes") { lex >> output_changes; + } else if (token == "\\change_bars") { + lex >> change_bars; + } else if (token == "\\postpone_fragile_content") { + lex >> postpone_fragile_content; } else if (token == "\\branch") { lex.eatLine(); docstring branch = lex.getDocString(); @@ -962,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") { @@ -996,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()); @@ -1025,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") { @@ -1110,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") { @@ -1118,6 +1203,11 @@ string BufferParams::readToken(Lexer & lex, string const & token, lex >> use_refstyle; } else if (token == "\\use_minted") { lex >> use_minted; + } else if (token == "\\use_lineno") { + lex >> use_lineno; + } else if (token == "\\lineno_options") { + lex.eatLine(); + lineno_opts = trim(lex.getString()); } else { lyxerr << "BufferParams::readToken(): Unknown token: " << token << endl; @@ -1167,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 @@ -1193,34 +1292,39 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const // removed modules if (!removed_modules_.empty()) { os << "\\begin_removed_modules" << '\n'; - list::const_iterator it = removed_modules_.begin(); - list::const_iterator en = removed_modules_.end(); - for (; it != en; ++it) - os << *it << '\n'; + for (auto const & mod : removed_modules_) + os << mod << '\n'; os << "\\end_removed_modules" << '\n'; } // the modules if (!layout_modules_.empty()) { os << "\\begin_modules" << '\n'; - LayoutModuleList::const_iterator it = layout_modules_.begin(); - LayoutModuleList::const_iterator en = layout_modules_.end(); - for (; it != en; ++it) - os << *it << '\n'; + for (auto const & mod : layout_modules_) + os << mod << '\n'; os << "\\end_modules" << '\n'; } // includeonly if (!included_children_.empty()) { os << "\\begin_includeonly" << '\n'; - list::const_iterator it = included_children_.begin(); - list::const_iterator en = included_children_.end(); - for (; it != en; ++it) - os << *it << '\n'; + for (auto const & c : included_children_) + os << c << '\n'; os << "\\end_includeonly" << '\n'; } - os << "\\maintain_unincluded_children " - << convert(maintain_unincluded_children) << '\n'; + string muc = "no"; + switch (maintain_unincluded_children) { + case CM_Mostly: + muc = "mostly"; + break; + case CM_Strict: + muc = "strict"; + break; + case CM_None: + default: + break; + } + os << "\\maintain_unincluded_children " << muc << '\n'; // local layout information docstring const local_layout = getLocalLayout(false); @@ -1257,15 +1361,22 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << "\n\\font_default_family " << fonts_default_family << "\n\\use_non_tex_fonts " << convert(useNonTeXFonts) << "\n\\font_sc " << convert(fonts_expert_sc) - << "\n\\font_osf " << convert(fonts_old_figures) - << "\n\\font_sf_scale " << fonts_sans_scale[0] - << ' ' << fonts_sans_scale[1] - << "\n\\font_tt_scale " << fonts_typewriter_scale[0] - << ' ' << fonts_typewriter_scale[1] - << '\n'; - if (!fonts_cjk.empty()) { + << "\n\\font_roman_osf " << convert(fonts_roman_osf) + << "\n\\font_sans_osf " << convert(fonts_sans_osf) + << "\n\\font_typewriter_osf " << convert(fonts_typewriter_osf); + if (!font_roman_opts.empty()) + os << "\n\\font_roman_opts \"" << font_roman_opts << "\""; + os << "\n\\font_sf_scale " << fonts_sans_scale[0] + << ' ' << fonts_sans_scale[1]; + if (!font_sans_opts.empty()) + os << "\n\\font_sans_opts \"" << font_sans_opts << "\""; + os << "\n\\font_tt_scale " << fonts_typewriter_scale[0] + << ' ' << fonts_typewriter_scale[1]; + if (!font_typewriter_opts.empty()) + os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\""; + os << '\n'; + if (!fonts_cjk.empty()) os << "\\font_cjk " << fonts_cjk << '\n'; - } os << "\\use_microtype " << convert(use_microtype) << '\n'; os << "\\use_dash_ligatures " << convert(use_dash_ligatures) << '\n'; os << "\\graphics " << graphics_driver << '\n'; @@ -1288,10 +1399,9 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const os << "\\papersize " << string_papersize[papersize] << "\n\\use_geometry " << convert(use_geometry); map const & packages = auto_packages(); - for (map::const_iterator it = packages.begin(); - it != packages.end(); ++it) - os << "\n\\use_package " << it->first << ' ' - << use_package(it->first); + for (auto const & pack : packages) + os << "\n\\use_package " << pack.first << ' ' + << use_package(pack.first); os << "\n\\cite_engine "; @@ -1320,37 +1430,44 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << "\n\\justification " << convert(justification) << "\n\\use_refstyle " << use_refstyle << "\n\\use_minted " << use_minted + << "\n\\use_lineno " << use_lineno << '\n'; - if (isbackgroundcolor == true) + + if (!lineno_opts.empty()) + os << "\\lineno_options " << lineno_opts << '\n'; + + 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'; - BranchList::const_iterator it = branchlist().begin(); - BranchList::const_iterator end = branchlist().end(); - for (; it != end; ++it) { - os << "\\branch " << to_utf8(it->branch()) - << "\n\\selected " << it->isSelected() - << "\n\\filename_suffix " << it->hasFileNameSuffix() - << "\n\\color " << lyx::X11hexname(it->color()) + for (auto const & br : branchlist()) { + os << "\\branch " << to_utf8(br.branch()) + << "\n\\selected " << br.isSelected() + << "\n\\filename_suffix " << br.hasFileNameSuffix() + << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor() << "\n\\end_branch" << "\n"; } - IndicesList::const_iterator iit = indiceslist().begin(); - IndicesList::const_iterator iend = indiceslist().end(); - for (; iit != iend; ++iit) { - os << "\\index " << to_utf8(iit->index()) - << "\n\\shortcut " << to_utf8(iit->shortcut()) - << "\n\\color " << lyx::X11hexname(iit->color()) + for (auto const & id : indiceslist()) { + os << "\\index " << to_utf8(id.index()) + << "\n\\shortcut " << to_utf8(id.shortcut()) + << "\n\\color " << lyx::X11hexname(id.color()) << "\n\\end_index" << "\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'; @@ -1406,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 @@ -1440,10 +1557,19 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << (save_transient_properties ? convert(output_changes) : "false") << '\n'; + os << "\\change_bars " + << (save_transient_properties ? convert(change_bars) : "false") + << '\n'; + + os << "\\postpone_fragile_content " << convert(postpone_fragile_content) << '\n'; + os << "\\html_math_output " << html_math_output << '\n' << "\\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()) @@ -1457,23 +1583,19 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const void BufferParams::validate(LaTeXFeatures & features) const { - features.require(documentClass().requires()); + features.require(documentClass().required()); if (columns > 1 && language->rightToLeft()) features.require("rtloutputdblcol"); if (output_changes) { - bool dvipost = LaTeXFeatures::isAvailable("dvipost"); bool xcolorulem = LaTeXFeatures::isAvailable("ulem") && LaTeXFeatures::isAvailable("xcolor"); switch (features.runparams().flavor) { - case OutputParams::LATEX: - case OutputParams::DVILUATEX: - if (dvipost) { - features.require("ct-dvipost"); - features.require("dvipost"); - } else if (xcolorulem) { + case Flavor::LaTeX: + case Flavor::DviLuaTeX: + if (xcolorulem) { features.require("ct-xcolor-ulem"); features.require("ulem"); features.require("xcolor"); @@ -1481,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"); @@ -1497,21 +1619,22 @@ void BufferParams::validate(LaTeXFeatures & features) const default: break; } + if (change_bars) + features.require("changebar"); } // Floats with 'Here definitely' as default setting. if (float_placement.find('H') != string::npos) features.require("float"); - for (PackageMap::const_iterator it = use_packages.begin(); - it != use_packages.end(); ++it) { - if (it->first == "amsmath") { + for (auto const & pm : use_packages) { + if (pm.first == "amsmath") { // AMS Style is at document level - if (it->second == package_on || + if (pm.second == package_on || features.isProvided("amsmath")) - features.require(it->first); - } else if (it->second == package_on) - features.require(it->first); + features.require(pm.first); + } else if (pm.second == package_on) + features.require(pm.first); } // Document-level line spacing @@ -1568,14 +1691,64 @@ void BufferParams::validate(LaTeXFeatures & features) const if (use_microtype) features.require("microtype"); - if (!language->requires().empty()) - features.require(language->requires()); + if (!language->required().empty()) + features.require(language->required()); } 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 @@ -1599,69 +1772,18 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, if (tokenPos(tclass.opt_fontsize(), '|', fontsize) >= 0) { // only write if existing in list (and not default) - clsoptions << fontsize << "pt,"; + clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ","; } - // all paper sizes except of A4, A5, B5 and the US sizes need the + // paper sizes not supported by the class itself need the // geometry package - bool nonstandard_papersize = papersize != PAPER_DEFAULT - && papersize != PAPER_USLETTER - && papersize != PAPER_USLEGAL - && papersize != PAPER_USEXECUTIVE - && papersize != PAPER_A4 - && papersize != PAPER_A5 - && papersize != PAPER_B5; - - if (!use_geometry) { - switch (papersize) { - case PAPER_A4: - clsoptions << "a4paper,"; - break; - case PAPER_USLETTER: - clsoptions << "letterpaper,"; - break; - case PAPER_A5: - clsoptions << "a5paper,"; - break; - case PAPER_B5: - clsoptions << "b5paper,"; - break; - case PAPER_USEXECUTIVE: - clsoptions << "executivepaper,"; - break; - case PAPER_USLEGAL: - clsoptions << "legalpaper,"; - break; - case PAPER_DEFAULT: - case PAPER_A0: - case PAPER_A1: - case PAPER_A2: - case PAPER_A3: - case PAPER_A6: - case PAPER_B0: - case PAPER_B1: - case PAPER_B2: - case PAPER_B3: - case PAPER_B4: - case PAPER_B6: - case PAPER_C0: - case PAPER_C1: - case PAPER_C2: - case PAPER_C3: - case PAPER_C4: - case PAPER_C5: - case PAPER_C6: - case PAPER_JISB0: - case PAPER_JISB1: - case PAPER_JISB2: - case PAPER_JISB3: - case PAPER_JISB4: - case PAPER_JISB5: - case PAPER_JISB6: - case PAPER_CUSTOM: - break; - } - } + vector classpsizes = getVectorFromString(tclass.opt_pagesize(), "|"); + bool class_supported_papersize = papersize == PAPER_DEFAULT + || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end(); + + if ((!use_geometry || features.isProvided("geometry-light")) + && class_supported_papersize && papersize != PAPER_DEFAULT) + clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ","; // if needed if (sides != tclass.sides()) { @@ -1731,20 +1853,63 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, if (!options.empty()) { clsoptions << options << ','; } - - string strOptions(clsoptions.str()); + + docstring const strOptions = from_utf8(clsoptions.str()); if (!strOptions.empty()) { - strOptions = rtrim(strOptions, ","); - // FIXME UNICODE - os << '[' << from_utf8(strOptions) << ']'; + // Check if class options contain uncodable glyphs + docstring uncodable_glyphs; + docstring options_encodable; + Encoding const * const enc = features.runparams().encoding; + if (enc) { + for (char_type c : strOptions) { + if (!enc->encodable(c)) { + docstring const glyph(1, c); + LYXERR0("Uncodable character '" + << glyph + << "' in class options!"); + uncodable_glyphs += glyph; + if (features.runparams().dryrun) { + options_encodable += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + options_encodable += c; + options_encodable += "'>"; + } + } else + options_encodable += c; + } + } else + options_encodable = strOptions; + + // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs + if (!features.runparams().dryrun && !uncodable_glyphs.empty()) { + frontend::Alert::warning( + _("Uncodable character in class options"), + support::bformat( + _("The class options of your document contain 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 " + "class options accordingly."), + uncodable_glyphs)); + } + options_encodable = rtrim(options_encodable, ","); + os << '[' << options_encodable << ']'; } os << '{' << from_ascii(tclass.latexname()) << "}\n"; // end of \documentclass defs + // The package options (via \PassOptionsToPackage) + os << from_ascii(features.getPackageOptions()); + // 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"; @@ -1752,7 +1917,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, os << from_ascii(ams); if (useNonTeXFonts) { - if (!features.isProvided("fontspec")) + // Babel (as of 2017/11/03) loads fontspec itself + if (!features.isProvided("fontspec") + && !(features.useBabel() && features.isAvailable("babel-2017/11/03"))) os << "\\usepackage{fontspec}\n"; if (features.mustProvide("unicode-math") && features.isAvailable("unicode-math")) @@ -1770,8 +1937,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, } // font selection must be done before loading fontenc.sty + // but after babel with non-TeX fonts string const fonts = loadFonts(features); - if (!fonts.empty()) + if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts)) os << from_utf8(fonts); if (fonts_default_family != "default") @@ -1781,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 @@ -1805,19 +1973,16 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // (In documents containing text in Thai language, // we must load inputenc after babel, see lib/languages). if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf"))) - writeEncodingPreamble(os, features); + writeEncodingPreamble(os, features); // includeonly if (!features.runparams().includeall && !included_children_.empty()) { os << "\\includeonly{"; - list::const_iterator it = included_children_.begin(); - list::const_iterator en = included_children_.end(); bool first = true; - for (; it != en; ++it) { - string incfile = *it; + for (auto incfile : included_children_) { FileName inc = makeAbsPath(incfile, filepath.absFileName()); string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")). - mangledFileName(); + mangledFileName(); if (!features.runparams().nice) incfile = mangled; // \includeonly doesn't want an extension @@ -1834,7 +1999,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, } if (!features.isProvided("geometry") - && (use_geometry || nonstandard_papersize)) { + && (use_geometry || !class_supported_papersize)) { odocstringstream ods; if (!getGraphicsDriver("geometry").empty()) ods << getGraphicsDriver("geometry"); @@ -1850,126 +2015,77 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, << from_ascii(paperheight); break; case PAPER_USLETTER: - ods << ",letterpaper"; - break; case PAPER_USLEGAL: - ods << ",legalpaper"; - break; case PAPER_USEXECUTIVE: - ods << ",executivepaper"; - break; case PAPER_A0: - ods << ",a0paper"; - break; case PAPER_A1: - ods << ",a1paper"; - break; case PAPER_A2: - ods << ",a2paper"; - break; case PAPER_A3: - ods << ",a3paper"; - break; case PAPER_A4: - ods << ",a4paper"; - break; case PAPER_A5: - ods << ",a5paper"; - break; case PAPER_A6: - ods << ",a6paper"; - break; case PAPER_B0: - ods << ",b0paper"; - break; case PAPER_B1: - ods << ",b1paper"; - break; case PAPER_B2: - ods << ",b2paper"; - break; case PAPER_B3: - ods << ",b3paper"; - break; case PAPER_B4: - ods << ",b4paper"; - break; case PAPER_B5: - ods << ",b5paper"; - break; case PAPER_B6: - ods << ",b6paper"; - break; case PAPER_C0: - ods << ",c0paper"; - break; case PAPER_C1: - ods << ",c1paper"; - break; case PAPER_C2: - ods << ",c2paper"; - break; case PAPER_C3: - ods << ",c3paper"; - break; case PAPER_C4: - ods << ",c4paper"; - break; case PAPER_C5: - ods << ",c5paper"; - break; case PAPER_C6: - ods << ",c6paper"; - break; case PAPER_JISB0: - ods << ",b0j"; - break; case PAPER_JISB1: - ods << ",b1j"; - break; case PAPER_JISB2: - ods << ",b2j"; - break; case PAPER_JISB3: - ods << ",b3j"; - break; case PAPER_JISB4: - ods << ",b4j"; - break; case PAPER_JISB5: - ods << ",b5j"; - break; case PAPER_JISB6: - ods << ",b6j"; + ods << "," << from_ascii(string_papersize_geometry[papersize]); break; case PAPER_DEFAULT: break; } - docstring const g_options = trim(ods.str(), ","); + docstring g_options = trim(ods.str(), ","); os << "\\usepackage"; - if (!g_options.empty()) + // geometry-light means that the class works with geometry, but overwrites + // the package options and paper sizes (memoir does this). + // In this case, all options need to go to \geometry + // and the standard paper sizes need to go to the class options. + if (!g_options.empty() && !features.isProvided("geometry-light")) { os << '[' << g_options << ']'; + g_options.clear(); + } os << "{geometry}\n"; - // output this only if use_geometry is true - if (use_geometry) { + if (use_geometry || features.isProvided("geometry-light")) { os << "\\geometry{verbose"; - if (!topmargin.empty()) - os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString()); - if (!bottommargin.empty()) - os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString()); - if (!leftmargin.empty()) - os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString()); - if (!rightmargin.empty()) - os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString()); - if (!headheight.empty()) - os << ",headheight=" << from_ascii(Length(headheight).asLatexString()); - if (!headsep.empty()) - os << ",headsep=" << from_ascii(Length(headsep).asLatexString()); - if (!footskip.empty()) - os << ",footskip=" << from_ascii(Length(footskip).asLatexString()); - if (!columnsep.empty()) - os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString()); - os << "}\n"; + if (!g_options.empty()) + // Output general options here with "geometry light". + os << "," << g_options; + // output this only if use_geometry is true + if (use_geometry) { + if (!topmargin.empty()) + os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString()); + if (!bottommargin.empty()) + os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString()); + if (!leftmargin.empty()) + os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString()); + if (!rightmargin.empty()) + os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString()); + if (!headheight.empty()) + os << ",headheight=" << from_ascii(Length(headheight).asLatexString()); + if (!headsep.empty()) + os << ",headsep=" << from_ascii(Length(headsep).asLatexString()); + if (!footskip.empty()) + os << ",footskip=" << from_ascii(Length(footskip).asLatexString()); + if (!columnsep.empty()) + os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString()); + } + os << "}\n"; } } else if (orientation == ORIENTATION_LANDSCAPE || papersize != PAPER_DEFAULT) { @@ -1983,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 @@ -1992,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 @@ -2016,26 +2132,36 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, if (paragraph_separation) { // when skip separation + string psopt; switch (getDefSkip().kind()) { case VSpace::SMALLSKIP: - os << "\\setlength{\\parskip}{\\smallskipamount}\n"; + psopt = "\\smallskipamount"; break; case VSpace::MEDSKIP: - os << "\\setlength{\\parskip}{\\medskipamount}\n"; + psopt = "\\medskipamount"; break; case VSpace::BIGSKIP: - os << "\\setlength{\\parskip}{\\bigskipamount}\n"; + psopt = "\\bigskipamount"; + break; + case VSpace::HALFLINE: + // default (no option) + break; + case VSpace::FULLLINE: + psopt = "\\baselineskip"; break; case VSpace::LENGTH: - os << "\\setlength{\\parskip}{" - << from_utf8(getDefSkip().length().asLatexString()) - << "}\n"; + psopt = getDefSkip().length().asLatexString(); break; - default: // should never happen // Then delete it. - os << "\\setlength{\\parskip}{\\medskipamount}\n"; + default: break; } - os << "\\setlength{\\parindent}{0pt}\n"; + if (!features.isProvided("parskip")) { + if (!psopt.empty()) + psopt = "[skip=" + psopt + "]"; + os << "\\usepackage" + psopt + "{parskip}\n"; + } else { + os << "\\setlength{\\parskip}{" + psopt + "}\n"; + } } else { // when separation by indentation // only output something when a width is given @@ -2063,15 +2189,12 @@ 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"; } - // The package options (via \PassOptionsToPackage) - os << from_ascii(features.getPackageOptions()); - // due to interferences with babel and hyperref, the color package has to // be loaded (when it is not already loaded) before babel when hyperref // is used with the colorlinks option, see @@ -2099,11 +2222,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // Additional Indices if (features.isRequired("splitidx")) { - IndicesList::const_iterator iit = indiceslist().begin(); - IndicesList::const_iterator iend = indiceslist().end(); - for (; iit != iend; ++iit) { + for (auto const & idx : indiceslist()) { os << "\\newindex{"; - os << escape(iit->shortcut()); + os << escape(idx.shortcut()); os << "}\n"; } } @@ -2132,6 +2253,14 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // hyperref loads this automatically os << "\\usepackage{nameref}\n"; + if (use_lineno){ + os << "\\usepackage"; + if (!lineno_opts.empty()) + os << "[" << lineno_opts << "]"; + os << "{lineno}\n"; + os << "\\linenumbers\n"; + } + // bibtopic needs to be loaded after hyperref. // the dot provides the aux file naming which LyX can detect. if (features.mustProvide("bibtopic")) @@ -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 @@ -2292,7 +2422,11 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // In documents containing text in Thai language, // we must load inputenc after babel (see lib/languages). if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf"))) - writeEncodingPreamble(os, features); + writeEncodingPreamble(os, features); + + // font selection must be done after babel with non-TeX fonts + if (!fonts.empty() && features.useBabel() && useNonTeXFonts) + os << from_utf8(fonts); if (features.isRequired("bicaption")) os << "\\usepackage{bicaption}\n"; @@ -2336,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"; } @@ -2359,15 +2493,14 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, // now setup the other languages set const polylangs = features.getPolyglossiaLanguages(); - for (set::const_iterator mit = polylangs.begin(); - mit != polylangs.end() ; ++mit) { + for (auto const & pl : polylangs) { // We do not output the options here; they are output in // the language switch commands. This is safer if multiple // varieties are used. - if (*mit == language->polyglossia()) + if (pl == language->polyglossia()) continue; os << "\\setotherlanguage"; - os << "{" << from_ascii(*mit) << "}\n"; + os << "{" << from_ascii(pl) << "}\n"; } } @@ -2543,8 +2676,8 @@ LayoutFile const * BufferParams::baseClass() const { if (LayoutFileList::get().haveClass(pimpl_->baseClass_)) return &(LayoutFileList::get()[pimpl_->baseClass_]); - else - return 0; + + return nullptr; } @@ -2554,19 +2687,17 @@ LayoutFileIndex const & BufferParams::baseClassID() const } -void BufferParams::makeDocumentClass(bool const clone) +void BufferParams::makeDocumentClass(bool clone, bool internal) { if (!baseClass()) return; invalidateConverterCache(); LayoutModuleList mods; - LayoutModuleList::iterator it = layout_modules_.begin(); - LayoutModuleList::iterator en = layout_modules_.end(); - for (; it != en; ++it) - mods.push_back(*it); + 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()) @@ -2608,10 +2739,8 @@ void BufferParams::setLocalLayout(docstring const & layout, bool forced) bool BufferParams::addLayoutModule(string const & modName) { - LayoutModuleList::const_iterator it = layout_modules_.begin(); - LayoutModuleList::const_iterator end = layout_modules_.end(); - for (; it != end; ++it) - if (*it == modName) + for (auto const & mod : layout_modules_) + if (mod == modName) return false; layout_modules_.push_back(modName); return true; @@ -2627,10 +2756,8 @@ string BufferParams::bufferFormat() const bool BufferParams::isExportable(string const & format, bool need_viewable) const { FormatList const & formats = exportableFormats(need_viewable); - FormatList::const_iterator fit = formats.begin(); - FormatList::const_iterator end = formats.end(); - for (; fit != end ; ++fit) { - if ((*fit)->name() == format) + for (auto const & fmt : formats) { + if (fmt->name() == format) return true; } return false; @@ -2651,15 +2778,15 @@ FormatList const & BufferParams::exportableFormats(bool only_viewable) const if (useNonTeXFonts) { excludes.insert("latex"); excludes.insert("pdflatex"); - } else if (inputenc != "ascii" && inputenc != "utf8" - && inputenc != "utf8x" && inputenc != "utf8-plain") - // XeTeX with TeX fonts requires input encoding ascii or utf8 - // (https://www.tug.org/pipermail/xetex/2010-April/016452.html). + } else if (inputenc != "ascii" && inputenc != "utf8-plain") { + // XeTeX with TeX fonts requires input encoding ascii (#10600). excludes.insert("xetex"); - FormatList result = theConverters().getReachable(backs[0], only_viewable, - true, excludes); - for (vector::const_iterator it = backs.begin() + 1; - it != backs.end(); ++it) { + } + + 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()); @@ -2685,8 +2812,8 @@ vector BufferParams::backends() const v.push_back("pdflatex"); v.push_back("latex"); } - if (useNonTeXFonts || inputenc == "ascii" || inputenc == "utf8" - || inputenc == "utf8x" || inputenc == "utf8-plain") + if (useNonTeXFonts + || inputenc == "ascii" || inputenc == "utf8-plain") v.push_back("xetex"); v.push_back("luatex"); v.push_back("dviluatex"); @@ -2703,13 +2830,14 @@ vector BufferParams::backends() const } v.push_back("xhtml"); + v.push_back("docbook5"); v.push_back("text"); v.push_back("lyx"); return v; } -OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const +Flavor BufferParams::getOutputFlavor(string const & format) const { string const dformat = (format.empty() || format == "default") ? getDefaultOutputFormat() : format; @@ -2719,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(); @@ -2764,13 +2894,6 @@ string BufferParams::getDefaultOutputFormat() const if (!default_output_format.empty() && default_output_format != "default") return default_output_format; - if (isDocBook()) { - FormatList const & formats = exportableFormats(true); - if (formats.empty()) - return string(); - // return the first we find - return formats.front()->name(); - } if (encoding().package() == Encoding::japanese) return lyxrc.default_platex_view_format; if (useNonTeXFonts) @@ -2791,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); } @@ -2809,12 +2932,6 @@ bool BufferParams::isLiterate() const } -bool BufferParams::isDocBook() const -{ - return documentClass().outputType() == DOCBOOK; -} - - void BufferParams::readPreamble(Lexer & lex) { if (lex.getString() != "\\begin_preamble") @@ -2825,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" : @@ -2964,12 +3091,10 @@ void BufferParams::readRemovedModules(Lexer & lex) // added. normally, that will be because default modules were added in // setBaseClass(), which gets called when \textclass is read at the // start of the read. - list::const_iterator rit = removed_modules_.begin(); - list::const_iterator const ren = removed_modules_.end(); - for (; rit != ren; ++rit) { + for (auto const & rm : removed_modules_) { LayoutModuleList::iterator const mit = layout_modules_.begin(); LayoutModuleList::iterator const men = layout_modules_.end(); - LayoutModuleList::iterator found = find(mit, men, *rit); + LayoutModuleList::iterator found = find(mit, men, rm); if (found == men) continue; layout_modules_.erase(found); @@ -2994,12 +3119,15 @@ void BufferParams::readIncludeonly(Lexer & lex) } -string BufferParams::paperSizeName(PapersizePurpose purpose) const +string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const { - switch (papersize) { + PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize); + switch (ppsize) { case PAPER_DEFAULT: - // could be anything, so don't guess - return string(); + if (documentClass().pagesize() == "default") + // could be anything, so don't guess + return string(); + return paperSizeName(purpose, documentClass().pagesize()); case PAPER_CUSTOM: { if (purpose == XDVI && !paperwidth.empty() && !paperheight.empty()) { @@ -3179,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(); } @@ -3199,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); @@ -3262,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); @@ -3287,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"; @@ -3310,16 +3440,24 @@ void BufferParams::writeEncodingPreamble(otexstream & os, if (features.isRequired("japanese") || features.isProvided("inputenc")) break; - if (features.runparams().flavor == OutputParams::XETEX) - os << xetex_pre_inputenc; - 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"; - if (features.runparams().flavor == OutputParams::XETEX) - os << xetex_post_inputenc; break; } } @@ -3372,64 +3510,115 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const // variants are understood by both engines. However, // we want to provide support for at least TeXLive 2009 // (for XeTeX; LuaTeX is only supported as of v.2) + // As of 2017/11/03, Babel has its own higher-level + // interface on top of fontspec that is to be used. + 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") { - os << "\\setmainfont[" << texmapping; - if (fonts_old_figures) + if (babelfonts) + os << "\\babelfont{rm}["; + else + os << "\\setmainfont["; + if (!font_roman_opts.empty()) + os << font_roman_opts << ','; + os << texmapping; + if (fonts_roman_osf) os << ",Numbers=OldStyle"; os << "]{" << parseFontName(fontsRoman()) << "}\n"; } if (fontsSans() != "default") { string const sans = parseFontName(fontsSans()); - if (fontsSansScale() != 100) - os << "\\setsansfont[Scale=" - << float(fontsSansScale()) / 100 - << "," << texmapping << "]{" + if (fontsSansScale() != 100) { + if (babelfonts) + os << "\\babelfont{sf}"; + else + os << "\\setsansfont"; + os << "[Scale=" + << float(fontsSansScale()) / 100 << ','; + if (fonts_sans_osf) + os << "Numbers=OldStyle,"; + if (!font_sans_opts.empty()) + os << font_sans_opts << ','; + os << texmapping << "]{" << sans << "}\n"; - else - os << "\\setsansfont[" << texmapping << "]{" + } else { + if (babelfonts) + os << "\\babelfont{sf}["; + else + os << "\\setsansfont["; + if (fonts_sans_osf) + os << "Numbers=OldStyle,"; + if (!font_sans_opts.empty()) + os << font_sans_opts << ','; + os << texmapping << "]{" << sans << "}\n"; + } } if (fontsTypewriter() != "default") { string const mono = parseFontName(fontsTypewriter()); - if (fontsTypewriterScale() != 100) - os << "\\setmonofont[Scale=" - << float(fontsTypewriterScale()) / 100 - << "]{" - << mono << "}\n"; - else - os << "\\setmonofont{" + if (fontsTypewriterScale() != 100) { + if (babelfonts) + os << "\\babelfont{tt}"; + else + os << "\\setmonofont"; + os << "[Scale=" + << float(fontsTypewriterScale()) / 100; + if (fonts_typewriter_osf) + os << ",Numbers=OldStyle"; + if (!font_typewriter_opts.empty()) + os << ',' << font_typewriter_opts; + os << "]{" << mono << "}\n"; + } else { + if (babelfonts) + os << "\\babelfont{tt}"; + else + os << "\\setmonofont"; + if (!font_typewriter_opts.empty() || fonts_typewriter_osf) { + os << '['; + if (fonts_typewriter_osf) + os << "Numbers=OldStyle"; + if (!font_typewriter_opts.empty()) { + if (fonts_typewriter_osf) + os << ','; + os << font_typewriter_opts; + } + os << ']'; + } + os << '{' << mono << "}\n"; + } } return os.str(); } // 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( - dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures, - nomath); + dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf, + nomath, font_roman_opts); // SANS SERIF os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode( - dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures, - nomath, fontsSansScale()); + dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf, + nomath, font_sans_opts, fontsSansScale()); // MONOSPACED/TYPEWRITER os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode( - dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures, - nomath, fontsTypewriterScale()); + dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf, + nomath, font_typewriter_opts, fontsTypewriterScale()); // MATH os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode( - dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures, + dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf, nomath); return os.str(); @@ -3468,7 +3657,7 @@ string const & BufferParams::defaultBiblioStyle() const } -bool const & BufferParams::fullAuthorList() const +bool BufferParams::fullAuthorList() const { return documentClass().fullAuthorList(); } @@ -3510,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) @@ -3534,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()) { @@ -3568,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);