2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
25 #include "CiteEnginesList.h"
28 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
37 #include "OutputParams.h"
39 #include "texstream.h"
42 #include "PDFOptions.h"
44 #include "frontends/alert.h"
46 #include "insets/InsetListingsParams.h"
47 #include "insets/InsetQuotes.h"
49 #include "support/convert.h"
50 #include "support/debug.h"
51 #include "support/FileName.h"
52 #include "support/filetools.h"
53 #include "support/gettext.h"
54 #include "support/Length.h"
55 #include "support/Lexer.h"
56 #include "support/Messages.h"
57 #include "support/mutex.h"
58 #include "support/Package.h"
59 #include "support/Translator.h"
60 #include "support/lstrings.h"
66 using namespace lyx::support;
69 static char const * const string_paragraph_separation[] = {
74 static char const * const string_quotes_style[] = {
75 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76 "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
77 "hungarian", "hebrew", ""
81 static char const * const string_papersize[] = {
82 "default", "custom", "letter", "legal", "executive",
83 "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84 "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85 "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
90 static char const * const string_papersize_geometry[] = {
91 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93 "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94 "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95 "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
99 static char const * const string_orientation[] = {
100 "portrait", "landscape", ""
104 static char const * const tex_graphics[] = {
105 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
122 ParSepTranslator const init_parseptranslator()
124 ParSepTranslator translator
125 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
131 ParSepTranslator const & parseptranslator()
133 static ParSepTranslator const translator =
134 init_parseptranslator();
140 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
143 QuotesStyleTranslator const init_quotesstyletranslator()
145 QuotesStyleTranslator translator
146 (string_quotes_style[0], QuoteStyle::English);
147 translator.addPair(string_quotes_style[1], QuoteStyle::Swedish);
148 translator.addPair(string_quotes_style[2], QuoteStyle::German);
149 translator.addPair(string_quotes_style[3], QuoteStyle::Polish);
150 translator.addPair(string_quotes_style[4], QuoteStyle::Swiss);
151 translator.addPair(string_quotes_style[5], QuoteStyle::Danish);
152 translator.addPair(string_quotes_style[6], QuoteStyle::Plain);
153 translator.addPair(string_quotes_style[7], QuoteStyle::British);
154 translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG);
155 translator.addPair(string_quotes_style[9], QuoteStyle::French);
156 translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN);
157 translator.addPair(string_quotes_style[11], QuoteStyle::Russian);
158 translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
159 translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
160 translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
161 translator.addPair(string_quotes_style[15], QuoteStyle::Hebrew);
166 QuotesStyleTranslator const & quotesstyletranslator()
168 static QuotesStyleTranslator const translator =
169 init_quotesstyletranslator();
175 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
178 static PaperSizeTranslator initPaperSizeTranslator()
180 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
181 translator.addPair(string_papersize[1], PAPER_CUSTOM);
182 translator.addPair(string_papersize[2], PAPER_USLETTER);
183 translator.addPair(string_papersize[3], PAPER_USLEGAL);
184 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
185 translator.addPair(string_papersize[5], PAPER_A0);
186 translator.addPair(string_papersize[6], PAPER_A1);
187 translator.addPair(string_papersize[7], PAPER_A2);
188 translator.addPair(string_papersize[8], PAPER_A3);
189 translator.addPair(string_papersize[9], PAPER_A4);
190 translator.addPair(string_papersize[10], PAPER_A5);
191 translator.addPair(string_papersize[11], PAPER_A6);
192 translator.addPair(string_papersize[12], PAPER_B0);
193 translator.addPair(string_papersize[13], PAPER_B1);
194 translator.addPair(string_papersize[14], PAPER_B2);
195 translator.addPair(string_papersize[15], PAPER_B3);
196 translator.addPair(string_papersize[16], PAPER_B4);
197 translator.addPair(string_papersize[17], PAPER_B5);
198 translator.addPair(string_papersize[18], PAPER_B6);
199 translator.addPair(string_papersize[19], PAPER_C0);
200 translator.addPair(string_papersize[20], PAPER_C1);
201 translator.addPair(string_papersize[21], PAPER_C2);
202 translator.addPair(string_papersize[22], PAPER_C3);
203 translator.addPair(string_papersize[23], PAPER_C4);
204 translator.addPair(string_papersize[24], PAPER_C5);
205 translator.addPair(string_papersize[25], PAPER_C6);
206 translator.addPair(string_papersize[26], PAPER_JISB0);
207 translator.addPair(string_papersize[27], PAPER_JISB1);
208 translator.addPair(string_papersize[28], PAPER_JISB2);
209 translator.addPair(string_papersize[29], PAPER_JISB3);
210 translator.addPair(string_papersize[30], PAPER_JISB4);
211 translator.addPair(string_papersize[31], PAPER_JISB5);
212 translator.addPair(string_papersize[32], PAPER_JISB6);
217 PaperSizeTranslator const & papersizetranslator()
219 static PaperSizeTranslator const translator =
220 initPaperSizeTranslator();
226 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
229 PaperOrientationTranslator const init_paperorientationtranslator()
231 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
232 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
237 PaperOrientationTranslator const & paperorientationtranslator()
239 static PaperOrientationTranslator const translator =
240 init_paperorientationtranslator();
246 typedef Translator<int, PageSides> SidesTranslator;
249 SidesTranslator const init_sidestranslator()
251 SidesTranslator translator(1, OneSide);
252 translator.addPair(2, TwoSides);
257 SidesTranslator const & sidestranslator()
259 static SidesTranslator const translator = init_sidestranslator();
265 typedef Translator<int, BufferParams::Package> PackageTranslator;
268 PackageTranslator const init_packagetranslator()
270 PackageTranslator translator(0, BufferParams::package_off);
271 translator.addPair(1, BufferParams::package_auto);
272 translator.addPair(2, BufferParams::package_on);
277 PackageTranslator const & packagetranslator()
279 static PackageTranslator const translator =
280 init_packagetranslator();
286 typedef Translator<string, Spacing::Space> SpaceTranslator;
289 SpaceTranslator const init_spacetranslator()
291 SpaceTranslator translator("default", Spacing::Default);
292 translator.addPair("single", Spacing::Single);
293 translator.addPair("onehalf", Spacing::Onehalf);
294 translator.addPair("double", Spacing::Double);
295 translator.addPair("other", Spacing::Other);
300 SpaceTranslator const & spacetranslator()
302 static SpaceTranslator const translator = init_spacetranslator();
307 bool inSystemDir(FileName const & document_dir, string & system_dir)
309 // A document is assumed to be in a system LyX directory (not
310 // necessarily the system directory of the running instance)
311 // if both "configure.py" and "chkconfig.ltx" are found in
312 // either document_dir/../ or document_dir/../../.
313 // If true, the system directory path is returned in system_dir
314 // with a trailing path separator.
316 string const msg = "Checking whether document is in a system dir...";
318 string dir = document_dir.absFileName();
320 for (int i = 0; i < 3; ++i) {
321 dir = addPath(dir, "..");
322 if (!fileSearch(dir, "configure.py").empty() &&
323 !fileSearch(dir, "chkconfig.ltx").empty()) {
324 LYXERR(Debug::FILES, msg << " yes");
325 system_dir = addPath(FileName(dir).realPath(), "");
330 LYXERR(Debug::FILES, msg << " no");
331 system_dir = string();
338 class BufferParams::Impl
343 AuthorList authorlist;
345 BranchList branchlist;
346 WordLangTable spellignore;
347 Bullet temp_bullets[4];
348 Bullet user_defined_bullets[4];
349 IndicesList indiceslist;
353 /** This is the amount of space used for paragraph_separation "skip",
354 * and for detached paragraphs in "indented" documents.
357 PDFOptions pdfoptions;
358 LayoutFileIndex baseClass_;
359 FormatList exportableFormatList;
360 FormatList viewableFormatList;
361 bool isViewCacheValid;
362 bool isExportCacheValid;
366 BufferParams::Impl::Impl()
367 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
368 isViewCacheValid(false), isExportCacheValid(false)
370 // set initial author
372 authorlist.record(Author(from_utf8(lyxrc.user_name),
373 from_utf8(lyxrc.user_email),
374 from_utf8(lyxrc.user_initials)));
375 // set comparison author
376 authorlist.record(Author(from_utf8("Document Comparison"),
377 docstring(), docstring()));
382 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
385 return new BufferParams::Impl(*ptr);
389 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
395 BufferParams::BufferParams()
398 setBaseClass(defaultBaseclass());
399 cite_engine_ = "basic";
400 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
402 paragraph_separation = ParagraphIndentSeparation;
403 is_math_indent = false;
404 math_numbering_side = DEFAULT;
405 quotes_style = QuoteStyle::English;
406 dynamic_quotes = false;
407 fontsize = "default";
410 papersize = PAPER_DEFAULT;
411 orientation = ORIENTATION_PORTRAIT;
412 use_geometry = false;
413 biblio_style = string();
414 use_bibtopic = false;
417 use_memindex = false;
418 save_transient_properties = true;
419 track_changes = false;
420 output_changes = false;
422 postpone_fragile_content = true;
423 use_default_options = true;
424 maintain_unincluded_children = CM_None;
427 language = default_language;
429 fonts_roman[0] = "default";
430 fonts_roman[1] = "default";
431 fonts_sans[0] = "default";
432 fonts_sans[1] = "default";
433 fonts_typewriter[0] = "default";
434 fonts_typewriter[1] = "default";
435 fonts_math[0] = "auto";
436 fonts_math[1] = "auto";
437 fonts_default_family = "default";
438 useNonTeXFonts = false;
439 use_microtype = false;
440 use_dash_ligatures = true;
441 fonts_expert_sc = false;
442 fonts_roman_osf = false;
443 fonts_sans_osf = false;
444 fonts_typewriter_osf = false;
445 fonts_sans_scale[0] = 100;
446 fonts_sans_scale[1] = 100;
447 fonts_typewriter_scale[0] = 100;
448 fonts_typewriter_scale[1] = 100;
450 lang_package = "default";
451 graphics_driver = "default";
452 default_output_format = "default";
453 bibtex_command = "default";
454 index_command = "default";
457 listings_params = string();
458 pagestyle = "default";
459 tablestyle = "default";
460 float_alignment = "class";
461 float_placement = "class";
462 suppress_date = false;
463 justification = true;
464 // no color is the default (white)
465 backgroundcolor = lyx::rgbFromHexName("#ffffff");
466 isbackgroundcolor = false;
467 // no color is the default (black)
468 fontcolor = lyx::rgbFromHexName("#000000");
470 // light gray is the default font color for greyed-out notes
471 notefontcolor = lyx::rgbFromHexName("#cccccc");
472 isnotefontcolor = false;
473 boxbgcolor = lyx::rgbFromHexName("#ff0000");
474 isboxbgcolor = false;
475 compressed = lyxrc.save_compressed;
476 for (int iter = 0; iter < 4; ++iter) {
477 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
478 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
481 indiceslist().addDefault(B_("Index"));
482 html_be_strict = false;
483 html_math_output = MathML;
484 html_math_img_scale = 1.0;
485 html_css_as_file = false;
486 docbook_table_output = HTMLTable;
487 docbook_mathml_prefix = MPrefix;
488 display_pixel_ratio = 1.0;
490 shell_escape = false;
493 use_formatted_ref = false;
497 // map current author
498 pimpl_->authormap[pimpl_->authorlist.get(0).bufferId()] = 0;
502 docstring BufferParams::B_(string const & l10n) const
504 LASSERT(language, return from_utf8(l10n));
505 return getMessages(language->code()).get(l10n);
509 BufferParams::Package BufferParams::use_package(std::string const & p) const
511 PackageMap::const_iterator it = use_packages.find(p);
512 if (it == use_packages.end())
518 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
524 map<string, string> const & BufferParams::auto_packages()
526 static map<string, string> packages;
527 if (packages.empty()) {
528 // We could have a race condition here that two threads
529 // discover an empty map at the same time and want to fill
530 // it, but that is no problem, since the same contents is
531 // filled in twice then. Having the locker inside the
532 // packages.empty() condition has the advantage that we
533 // don't need the mutex overhead for simple reading.
535 Mutex::Locker locker(&mutex);
536 // adding a package here implies a file format change!
537 packages["amsmath"] =
538 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
539 packages["amssymb"] =
540 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
542 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
544 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
545 packages["mathdots"] =
546 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
547 packages["mathtools"] =
548 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
550 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
551 packages["stackrel"] =
552 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
553 packages["stmaryrd"] =
554 N_("The LaTeX package stmaryrd is only used if symbols from the St Mary's Road symbol font for theoretical computer science are inserted into formulas");
555 packages["undertilde"] =
556 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
562 bool BufferParams::useBibtopic() const
566 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
570 AuthorList & BufferParams::authors()
572 return pimpl_->authorlist;
576 AuthorList const & BufferParams::authors() const
578 return pimpl_->authorlist;
582 BufferParams::AuthorMap & BufferParams::authormap()
584 return pimpl_->authormap;
588 BufferParams::AuthorMap const & BufferParams::authormap() const
590 return pimpl_->authormap;
594 void BufferParams::addAuthor(Author const & a)
596 pimpl_->authormap[a.bufferId()] = pimpl_->authorlist.record(a);
600 BranchList & BufferParams::branchlist()
602 return pimpl_->branchlist;
606 BranchList const & BufferParams::branchlist() const
608 return pimpl_->branchlist;
612 IndicesList & BufferParams::indiceslist()
614 return pimpl_->indiceslist;
618 IndicesList const & BufferParams::indiceslist() const
620 return pimpl_->indiceslist;
624 WordLangTable & BufferParams::spellignore()
626 return pimpl_->spellignore;
630 WordLangTable const & BufferParams::spellignore() const
632 return pimpl_->spellignore;
636 bool BufferParams::spellignored(WordLangTuple const & wl) const
638 bool has_item = false;
639 vector<WordLangTuple> il = spellignore();
640 vector<WordLangTuple>::const_iterator it = il.begin();
641 for (; it != il.end(); ++it) {
642 if (it->lang()->code() != wl.lang()->code())
644 if (it->word() == wl.word()) {
653 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
655 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
656 return pimpl_->temp_bullets[index];
660 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
662 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
663 return pimpl_->temp_bullets[index];
667 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
669 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
670 return pimpl_->user_defined_bullets[index];
674 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
676 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
677 return pimpl_->user_defined_bullets[index];
681 Spacing & BufferParams::spacing()
683 return pimpl_->spacing;
687 Spacing const & BufferParams::spacing() const
689 return pimpl_->spacing;
693 PDFOptions & BufferParams::pdfoptions()
695 return pimpl_->pdfoptions;
699 PDFOptions const & BufferParams::pdfoptions() const
701 return pimpl_->pdfoptions;
705 Length const & BufferParams::getMathIndent() const
707 return pimpl_->mathindent;
711 void BufferParams::setMathIndent(Length const & indent)
713 pimpl_->mathindent = indent;
717 Length const & BufferParams::getParIndent() const
719 return pimpl_->parindent;
723 void BufferParams::setParIndent(Length const & indent)
725 pimpl_->parindent = indent;
729 VSpace const & BufferParams::getDefSkip() const
731 return pimpl_->defskip;
735 void BufferParams::setDefSkip(VSpace const & vs)
737 // DEFSKIP will cause an infinite loop
738 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
739 pimpl_->defskip = vs;
743 BufferParams::MathNumber BufferParams::getMathNumber() const
745 if (math_numbering_side != DEFAULT)
746 return math_numbering_side;
747 // FIXME: do not hardcode language here
748 else if (language->lang() == "arabic_arabi"
749 || documentClass().provides("leqno"))
756 string BufferParams::readToken(Lexer & lex, string const & token,
757 FileName const & filename)
760 FileName const & filepath = filename.onlyPath();
762 if (token == "\\textclass") {
764 string const classname = lex.getString();
765 // if there exists a local layout file, ignore the system one
766 // NOTE: in this case, the textclass (.cls file) is assumed to
769 LayoutFileList & bcl = LayoutFileList::get();
770 if (!filepath.empty()) {
771 // If classname is an absolute path, the document is
772 // using a local layout file which could not be accessed
773 // by a relative path. In this case the path is correct
774 // even if the document was moved to a different
775 // location. However, we will have a problem if the
776 // document was generated on a different platform.
777 bool isabsolute = FileName::isAbsolute(classname);
778 string const classpath = onlyPath(classname);
779 string const path = isabsolute ? classpath
780 : FileName(addPath(filepath.absFileName(),
781 classpath)).realPath();
782 string const oldpath = isabsolute ? string()
783 : FileName(addPath(origin, classpath)).realPath();
784 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
786 // that returns non-empty if a "local" layout file is found.
788 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
789 from_utf8(filepath.absFileName())));
792 setBaseClass(onlyFileName(tcp));
794 setBaseClass(onlyFileName(classname));
795 // We assume that a tex class exists for local or unknown
796 // layouts so this warning, will only be given for system layouts.
797 if (!baseClass()->isTeXClassAvailable()) {
798 docstring const desc =
799 translateIfPossible(from_utf8(baseClass()->description()));
800 docstring const prereqs =
801 from_utf8(baseClass()->prerequisites());
802 docstring const msg =
803 bformat(_("The selected document class\n"
805 "requires external files that are not available.\n"
806 "The document class can still be used, but the\n"
807 "document cannot be compiled until the following\n"
808 "prerequisites are installed:\n"
810 "See section 3.1.2.2 (Class Availability) of the\n"
811 "User's Guide for more information."), desc, prereqs);
812 frontend::Alert::warning(_("Document class not available"),
815 } else if (token == "\\save_transient_properties") {
816 lex >> save_transient_properties;
817 } else if (token == "\\origin") {
819 origin = lex.getString();
820 string const sysdirprefix = "/systemlyxdir/";
821 if (prefixIs(origin, sysdirprefix)) {
823 if (inSystemDir(filepath, docsys))
824 origin.replace(0, sysdirprefix.length() - 1, docsys);
826 origin.replace(0, sysdirprefix.length() - 1,
827 package().system_support().absFileName());
829 } else if (token == "\\begin_metadata") {
830 readDocumentMetadata(lex);
831 } else if (token == "\\begin_preamble") {
833 } else if (token == "\\begin_local_layout") {
834 readLocalLayout(lex, false);
835 } else if (token == "\\begin_forced_local_layout") {
836 readLocalLayout(lex, true);
837 } else if (token == "\\begin_modules") {
839 } else if (token == "\\begin_removed_modules") {
840 readRemovedModules(lex);
841 } else if (token == "\\begin_includeonly") {
842 readIncludeonly(lex);
843 } else if (token == "\\maintain_unincluded_children") {
847 maintain_unincluded_children = CM_None;
848 else if (tmp == "mostly")
849 maintain_unincluded_children = CM_Mostly;
850 else if (tmp == "strict")
851 maintain_unincluded_children = CM_Strict;
852 } else if (token == "\\options") {
854 options = lex.getString();
855 } else if (token == "\\use_default_options") {
856 lex >> use_default_options;
857 } else if (token == "\\master") {
859 master = lex.getString();
860 if (!filepath.empty() && FileName::isAbsolute(origin)) {
861 bool const isabs = FileName::isAbsolute(master);
862 FileName const abspath(isabs ? master : origin + master);
863 bool const moved = filepath != FileName(origin);
864 if (moved && abspath.exists()) {
865 docstring const path = isabs
867 : from_utf8(abspath.realPath());
868 docstring const refpath =
869 from_utf8(filepath.absFileName());
870 master = to_utf8(makeRelPath(path, refpath));
873 } else if (token == "\\suppress_date") {
874 lex >> suppress_date;
875 } else if (token == "\\justification") {
876 lex >> justification;
877 } else if (token == "\\language") {
879 } else if (token == "\\language_package") {
881 lang_package = lex.getString();
882 } else if (token == "\\language_options_babel") {
886 string const opts = lex.getString();
887 lang_options_babel_[lang] = trim(opts, "\"");
888 } else if (token == "\\language_options_polyglossia") {
892 string const opts = lex.getString();
893 lang_options_polyglossia_[lang] = trim(opts, "\"");
894 } else if (token == "\\inputencoding") {
896 } else if (token == "\\graphics") {
897 readGraphicsDriver(lex);
898 } else if (token == "\\default_output_format") {
899 lex >> default_output_format;
900 } else if (token == "\\bibtex_command") {
902 bibtex_command = lex.getString();
903 } else if (token == "\\index_command") {
905 index_command = lex.getString();
906 } else if (token == "\\fontencoding") {
908 fontenc = lex.getString();
909 } else if (token == "\\font_roman") {
910 lex >> fonts_roman[0];
911 lex >> fonts_roman[1];
912 } else if (token == "\\font_sans") {
913 lex >> fonts_sans[0];
914 lex >> fonts_sans[1];
915 } else if (token == "\\font_typewriter") {
916 lex >> fonts_typewriter[0];
917 lex >> fonts_typewriter[1];
918 } else if (token == "\\font_math") {
919 lex >> fonts_math[0];
920 lex >> fonts_math[1];
921 } else if (token == "\\font_default_family") {
922 lex >> fonts_default_family;
923 } else if (token == "\\use_non_tex_fonts") {
924 lex >> useNonTeXFonts;
925 } else if (token == "\\font_sc") {
926 lex >> fonts_expert_sc;
927 } else if (token == "\\font_roman_osf") {
928 lex >> fonts_roman_osf;
929 } else if (token == "\\font_sans_osf") {
930 lex >> fonts_sans_osf;
931 } else if (token == "\\font_typewriter_osf") {
932 lex >> fonts_typewriter_osf;
933 } else if (token == "\\font_roman_opts") {
934 lex >> font_roman_opts;
935 } else if (token == "\\font_sf_scale") {
936 lex >> fonts_sans_scale[0];
937 lex >> fonts_sans_scale[1];
938 } else if (token == "\\font_sans_opts") {
939 lex >> font_sans_opts;
940 } else if (token == "\\font_tt_scale") {
941 lex >> fonts_typewriter_scale[0];
942 lex >> fonts_typewriter_scale[1];
943 } else if (token == "\\font_typewriter_opts") {
944 lex >> font_typewriter_opts;
945 } else if (token == "\\font_cjk") {
947 } else if (token == "\\use_microtype") {
948 lex >> use_microtype;
949 } else if (token == "\\use_dash_ligatures") {
950 lex >> use_dash_ligatures;
951 } else if (token == "\\paragraph_separation") {
954 paragraph_separation = parseptranslator().find(parsep);
955 } else if (token == "\\paragraph_indentation") {
957 string parindent = lex.getString();
958 if (parindent == "default")
959 pimpl_->parindent = Length();
961 pimpl_->parindent = Length(parindent);
962 } else if (token == "\\defskip") {
964 string const defskip = lex.getString();
965 pimpl_->defskip = VSpace(defskip);
966 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
968 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
969 } else if (token == "\\is_math_indent") {
970 lex >> is_math_indent;
971 } else if (token == "\\math_indentation") {
973 string mathindent = lex.getString();
974 if (mathindent == "default")
975 pimpl_->mathindent = Length();
977 pimpl_->mathindent = Length(mathindent);
978 } else if (token == "\\math_numbering_side") {
982 math_numbering_side = LEFT;
983 else if (tmp == "right")
984 math_numbering_side = RIGHT;
986 math_numbering_side = DEFAULT;
987 } else if (token == "\\quotes_style") {
990 quotes_style = quotesstyletranslator().find(qstyle);
991 } else if (token == "\\dynamic_quotes") {
992 lex >> dynamic_quotes;
993 } else if (token == "\\papersize") {
996 papersize = papersizetranslator().find(ppsize);
997 } else if (token == "\\use_geometry") {
999 } else if (token == "\\use_package") {
1004 use_package(package, packagetranslator().find(use));
1005 } else if (token == "\\cite_engine") {
1007 cite_engine_ = lex.getString();
1008 } else if (token == "\\cite_engine_type") {
1011 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
1012 } else if (token == "\\biblio_style") {
1014 biblio_style = lex.getString();
1015 } else if (token == "\\biblio_options") {
1017 biblio_opts = trim(lex.getString());
1018 } else if (token == "\\biblatex_bibstyle") {
1020 biblatex_bibstyle = trim(lex.getString());
1021 } else if (token == "\\biblatex_citestyle") {
1023 biblatex_citestyle = trim(lex.getString());
1024 } else if (token == "\\use_bibtopic") {
1025 lex >> use_bibtopic;
1026 } else if (token == "\\multibib") {
1028 } else if (token == "\\use_indices") {
1030 } else if (token == "\\tracking_changes") {
1031 lex >> track_changes;
1032 } else if (token == "\\output_changes") {
1033 lex >> output_changes;
1034 } else if (token == "\\change_bars") {
1036 } else if (token == "\\postpone_fragile_content") {
1037 lex >> postpone_fragile_content;
1038 } else if (token == "\\branch") {
1040 docstring branch = lex.getDocString();
1041 branchlist().add(branch);
1044 string const tok = lex.getString();
1045 if (tok == "\\end_branch")
1047 Branch * branch_ptr = branchlist().find(branch);
1048 if (tok == "\\selected") {
1051 branch_ptr->setSelected(lex.getInteger());
1053 if (tok == "\\filename_suffix") {
1056 branch_ptr->setFileNameSuffix(lex.getInteger());
1058 if (tok == "\\color") {
1060 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1061 string const lmcolor = colors.front();
1063 if (colors.size() > 1)
1064 dmcolor = colors.back();
1066 branch_ptr->setColors(lmcolor, dmcolor);
1069 } else if (token == "\\index") {
1071 docstring index = lex.getDocString();
1073 indiceslist().add(index);
1076 string const tok = lex.getString();
1077 if (tok == "\\end_index")
1079 Index * index_ptr = indiceslist().find(index);
1080 if (tok == "\\shortcut") {
1082 shortcut = lex.getDocString();
1084 index_ptr->setShortcut(shortcut);
1086 if (tok == "\\color") {
1088 string color = lex.getString();
1090 index_ptr->setColor(color);
1091 // Update also the Color table:
1092 if (color == "none")
1093 color = lcolor.getX11HexName(Color_background);
1095 if (!shortcut.empty())
1096 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1099 } else if (token == "\\spellchecker_ignore") {
1101 docstring wl = lex.getDocString();
1103 docstring word = split(wl, language, ' ');
1104 Language const * lang = languages.getLanguage(to_ascii(language));
1106 spellignore().push_back(WordLangTuple(word, lang));
1107 } else if (token == "\\author") {
1109 istringstream ss(lex.getString());
1113 } else if (token == "\\paperorientation") {
1116 orientation = paperorientationtranslator().find(orient);
1117 } else if (token == "\\backgroundcolor") {
1119 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1120 isbackgroundcolor = true;
1121 } else if (token == "\\fontcolor") {
1123 fontcolor = lyx::rgbFromHexName(lex.getString());
1125 } else if (token == "\\notefontcolor") {
1127 string color = lex.getString();
1128 notefontcolor = lyx::rgbFromHexName(color);
1129 lcolor.setColor("notefontcolor", color);
1130 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1131 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1132 // set a local name for the painter
1133 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1134 isnotefontcolor = true;
1135 } else if (token == "\\boxbgcolor") {
1137 string color = lex.getString();
1138 boxbgcolor = lyx::rgbFromHexName(color);
1139 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1140 isboxbgcolor = true;
1141 } else if (token == "\\paperwidth") {
1143 } else if (token == "\\paperheight") {
1145 } else if (token == "\\leftmargin") {
1147 } else if (token == "\\topmargin") {
1149 } else if (token == "\\rightmargin") {
1151 } else if (token == "\\bottommargin") {
1152 lex >> bottommargin;
1153 } else if (token == "\\headheight") {
1155 } else if (token == "\\headsep") {
1157 } else if (token == "\\footskip") {
1159 } else if (token == "\\columnsep") {
1161 } else if (token == "\\paperfontsize") {
1163 } else if (token == "\\papercolumns") {
1165 } else if (token == "\\listings_params") {
1168 listings_params = InsetListingsParams(par).params();
1169 } else if (token == "\\papersides") {
1172 sides = sidestranslator().find(psides);
1173 } else if (token == "\\paperpagestyle") {
1175 } else if (token == "\\tablestyle") {
1177 } else if (token == "\\bullet") {
1179 } else if (token == "\\bulletLaTeX") {
1180 readBulletsLaTeX(lex);
1181 } else if (token == "\\secnumdepth") {
1183 } else if (token == "\\tocdepth") {
1185 } else if (token == "\\spacing") {
1189 if (nspacing == "other") {
1192 spacing().set(spacetranslator().find(nspacing), tmp_val);
1193 } else if (token == "\\float_placement") {
1194 lex >> float_placement;
1195 } else if (token == "\\float_alignment") {
1196 lex >> float_alignment;
1198 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1199 string toktmp = pdfoptions().readToken(lex, token);
1200 if (!toktmp.empty()) {
1201 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1205 } else if (token == "\\html_math_output") {
1208 html_math_output = static_cast<MathOutput>(temp);
1209 } else if (token == "\\html_be_strict") {
1210 lex >> html_be_strict;
1211 } else if (token == "\\html_css_as_file") {
1212 lex >> html_css_as_file;
1213 } else if (token == "\\html_math_img_scale") {
1214 lex >> html_math_img_scale;
1215 } else if (token == "\\html_latex_start") {
1217 html_latex_start = lex.getString();
1218 } else if (token == "\\html_latex_end") {
1220 html_latex_end = lex.getString();
1221 } else if (token == "\\docbook_table_output") {
1224 docbook_table_output = static_cast<TableOutput>(temp);
1225 } else if (token == "\\docbook_mathml_prefix") {
1228 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1229 } else if (token == "\\output_sync") {
1231 } else if (token == "\\output_sync_macro") {
1232 lex >> output_sync_macro;
1233 } else if (token == "\\use_refstyle") {
1234 lex >> use_refstyle;
1235 } else if (token == "\\use_formatted_ref") {
1236 lex >> use_formatted_ref;
1237 } else if (token == "\\use_minted") {
1239 } else if (token == "\\nomencl_options") {
1241 nomencl_opts = trim(lex.getString());
1242 } else if (token == "\\use_lineno") {
1244 } else if (token == "\\lineno_options") {
1246 lineno_opts = trim(lex.getString());
1248 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1258 // Quote argument if it contains spaces
1259 string quoteIfNeeded(string const & str) {
1260 if (contains(str, ' '))
1261 return "\"" + str + "\"";
1267 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1269 // The top of the file is written by the buffer.
1270 // Prints out the buffer info into the .lyx file given by file
1272 os << "\\save_transient_properties "
1273 << convert<string>(save_transient_properties) << '\n';
1275 // the document directory (must end with a path separator)
1276 // realPath() is used to resolve symlinks, while addPath(..., "")
1277 // ensures a trailing path separator.
1279 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1280 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1281 : addPath(package().system_support().realPath(), "");
1282 string const relpath =
1283 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1284 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1285 filepath = addPath("/systemlyxdir", relpath);
1286 else if (!save_transient_properties || !lyxrc.save_origin)
1287 filepath = "unavailable";
1288 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1291 os << "\\textclass "
1292 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1293 baseClass()->name()), "layout"))
1296 // then document metadata
1297 if (!document_metadata.empty()) {
1298 // remove '\n' from the end of document_metadata
1299 docstring const tmpmd = rtrim(document_metadata, "\n");
1300 os << "\\begin_metadata\n"
1302 << "\n\\end_metadata\n";
1305 // then the preamble
1306 if (!preamble.empty()) {
1307 // remove '\n' from the end of preamble
1308 docstring const tmppreamble = rtrim(preamble, "\n");
1309 os << "\\begin_preamble\n"
1310 << to_utf8(tmppreamble)
1311 << "\n\\end_preamble\n";
1315 if (!options.empty()) {
1316 os << "\\options " << options << '\n';
1319 // use the class options defined in the layout?
1320 os << "\\use_default_options "
1321 << convert<string>(use_default_options) << "\n";
1323 // the master document
1324 if (!master.empty()) {
1325 os << "\\master " << master << '\n';
1329 if (!removed_modules_.empty()) {
1330 os << "\\begin_removed_modules" << '\n';
1331 for (auto const & mod : removed_modules_)
1333 os << "\\end_removed_modules" << '\n';
1337 if (!layout_modules_.empty()) {
1338 os << "\\begin_modules" << '\n';
1339 for (auto const & mod : layout_modules_)
1341 os << "\\end_modules" << '\n';
1345 if (!included_children_.empty()) {
1346 os << "\\begin_includeonly" << '\n';
1347 for (auto const & c : included_children_)
1349 os << "\\end_includeonly" << '\n';
1352 switch (maintain_unincluded_children) {
1363 os << "\\maintain_unincluded_children " << muc << '\n';
1365 // local layout information
1366 docstring const local_layout = getLocalLayout(false);
1367 if (!local_layout.empty()) {
1368 // remove '\n' from the end
1369 docstring const tmplocal = rtrim(local_layout, "\n");
1370 os << "\\begin_local_layout\n"
1371 << to_utf8(tmplocal)
1372 << "\n\\end_local_layout\n";
1374 docstring const forced_local_layout = getLocalLayout(true);
1375 if (!forced_local_layout.empty()) {
1376 // remove '\n' from the end
1377 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1378 os << "\\begin_forced_local_layout\n"
1379 << to_utf8(tmplocal)
1380 << "\n\\end_forced_local_layout\n";
1383 // then the text parameters
1384 if (language != ignore_language)
1385 os << "\\language " << language->lang() << '\n';
1386 for (auto const & s : lang_options_babel_) {
1387 Language const * l = languages.getLanguage(s.first);
1388 if (l && l->babelOpts() != s.second)
1389 // babel options can be empty
1390 os << "\\language_options_babel " << s.first << " \"" << s.second << "\"\n";
1392 for (auto const & s : lang_options_polyglossia_) {
1393 Language const * l = languages.getLanguage(s.first);
1394 if (l && l->polyglossiaOpts() != s.second)
1395 // polyglossia options can be empty
1396 os << "\\language_options_polyglossia " << s.first << " \"" << s.second << "\"\n";
1398 os << "\\language_package " << lang_package
1399 << "\n\\inputencoding " << inputenc
1400 << "\n\\fontencoding " << fontenc
1401 << "\n\\font_roman \"" << fonts_roman[0]
1402 << "\" \"" << fonts_roman[1] << '"'
1403 << "\n\\font_sans \"" << fonts_sans[0]
1404 << "\" \"" << fonts_sans[1] << '"'
1405 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1406 << "\" \"" << fonts_typewriter[1] << '"'
1407 << "\n\\font_math \"" << fonts_math[0]
1408 << "\" \"" << fonts_math[1] << '"'
1409 << "\n\\font_default_family " << fonts_default_family
1410 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1411 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1412 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1413 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1414 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1415 if (!font_roman_opts.empty())
1416 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1417 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1418 << ' ' << fonts_sans_scale[1];
1419 if (!font_sans_opts.empty())
1420 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1421 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1422 << ' ' << fonts_typewriter_scale[1];
1423 if (!font_typewriter_opts.empty())
1424 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1426 if (!fonts_cjk.empty())
1427 os << "\\font_cjk " << fonts_cjk << '\n';
1428 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1429 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1430 os << "\\graphics " << graphics_driver << '\n';
1431 os << "\\default_output_format " << default_output_format << '\n';
1432 os << "\\output_sync " << output_sync << '\n';
1433 if (!output_sync_macro.empty())
1434 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1435 os << "\\bibtex_command " << bibtex_command << '\n';
1436 os << "\\index_command " << index_command << '\n';
1438 if (!float_placement.empty())
1439 os << "\\float_placement " << float_placement << '\n';
1440 if (!float_alignment.empty())
1441 os << "\\float_alignment " << float_alignment << '\n';
1442 os << "\\paperfontsize " << fontsize << '\n';
1444 spacing().writeFile(os);
1445 pdfoptions().writeFile(os);
1447 os << "\\papersize " << string_papersize[papersize]
1448 << "\n\\use_geometry " << convert<string>(use_geometry);
1449 map<string, string> const & packages = auto_packages();
1450 for (auto const & pack : packages)
1451 os << "\n\\use_package " << pack.first << ' '
1452 << use_package(pack.first);
1454 os << "\n\\cite_engine ";
1456 if (!cite_engine_.empty())
1461 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1463 if (!biblio_style.empty())
1464 os << "\n\\biblio_style " << biblio_style;
1465 if (!biblio_opts.empty())
1466 os << "\n\\biblio_options " << biblio_opts;
1467 if (!biblatex_bibstyle.empty())
1468 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1469 if (!biblatex_citestyle.empty())
1470 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1471 if (!multibib.empty())
1472 os << "\n\\multibib " << multibib;
1474 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1475 << "\n\\use_indices " << convert<string>(use_indices)
1476 << "\n\\paperorientation " << string_orientation[orientation]
1477 << "\n\\suppress_date " << convert<string>(suppress_date)
1478 << "\n\\justification " << convert<string>(justification)
1479 << "\n\\use_refstyle " << use_refstyle
1480 << "\n\\use_formatted_ref " << use_formatted_ref
1481 << "\n\\use_minted " << use_minted
1482 << "\n\\use_lineno " << use_lineno
1485 if (!lineno_opts.empty())
1486 os << "\\lineno_options " << lineno_opts << '\n';
1488 if (!nomencl_opts.empty())
1489 os << "\\nomencl_options " << nomencl_opts << '\n';
1491 if (isbackgroundcolor)
1492 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1494 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1495 if (isnotefontcolor)
1496 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1498 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1500 for (auto const & br : branchlist()) {
1501 os << "\\branch " << to_utf8(br.branch())
1502 << "\n\\selected " << br.isSelected()
1503 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1504 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1509 for (auto const & id : indiceslist()) {
1510 os << "\\index " << to_utf8(id.index())
1511 << "\n\\shortcut " << to_utf8(id.shortcut())
1512 << "\n\\color " << lyx::X11hexname(id.color())
1517 for (auto const & si : spellignore()) {
1518 os << "\\spellchecker_ignore " << si.lang()->lang()
1519 << " " << to_utf8(si.word())
1523 if (!paperwidth.empty())
1524 os << "\\paperwidth "
1525 << VSpace(paperwidth).asLyXCommand() << '\n';
1526 if (!paperheight.empty())
1527 os << "\\paperheight "
1528 << VSpace(paperheight).asLyXCommand() << '\n';
1529 if (!leftmargin.empty())
1530 os << "\\leftmargin "
1531 << VSpace(leftmargin).asLyXCommand() << '\n';
1532 if (!topmargin.empty())
1533 os << "\\topmargin "
1534 << VSpace(topmargin).asLyXCommand() << '\n';
1535 if (!rightmargin.empty())
1536 os << "\\rightmargin "
1537 << VSpace(rightmargin).asLyXCommand() << '\n';
1538 if (!bottommargin.empty())
1539 os << "\\bottommargin "
1540 << VSpace(bottommargin).asLyXCommand() << '\n';
1541 if (!headheight.empty())
1542 os << "\\headheight "
1543 << VSpace(headheight).asLyXCommand() << '\n';
1544 if (!headsep.empty())
1546 << VSpace(headsep).asLyXCommand() << '\n';
1547 if (!footskip.empty())
1549 << VSpace(footskip).asLyXCommand() << '\n';
1550 if (!columnsep.empty())
1551 os << "\\columnsep "
1552 << VSpace(columnsep).asLyXCommand() << '\n';
1553 os << "\\secnumdepth " << secnumdepth
1554 << "\n\\tocdepth " << tocdepth
1555 << "\n\\paragraph_separation "
1556 << string_paragraph_separation[paragraph_separation];
1557 if (!paragraph_separation)
1558 os << "\n\\paragraph_indentation "
1559 << (getParIndent().empty() ? "default" : getParIndent().asString());
1561 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1562 os << "\n\\is_math_indent " << is_math_indent;
1564 os << "\n\\math_indentation "
1565 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1566 os << "\n\\math_numbering_side ";
1567 switch(math_numbering_side) {
1577 os << "\n\\quotes_style "
1578 << string_quotes_style[static_cast<int>(quotes_style)]
1579 << "\n\\dynamic_quotes " << dynamic_quotes
1580 << "\n\\papercolumns " << columns
1581 << "\n\\papersides " << sides
1582 << "\n\\paperpagestyle " << pagestyle
1583 << "\n\\tablestyle " << tablestyle << '\n';
1584 if (!listings_params.empty())
1585 os << "\\listings_params \"" <<
1586 InsetListingsParams(listings_params).encodedString() << "\"\n";
1587 for (int i = 0; i < 4; ++i) {
1588 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1589 if (user_defined_bullet(i).getFont() != -1) {
1590 os << "\\bullet " << i << " "
1591 << user_defined_bullet(i).getFont() << " "
1592 << user_defined_bullet(i).getCharacter() << " "
1593 << user_defined_bullet(i).getSize() << "\n";
1597 os << "\\bulletLaTeX " << i << " \""
1598 << lyx::to_ascii(user_defined_bullet(i).getText())
1604 os << "\\tracking_changes "
1605 << (save_transient_properties ? convert<string>(track_changes) : "false")
1608 os << "\\output_changes "
1609 << (save_transient_properties ? convert<string>(output_changes) : "false")
1612 os << "\\change_bars "
1613 << (save_transient_properties ? convert<string>(change_bars) : "false")
1616 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1618 os << "\\html_math_output " << html_math_output << '\n'
1619 << "\\html_css_as_file " << html_css_as_file << '\n'
1620 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1622 os << "\\docbook_table_output " << docbook_table_output << '\n';
1623 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1625 if (html_math_img_scale != 1.0)
1626 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1627 if (!html_latex_start.empty())
1628 os << "\\html_latex_start " << html_latex_start << '\n';
1629 if (!html_latex_end.empty())
1630 os << "\\html_latex_end " << html_latex_end << '\n';
1632 os << pimpl_->authorlist;
1636 void BufferParams::validate(LaTeXFeatures & features) const
1638 features.require(documentClass().required());
1640 if (columns > 1 && language->rightToLeft()
1641 && !features.runparams().isFullUnicode()
1642 && language->babel() != "hebrew")
1643 features.require("rtloutputdblcol");
1645 if (output_changes) {
1646 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1647 LaTeXFeatures::isAvailable("xcolor");
1649 switch (features.runparams().flavor) {
1651 case Flavor::DviLuaTeX:
1653 features.require("ct-xcolor-ulem");
1654 features.require("ulem");
1655 features.require("xcolor");
1657 features.require("ct-none");
1660 case Flavor::LuaTeX:
1661 case Flavor::PdfLaTeX:
1664 features.require("ct-xcolor-ulem");
1665 features.require("ulem");
1666 features.require("xcolor");
1667 // improves color handling in PDF output
1669 features.require("ct-none");
1676 features.require("changebar");
1679 // Floats with 'Here definitely' as default setting.
1680 if (float_placement.find('H') != string::npos)
1681 features.require("float");
1683 for (auto const & pm : use_packages) {
1684 if (pm.first == "amsmath") {
1685 // AMS Style is at document level
1686 if (pm.second == package_on ||
1687 features.isProvided("amsmath"))
1688 features.require(pm.first);
1689 } else if (pm.second == package_on)
1690 features.require(pm.first);
1693 // Document-level line spacing
1694 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1695 features.require("setspace");
1697 // the bullet shapes are buffer level not paragraph level
1698 // so they are tested here
1699 for (int i = 0; i < 4; ++i) {
1700 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1702 int const font = user_defined_bullet(i).getFont();
1704 int const c = user_defined_bullet(i).getCharacter();
1710 features.require("latexsym");
1712 } else if (font == 1) {
1713 features.require("amssymb");
1714 } else if (font >= 2 && font <= 5) {
1715 features.require("pifont");
1719 if (pdfoptions().use_hyperref) {
1720 features.require("hyperref");
1721 // due to interferences with babel and hyperref, the color package has to
1722 // be loaded after hyperref when hyperref is used with the colorlinks
1723 // option, see http://www.lyx.org/trac/ticket/5291
1724 if (pdfoptions().colorlinks)
1725 features.require("color");
1727 if (!listings_params.empty()) {
1728 // do not test validity because listings_params is
1729 // supposed to be valid
1731 InsetListingsParams(listings_params).separatedParams(true);
1732 // we can't support all packages, but we should load the color package
1733 if (par.find("\\color", 0) != string::npos)
1734 features.require("color");
1737 // some languages are only available via polyglossia
1738 if (features.hasPolyglossiaExclusiveLanguages())
1739 features.require("polyglossia");
1741 if (useNonTeXFonts && fontsMath() != "auto")
1742 features.require("unicode-math");
1745 features.require("microtype");
1747 if (!language->required().empty())
1748 features.require(language->required());
1752 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1753 FileName const & filepath) const
1755 // DocumentMetadata must come before anything else
1756 if (features.isAvailableAtLeastFrom("LaTeX", 2022, 6)
1757 && !containsOnly(document_metadata, " \n\t")) {
1758 // Check if the user preamble contains uncodable glyphs
1759 odocstringstream doc_metadata;
1760 docstring uncodable_glyphs;
1761 Encoding const * const enc = features.runparams().encoding;
1763 for (char_type c : document_metadata) {
1764 if (!enc->encodable(c)) {
1765 docstring const glyph(1, c);
1766 LYXERR0("Uncodable character '"
1768 << "' in document metadata!");
1769 uncodable_glyphs += glyph;
1770 if (features.runparams().dryrun) {
1771 doc_metadata << "<" << _("LyX Warning: ")
1772 << _("uncodable character") << " '";
1773 doc_metadata.put(c);
1774 doc_metadata << "'>";
1777 doc_metadata.put(c);
1780 doc_metadata << document_metadata;
1782 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1783 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1784 frontend::Alert::warning(
1785 _("Uncodable character in document metadata"),
1787 _("The metadata of your document contains glyphs "
1788 "that are unknown in the current document encoding "
1789 "(namely %1$s).\nThese glyphs are omitted "
1790 " from the output, which may result in "
1791 "incomplete output."
1792 "\n\nPlease select an appropriate "
1793 "document encoding\n"
1794 "(such as utf8) or change the "
1795 "metadata accordingly."),
1798 if (!doc_metadata.str().empty()) {
1799 os << "\\DocumentMetadata{\n"
1800 << doc_metadata.str()
1805 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1806 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1807 // \RequirePackage to do so, rather than the normal \usepackage
1808 // Do not try to load any other package before the document class, unless you
1809 // have a thorough understanding of the LATEX internals and know exactly what you
1811 if (features.mustProvide("fix-cm"))
1812 os << "\\RequirePackage{fix-cm}\n";
1813 // Likewise for fixltx2e. If other packages conflict with this policy,
1814 // treat it as a package bug (and report it!)
1815 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1816 if (features.mustProvide("fixltx2e"))
1817 os << "\\RequirePackage{fixltx2e}\n";
1819 os << "\\documentclass";
1821 DocumentClass const & tclass = documentClass();
1823 ostringstream clsoptions; // the document class options.
1825 if (tokenPos(tclass.opt_fontsize(),
1826 '|', fontsize) >= 0) {
1827 // only write if existing in list (and not default)
1828 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1831 // paper sizes not supported by the class itself need the
1833 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1834 bool class_supported_papersize = papersize == PAPER_DEFAULT
1835 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1837 if ((!use_geometry || features.isProvided("geometry-light"))
1838 && class_supported_papersize && papersize != PAPER_DEFAULT)
1839 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1842 if (sides != tclass.sides()) {
1845 clsoptions << "oneside,";
1848 clsoptions << "twoside,";
1854 if (columns != tclass.columns()) {
1856 clsoptions << "twocolumn,";
1858 clsoptions << "onecolumn,";
1862 && orientation == ORIENTATION_LANDSCAPE)
1863 clsoptions << "landscape,";
1866 clsoptions << "fleqn,";
1868 switch(math_numbering_side) {
1870 clsoptions << "leqno,";
1873 clsoptions << "reqno,";
1874 features.require("amsmath");
1880 if (paragraph_separation) {
1881 if (!tclass.halfparskip().empty() && getDefSkip().kind() == VSpace::HALFLINE)
1882 clsoptions << tclass.halfparskip() << ",";
1883 if (!tclass.fullparskip().empty() && getDefSkip().kind() == VSpace::FULLLINE)
1884 clsoptions << tclass.fullparskip() << ",";
1887 // language should be a parameter to \documentclass
1888 if (language->babel() == "hebrew"
1889 && default_language->babel() != "hebrew")
1890 // This seems necessary
1891 features.useLanguage(default_language);
1893 ostringstream language_options;
1894 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1895 bool const use_polyglossia = features.usePolyglossia();
1896 bool const global = lyxrc.language_global_options;
1897 if (features.useBabel() || (use_polyglossia && global)) {
1898 language_options << features.getBabelLanguages();
1899 if (!language->babel().empty()) {
1900 if (!language_options.str().empty())
1901 language_options << ',';
1902 language_options << language->babel();
1904 if (global && !language_options.str().empty())
1905 clsoptions << language_options.str() << ',';
1908 // the predefined options from the layout
1909 if (use_default_options && !tclass.options().empty())
1910 clsoptions << tclass.options() << ',';
1912 // the user-defined options
1913 if (!options.empty()) {
1914 clsoptions << options << ',';
1917 docstring const strOptions = from_utf8(clsoptions.str());
1918 if (!strOptions.empty()) {
1919 // Check if class options contain uncodable glyphs
1920 docstring uncodable_glyphs;
1921 docstring options_encodable;
1922 Encoding const * const enc = features.runparams().encoding;
1924 for (char_type c : strOptions) {
1925 if (!enc->encodable(c)) {
1926 docstring const glyph(1, c);
1927 LYXERR0("Uncodable character '"
1929 << "' in class options!");
1930 uncodable_glyphs += glyph;
1931 if (features.runparams().dryrun) {
1932 options_encodable += "<" + _("LyX Warning: ")
1933 + _("uncodable character") + " '";
1934 options_encodable += c;
1935 options_encodable += "'>";
1938 options_encodable += c;
1941 options_encodable = strOptions;
1943 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1944 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1945 frontend::Alert::warning(
1946 _("Uncodable character in class options"),
1948 _("The class options of your document contain glyphs "
1949 "that are unknown in the current document encoding "
1950 "(namely %1$s).\nThese glyphs are omitted "
1951 " from the output, which may result in "
1952 "incomplete output."
1953 "\n\nPlease select an appropriate "
1954 "document encoding\n"
1955 "(such as utf8) or change the "
1956 "class options accordingly."),
1959 options_encodable = rtrim(options_encodable, ",");
1960 os << '[' << options_encodable << ']';
1963 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1964 // end of \documentclass defs
1966 // The package options (via \PassOptionsToPackage)
1967 os << from_ascii(features.getPackageOptions());
1969 // if we use fontspec or newtxmath, we have to load the AMS packages here
1970 string const ams = features.loadAMSPackages();
1971 string const main_font_enc = features.runparams().main_fontenc;
1972 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1973 bool const use_newtxmath =
1974 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1975 ot1, false, false) == "newtxmath";
1976 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1977 os << from_ascii(ams);
1979 if (useNonTeXFonts) {
1980 // Babel (as of 2017/11/03) loads fontspec itself
1981 // However, it does so only if a non-default font is requested via \babelfont
1982 // Thus load fontspec if this is not the case and we need fontspec features
1983 bool const babel_needfontspec =
1984 !features.isAvailableAtLeastFrom("babel", 2017, 11, 3)
1985 || (fontsRoman() == "default"
1986 && fontsSans() == "default"
1987 && fontsTypewriter() == "default"
1988 // these need fontspec features
1989 && (features.isRequired("textquotesinglep")
1990 || features.isRequired("textquotedblp")));
1991 if (!features.isProvided("fontspec")
1992 && (!features.useBabel() || babel_needfontspec))
1993 os << "\\usepackage{fontspec}\n";
1994 if (features.mustProvide("unicode-math")
1995 && features.isAvailable("unicode-math"))
1996 os << "\\usepackage{unicode-math}\n";
1999 // load CJK support package before font selection
2000 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
2001 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
2002 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
2003 if (inputenc == "utf8-cjk" || inputenc == "utf8")
2004 os << "\\usepackage{CJKutf8}\n";
2006 os << "\\usepackage[encapsulated]{CJK}\n";
2009 // font selection must be done before loading fontenc.sty
2010 // but after babel with non-TeX fonts
2011 string const fonts = loadFonts(features);
2012 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
2013 os << from_utf8(fonts);
2015 if (fonts_default_family != "default")
2016 os << "\\renewcommand{\\familydefault}{\\"
2017 << from_ascii(fonts_default_family) << "}\n";
2019 // set font encoding
2020 // non-TeX fonts use font encoding TU (set by fontspec)
2021 if (!useNonTeXFonts && !features.isProvided("fontenc")
2022 && main_font_enc != "default") {
2023 // get main font encodings
2024 vector<string> fontencs = font_encodings();
2025 // get font encodings of secondary languages
2026 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
2027 // option (for text in other languages).
2028 features.getFontEncodings(fontencs);
2029 if (!fontencs.empty()) {
2030 os << "\\usepackage["
2031 << from_ascii(getStringFromVector(fontencs))
2036 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
2037 if (features.mustProvide("textcomp"))
2038 os << "\\usepackage{textcomp}\n";
2039 if (features.mustProvide("pmboxdraw"))
2040 os << "\\usepackage{pmboxdraw}\n";
2042 // handle inputenc etc.
2043 // (In documents containing text in Thai language,
2044 // we must load inputenc after babel, see lib/languages).
2045 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2046 writeEncodingPreamble(os, features);
2049 if (!features.runparams().includeall && !included_children_.empty()) {
2050 os << "\\includeonly{";
2052 // we do not use "auto const &" here, because incfile is modified later
2053 // coverity[auto_causes_copy]
2054 for (auto incfile : included_children_) {
2055 FileName inc = makeAbsPath(incfile, filepath.absFileName());
2056 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
2058 if (!features.runparams().nice)
2060 // \includeonly doesn't want an extension
2061 incfile = changeExtension(incfile, string());
2062 incfile = support::latex_path(incfile);
2063 if (!incfile.empty()) {
2066 os << from_utf8(incfile);
2073 if (!features.isProvided("geometry")
2074 && (use_geometry || !class_supported_papersize)) {
2075 odocstringstream ods;
2076 if (!getGraphicsDriver("geometry").empty())
2077 ods << getGraphicsDriver("geometry");
2078 if (orientation == ORIENTATION_LANDSCAPE)
2079 ods << ",landscape";
2080 switch (papersize) {
2082 if (!paperwidth.empty())
2083 ods << ",paperwidth="
2084 << from_ascii(paperwidth);
2085 if (!paperheight.empty())
2086 ods << ",paperheight="
2087 << from_ascii(paperheight);
2089 case PAPER_USLETTER:
2091 case PAPER_USEXECUTIVE:
2120 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2125 string g_options = to_ascii(trim(ods.str(), ","));
2126 // geometry must be loaded after graphics nowadays, since
2127 // graphic drivers might overwrite some settings
2128 // see https://tex.stackexchange.com/a/384952/19291
2129 // Hence we store this and output it later
2131 gs << "\\usepackage";
2132 // geometry-light means that the class works with geometry, but overwrites
2133 // the package options and paper sizes (memoir does this).
2134 // In this case, all options need to go to \geometry
2135 // and the standard paper sizes need to go to the class options.
2136 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2137 gs << '[' << g_options << ']';
2140 gs << "{geometry}\n";
2141 if (use_geometry || features.isProvided("geometry-light")) {
2142 gs << "\\geometry{verbose";
2143 if (!g_options.empty())
2144 // Output general options here with "geometry light".
2145 gs << "," << g_options;
2146 // output this only if use_geometry is true
2148 if (!topmargin.empty())
2149 gs << ",tmargin=" << Length(topmargin).asLatexString();
2150 if (!bottommargin.empty())
2151 gs << ",bmargin=" << Length(bottommargin).asLatexString();
2152 if (!leftmargin.empty())
2153 gs << ",lmargin=" << Length(leftmargin).asLatexString();
2154 if (!rightmargin.empty())
2155 gs << ",rmargin=" << Length(rightmargin).asLatexString();
2156 if (!headheight.empty())
2157 gs << ",headheight=" << Length(headheight).asLatexString();
2158 if (!headsep.empty())
2159 gs << ",headsep=" << Length(headsep).asLatexString();
2160 if (!footskip.empty())
2161 gs << ",footskip=" << Length(footskip).asLatexString();
2162 if (!columnsep.empty())
2163 gs << ",columnsep=" << Length(columnsep).asLatexString();
2167 set_geometry = gs.str();
2168 } else if (orientation == ORIENTATION_LANDSCAPE
2169 || papersize != PAPER_DEFAULT) {
2170 features.require("papersize");
2173 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2174 if (pagestyle == "fancy")
2175 os << "\\usepackage{fancyhdr}\n";
2176 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2179 // only output when the background color is not default
2180 if (isbackgroundcolor) {
2181 // only require color here, the background color will be defined
2182 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2184 features.require("color");
2185 features.require("pagecolor");
2188 // only output when the font color is not default
2190 // only require color here, the font color will be defined
2191 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2193 features.require("color");
2194 features.require("fontcolor");
2197 // Only if class has a ToC hierarchy
2198 if (tclass.hasTocLevels()) {
2199 if (secnumdepth != tclass.secnumdepth()) {
2200 os << "\\setcounter{secnumdepth}{"
2204 if (tocdepth != tclass.tocdepth()) {
2205 os << "\\setcounter{tocdepth}{"
2211 if (paragraph_separation) {
2212 // when skip separation
2214 bool default_skip = false;
2215 bool by_class_option = false;
2216 switch (getDefSkip().kind()) {
2217 case VSpace::SMALLSKIP:
2218 psopt = "\\smallskipamount";
2220 case VSpace::MEDSKIP:
2221 psopt = "\\medskipamount";
2223 case VSpace::BIGSKIP:
2224 psopt = "\\bigskipamount";
2226 case VSpace::HALFLINE:
2227 // default (no option)
2228 default_skip = true;
2229 by_class_option = !tclass.halfparskip().empty();
2231 case VSpace::FULLLINE:
2232 psopt = "\\baselineskip";
2233 by_class_option = !tclass.fullparskip().empty();
2235 case VSpace::LENGTH:
2236 psopt = getDefSkip().length().asLatexString();
2241 if (features.isProvided("parskip")) {
2242 // package already loaded (with arbitrary options)
2243 // change parskip value only
2245 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2246 else if (default_skip)
2247 // explicitly reset default (might have been changed
2248 // in a class or package)
2249 os << "\\parskip=.5\\baselineskip plus 2pt\\relax\n";
2250 } else if (!by_class_option) {
2251 // load parskip package with required options
2253 if (!psopt.empty()) {
2254 if (contains(psopt, ' '))
2255 // glue length has spaces: embrace
2256 psopts = "skip={" + psopt + "}";
2258 psopts = "skip=" + psopt;
2260 string const xpsopts = getPackageOptions("parskip");
2261 if (!xpsopts.empty()) {
2262 if (!psopts.empty())
2266 os << "\\usepackage";
2267 if (!psopts.empty())
2268 os << "[" << psopts << "]";
2269 os << "{parskip}\n";
2272 // when separation by indentation
2273 // only output something when a width is given
2274 if (!getParIndent().empty()) {
2275 os << "\\setlength{\\parindent}{"
2276 << from_utf8(getParIndent().asLatexString())
2281 if (is_math_indent) {
2282 // when formula indentation
2283 // only output something when it is not the default
2284 if (!getMathIndent().empty()) {
2285 os << "\\setlength{\\mathindent}{"
2286 << from_utf8(getMathIndent().asString())
2291 // Now insert the LyX specific LaTeX commands...
2292 features.resolveAlternatives();
2293 features.expandMultiples();
2296 if (!output_sync_macro.empty())
2297 os << from_utf8(output_sync_macro) +"\n";
2298 else if (features.runparams().flavor == Flavor::LaTeX)
2299 os << "\\usepackage[active]{srcltx}\n";
2301 os << "\\synctex=-1\n";
2304 // due to interferences with babel and hyperref, the color package has to
2305 // be loaded (when it is not already loaded) before babel when hyperref
2306 // is used with the colorlinks option, see
2307 // http://www.lyx.org/trac/ticket/5291
2308 // we decided therefore to load color always before babel, see
2309 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2310 os << from_ascii(features.getColorOptions());
2312 // If we use hyperref, jurabib, japanese or varioref,
2313 // we have to call babel before
2315 && (features.isRequired("jurabib")
2316 || features.isRequired("hyperref")
2317 || features.isRequired("varioref")
2318 || features.isRequired("japanese"))) {
2319 os << features.getBabelPresettings();
2321 os << from_utf8(babelCall(features, language_options.str(),
2322 !lyxrc.language_global_options)) + '\n';
2323 os << features.getBabelPostsettings();
2326 // The optional packages;
2327 os << from_ascii(features.getPackages());
2329 // Additional Indices
2330 if (features.isRequired("splitidx")) {
2331 for (auto const & idx : indiceslist()) {
2332 if (features.isProvided("memoir-idx")) {
2333 if (idx.shortcut() == "idx")
2335 os << "\\makeindex[";
2337 os << "\\newindex{";
2338 os << escape(idx.shortcut());
2339 if (features.isProvided("memoir-idx"))
2347 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2350 // * Hyperref manual: "Make sure it comes last of your loaded
2351 // packages, to give it a fighting chance of not being over-written,
2352 // since its job is to redefine many LaTeX commands."
2353 // * Email from Heiko Oberdiek: "It is usually better to load babel
2354 // before hyperref. Then hyperref has a chance to detect babel.
2355 // * Has to be loaded before the "LyX specific LaTeX commands" to
2356 // avoid errors with algorithm floats.
2357 // use hyperref explicitly if it is required
2358 if (features.isRequired("hyperref")) {
2359 OutputParams tmp_params = features.runparams();
2360 pdfoptions().writeLaTeX(tmp_params, os,
2361 features.isProvided("hyperref"));
2362 // correctly break URLs with hyperref and dvi/ps output
2363 if (features.runparams().hyperref_driver == "dvips"
2364 && features.isAvailable("breakurl"))
2365 os << "\\usepackage{breakurl}\n";
2366 } else if (features.isRequired("nameref"))
2367 // hyperref loads this automatically
2368 os << "\\usepackage{nameref}\n";
2371 os << "\\usepackage";
2372 if (!lineno_opts.empty())
2373 os << "[" << lineno_opts << "]";
2375 os << "\\linenumbers\n";
2378 // bibtopic needs to be loaded after hyperref.
2379 // the dot provides the aux file naming which LyX can detect.
2380 if (features.mustProvide("bibtopic"))
2381 os << "\\usepackage[dot]{bibtopic}\n";
2383 // Will be surrounded by \makeatletter and \makeatother when not empty
2384 otexstringstream atlyxpreamble;
2386 // Some macros LyX will need
2388 TexString tmppreamble = features.getMacros();
2389 if (!tmppreamble.str.empty())
2390 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2391 "LyX specific LaTeX commands.\n"
2392 << std::move(tmppreamble)
2395 // the text class specific preamble
2397 docstring tmppreamble = features.getTClassPreamble();
2398 if (!tmppreamble.empty())
2399 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2400 "Textclass specific LaTeX commands.\n"
2404 // suppress date if selected
2405 // use \@ifundefined because we cannot be sure that every document class
2406 // has a \date command
2408 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2410 /* the user-defined preamble */
2411 if (!containsOnly(preamble, " \n\t")) {
2413 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2414 "User specified LaTeX commands.\n";
2416 // Check if the user preamble contains uncodable glyphs
2417 odocstringstream user_preamble;
2418 docstring uncodable_glyphs;
2419 Encoding const * const enc = features.runparams().encoding;
2421 for (char_type c : preamble) {
2422 if (!enc->encodable(c)) {
2423 docstring const glyph(1, c);
2424 LYXERR0("Uncodable character '"
2426 << "' in user preamble!");
2427 uncodable_glyphs += glyph;
2428 if (features.runparams().dryrun) {
2429 user_preamble << "<" << _("LyX Warning: ")
2430 << _("uncodable character") << " '";
2431 user_preamble.put(c);
2432 user_preamble << "'>";
2435 user_preamble.put(c);
2438 user_preamble << preamble;
2440 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2441 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2442 frontend::Alert::warning(
2443 _("Uncodable character in user preamble"),
2445 _("The user preamble of your document contains glyphs "
2446 "that are unknown in the current document encoding "
2447 "(namely %1$s).\nThese glyphs are omitted "
2448 " from the output, which may result in "
2449 "incomplete output."
2450 "\n\nPlease select an appropriate "
2451 "document encoding\n"
2452 "(such as utf8) or change the "
2453 "preamble code accordingly."),
2456 atlyxpreamble << user_preamble.str() << '\n';
2459 // footmisc must be loaded after setspace
2460 // Load it here to avoid clashes with footmisc loaded in the user
2461 // preamble. For that reason we also pass the options via
2462 // \PassOptionsToPackage in getPreamble() and not here.
2463 if (features.mustProvide("footmisc"))
2464 atlyxpreamble << "\\usepackage{footmisc}\n";
2466 // subfig loads internally the LaTeX package "caption". As
2467 // caption is a very popular package, users will load it in
2468 // the preamble. Therefore we must load subfig behind the
2469 // user-defined preamble and check if the caption package was
2470 // loaded or not. For the case that caption is loaded before
2471 // subfig, there is the subfig option "caption=false". This
2472 // option also works when a koma-script class is used and
2473 // koma's own caption commands are used instead of caption. We
2474 // use \PassOptionsToPackage here because the user could have
2475 // already loaded subfig in the preamble.
2476 if (features.mustProvide("subfig"))
2477 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2478 " % Caption package is used. Advise subfig not to load it again.\n"
2479 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2481 "\\usepackage{subfig}\n";
2483 // Itemize bullet settings need to be last in case the user
2484 // defines their own bullets that use a package included
2485 // in the user-defined preamble -- ARRae
2486 // Actually it has to be done much later than that
2487 // since some packages like frenchb make modifications
2488 // at \begin{document} time -- JMarc
2489 docstring bullets_def;
2490 for (int i = 0; i < 4; ++i) {
2491 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2492 if (bullets_def.empty())
2493 bullets_def += "\\AtBeginDocument{\n";
2494 bullets_def += " \\def\\labelitemi";
2496 // `i' is one less than the item to modify
2503 bullets_def += "ii";
2509 bullets_def += '{' +
2510 user_defined_bullet(i).getText()
2515 if (!bullets_def.empty())
2516 atlyxpreamble << bullets_def << "}\n\n";
2518 if (!atlyxpreamble.empty())
2519 os << "\n\\makeatletter\n"
2520 << atlyxpreamble.release()
2521 << "\\makeatother\n\n";
2523 // We try to load babel late, in case it interferes with other packages.
2524 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2525 // have to be called after babel, though.
2526 if (use_babel && !features.isRequired("jurabib")
2527 && !features.isRequired("hyperref")
2528 && !features.isRequired("varioref")
2529 && !features.isRequired("japanese")) {
2530 os << features.getBabelPresettings();
2532 os << from_utf8(babelCall(features, language_options.str(),
2533 !lyxrc.language_global_options)) + '\n';
2534 os << features.getBabelPostsettings();
2536 // In documents containing text in Thai language,
2537 // we must load inputenc after babel (see lib/languages).
2538 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2539 writeEncodingPreamble(os, features);
2541 // font selection must be done after babel with non-TeX fonts
2542 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2543 os << from_utf8(fonts);
2545 if (features.isRequired("bicaption"))
2546 os << "\\usepackage{bicaption}\n";
2547 if (!listings_params.empty()
2548 || features.mustProvide("listings")
2549 || features.mustProvide("minted")) {
2551 os << "\\usepackage{minted}\n";
2553 os << "\\usepackage{listings}\n";
2555 string lst_params = listings_params;
2556 // If minted, do not output the language option (bug 11203)
2557 if (use_minted && contains(lst_params, "language=")) {
2558 vector<string> opts =
2559 getVectorFromString(lst_params, ",", false);
2560 for (size_t i = 0; i < opts.size(); ++i) {
2561 if (prefixIs(opts[i], "language="))
2562 opts.erase(opts.begin() + i--);
2564 lst_params = getStringFromVector(opts, ",");
2566 if (!lst_params.empty()) {
2568 os << "\\setminted{";
2571 // do not test validity because listings_params is
2572 // supposed to be valid
2574 InsetListingsParams(lst_params).separatedParams(true);
2575 os << from_utf8(par);
2579 // xunicode only needs to be loaded if tipa is used
2580 // (the rest is obsoleted by the new TU encoding).
2581 // It needs to be loaded at least after amsmath, amssymb,
2582 // esint and the other packages that provide special glyphs
2583 if (features.mustProvide("tipa") && useNonTeXFonts
2584 && !features.isProvided("xunicode")) {
2585 // The `xunicode` package officially only supports XeTeX,
2586 // but also works with LuaTeX. We work around its XeTeX test.
2587 if (features.runparams().flavor != Flavor::XeTeX) {
2588 os << "% Pretend to xunicode that we are XeTeX\n"
2589 << "\\def\\XeTeXpicfile{}\n";
2591 os << "\\usepackage{xunicode}\n";
2594 // covington must be loaded after beamerarticle
2595 if (features.isRequired("covington"))
2596 os << "\\usepackage{covington}\n";
2598 // Polyglossia must be loaded last ...
2599 if (use_polyglossia) {
2601 os << "\\usepackage{polyglossia}\n";
2602 // set the main language
2603 os << "\\setdefaultlanguage";
2604 if (!polyglossiaLangOptions(language->lang()).empty())
2605 os << "[" << from_ascii(polyglossiaLangOptions(language->lang())) << "]";
2606 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2607 // now setup the other languages
2608 set<string> const polylangs =
2609 features.getPolyglossiaLanguages();
2610 for (auto const & pl : polylangs) {
2611 // We do not output the options here; they are output in
2612 // the language switch commands. This is safer if multiple
2613 // varieties are used.
2614 if (pl == language->polyglossia())
2616 os << "\\setotherlanguage";
2617 os << "{" << from_ascii(pl) << "}\n";
2621 // ... but before biblatex (see #7065)
2622 if ((features.mustProvide("biblatex")
2623 || features.isRequired("biblatex-chicago"))
2624 && !features.isProvided("biblatex-chicago")
2625 && !features.isProvided("biblatex-natbib")
2626 && !features.isProvided("natbib-internal")
2627 && !features.isProvided("natbib")
2628 && !features.isProvided("jurabib")) {
2629 // The biblatex-chicago package has a differing interface
2630 // it uses a wrapper package and loads styles via fixed options
2631 bool const chicago = features.isRequired("biblatex-chicago");
2634 os << "\\usepackage";
2635 if (!biblatex_bibstyle.empty()
2636 && (biblatex_bibstyle == biblatex_citestyle)
2638 opts = "style=" + biblatex_bibstyle;
2640 } else if (!chicago) {
2641 if (!biblatex_bibstyle.empty()) {
2642 opts = "bibstyle=" + biblatex_bibstyle;
2645 if (!biblatex_citestyle.empty()) {
2646 opts += delim + "citestyle=" + biblatex_citestyle;
2650 if (!multibib.empty() && multibib != "child") {
2651 opts += delim + "refsection=" + multibib;
2654 if (bibtexCommand() == "bibtex8"
2655 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2656 opts += delim + "backend=bibtex8";
2658 } else if (bibtexCommand() == "bibtex"
2659 || prefixIs(bibtexCommand(), "bibtex ")) {
2660 opts += delim + "backend=bibtex";
2663 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2664 opts += delim + "bibencoding="
2665 + encodings.fromLyXName(bib_encoding)->latexName();
2668 // biblatex-chicago offers the style options "authordate"
2669 // or "authordate-trad". We use "authordate" if none
2670 // is given via the options field.
2671 if (chicago && citeEngineType() == ENGINE_TYPE_AUTHORYEAR
2672 && !contains(biblio_opts, "authordate")) {
2673 opts += delim + "authordate";
2677 if (!biblio_opts.empty())
2678 opts += delim + biblio_opts;
2680 os << "[" << opts << "]";
2682 os << "{biblatex-chicago}\n";
2684 os << "{biblatex}\n";
2688 // Load custom language package here
2689 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2690 if (lang_package == "default")
2691 os << from_utf8(lyxrc.language_custom_package);
2693 os << from_utf8(lang_package);
2697 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2698 // it is recommended to load menukeys as the last package (even after hyperref)
2699 if (features.isRequired("menukeys"))
2700 os << "\\usepackage{menukeys}\n";
2702 docstring const i18npreamble =
2703 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2705 if (!i18npreamble.empty())
2706 os << i18npreamble + '\n';
2712 void BufferParams::useClassDefaults()
2714 DocumentClass const & tclass = documentClass();
2716 sides = tclass.sides();
2717 columns = tclass.columns();
2718 pagestyle = tclass.pagestyle();
2719 tablestyle = tclass.tablestyle();
2720 use_default_options = true;
2721 // Only if class has a ToC hierarchy
2722 if (tclass.hasTocLevels()) {
2723 secnumdepth = tclass.secnumdepth();
2724 tocdepth = tclass.tocdepth();
2729 bool BufferParams::hasClassDefaults() const
2731 DocumentClass const & tclass = documentClass();
2733 return sides == tclass.sides()
2734 && columns == tclass.columns()
2735 && pagestyle == tclass.pagestyle()
2736 && tablestyle == tclass.tablestyle()
2737 && use_default_options
2738 && secnumdepth == tclass.secnumdepth()
2739 && tocdepth == tclass.tocdepth();
2743 DocumentClass const & BufferParams::documentClass() const
2749 DocumentClassConstPtr BufferParams::documentClassPtr() const
2755 void BufferParams::setDocumentClass(DocumentClassConstPtr const & tc)
2757 // evil, but this function is evil
2758 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2759 invalidateConverterCache();
2763 bool BufferParams::setBaseClass(string const & classname, string const & path)
2765 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2766 LayoutFileList & bcl = LayoutFileList::get();
2767 if (!bcl.haveClass(classname)) {
2769 bformat(_("The layout file:\n"
2771 "could not be found. A default textclass with default\n"
2772 "layouts will be used. LyX will not be able to produce\n"
2774 from_utf8(classname));
2775 frontend::Alert::error(_("Document class not found"), s);
2776 bcl.addEmptyClass(classname);
2779 bool const success = bcl[classname].load(path);
2782 bformat(_("Due to some error in it, the layout file:\n"
2784 "could not be loaded. A default textclass with default\n"
2785 "layouts will be used. LyX will not be able to produce\n"
2787 from_utf8(classname));
2788 frontend::Alert::error(_("Could not load class"), s);
2789 bcl.addEmptyClass(classname);
2792 pimpl_->baseClass_ = classname;
2793 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2798 LayoutFile const * BufferParams::baseClass() const
2800 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2801 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2807 LayoutFileIndex const & BufferParams::baseClassID() const
2809 return pimpl_->baseClass_;
2813 void BufferParams::makeDocumentClass(bool clone, bool internal)
2818 invalidateConverterCache();
2819 LayoutModuleList mods;
2820 for (auto const & mod : layout_modules_)
2821 mods.push_back(mod);
2823 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2825 TextClass::ReturnValues success = TextClass::OK;
2826 if (!forced_local_layout_.empty())
2827 success = doc_class_->read(to_utf8(forced_local_layout_),
2829 if (!local_layout_.empty() &&
2830 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2831 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2832 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2833 docstring const msg = _("Error reading internal layout information");
2834 frontend::Alert::warning(_("Read Error"), msg);
2839 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2841 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2845 docstring BufferParams::getLocalLayout(bool forced) const
2848 return from_utf8(doc_class_->forcedLayouts());
2850 return local_layout_;
2854 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2857 forced_local_layout_ = layout;
2859 local_layout_ = layout;
2863 bool BufferParams::addLayoutModule(string const & modName)
2865 for (auto const & mod : layout_modules_)
2868 layout_modules_.push_back(modName);
2873 string BufferParams::bufferFormat() const
2875 return documentClass().outputFormat();
2879 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2881 FormatList const & formats = exportableFormats(need_viewable);
2882 for (auto const & fmt : formats) {
2883 if (fmt->name() == format)
2890 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2892 FormatList & cached = only_viewable ?
2893 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2894 bool & valid = only_viewable ?
2895 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2899 vector<string> const backs = backends();
2900 set<string> excludes;
2901 if (useNonTeXFonts) {
2902 excludes.insert("latex");
2903 excludes.insert("pdflatex");
2904 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2905 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2906 excludes.insert("xetex");
2910 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2911 vector<string>::const_iterator it = backs.begin() + 1;
2912 for (; it != backs.end(); ++it) {
2913 FormatList r = theConverters().getReachable(*it, only_viewable,
2915 result.insert(result.end(), r.begin(), r.end());
2917 sort(result.begin(), result.end(), Format::formatSorter);
2924 vector<string> BufferParams::backends() const
2927 string const buffmt = bufferFormat();
2929 // FIXME: Don't hardcode format names here, but use a flag
2930 if (buffmt == "latex") {
2931 if (encoding().package() == Encoding::japanese)
2932 v.push_back("platex");
2934 if (!useNonTeXFonts) {
2935 v.push_back("pdflatex");
2936 v.push_back("latex");
2939 || inputenc == "ascii" || inputenc == "utf8-plain")
2940 v.push_back("xetex");
2941 v.push_back("luatex");
2942 v.push_back("dviluatex");
2945 string rbuffmt = buffmt;
2946 // If we use an OutputFormat in Japanese docs,
2947 // we need special format in order to get the path
2948 // via pLaTeX (#8823)
2949 if (documentClass().hasOutputFormat()
2950 && encoding().package() == Encoding::japanese)
2952 v.push_back(rbuffmt);
2955 v.push_back("xhtml");
2956 v.push_back("docbook5");
2957 v.push_back("text");
2963 Flavor BufferParams::getOutputFlavor(string const & format) const
2965 string const dformat = (format.empty() || format == "default") ?
2966 getDefaultOutputFormat() : format;
2967 DefaultFlavorCache::const_iterator it =
2968 default_flavors_.find(dformat);
2970 if (it != default_flavors_.end())
2973 Flavor result = Flavor::LaTeX;
2975 // FIXME It'd be better not to hardcode this, but to do
2976 // something with formats.
2977 if (dformat == "xhtml")
2978 result = Flavor::Html;
2979 else if (dformat == "docbook5")
2980 result = Flavor::DocBook5;
2981 else if (dformat == "text")
2982 result = Flavor::Text;
2983 else if (dformat == "lyx")
2984 result = Flavor::LyX;
2985 else if (dformat == "pdflatex")
2986 result = Flavor::PdfLaTeX;
2987 else if (dformat == "xetex")
2988 result = Flavor::XeTeX;
2989 else if (dformat == "luatex")
2990 result = Flavor::LuaTeX;
2991 else if (dformat == "dviluatex")
2992 result = Flavor::DviLuaTeX;
2994 // Try to determine flavor of default output format
2995 vector<string> backs = backends();
2996 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2997 // Get shortest path to format
2998 Graph::EdgePath path;
2999 for (auto const & bvar : backs) {
3000 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
3001 if (!p.empty() && (path.empty() || p.size() < path.size())) {
3006 result = theConverters().getFlavor(path);
3009 // cache this flavor
3010 default_flavors_[dformat] = result;
3015 string BufferParams::getDefaultOutputFormat() const
3017 if (!default_output_format.empty()
3018 && default_output_format != "default")
3019 return default_output_format;
3020 if (encoding().package() == Encoding::japanese)
3021 return lyxrc.default_platex_view_format;
3023 return lyxrc.default_otf_view_format;
3024 return lyxrc.default_view_format;
3027 Font const BufferParams::getFont() const
3029 FontInfo f = documentClass().defaultfont();
3030 if (fonts_default_family == "rmdefault")
3031 f.setFamily(ROMAN_FAMILY);
3032 else if (fonts_default_family == "sfdefault")
3033 f.setFamily(SANS_FAMILY);
3034 else if (fonts_default_family == "ttdefault")
3035 f.setFamily(TYPEWRITER_FAMILY);
3036 return Font(f, language);
3040 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
3042 return quotesstyletranslator().find(qs);
3046 bool BufferParams::isLatex() const
3048 return documentClass().outputType() == LATEX;
3052 bool BufferParams::isLiterate() const
3054 return documentClass().outputType() == LITERATE;
3058 bool BufferParams::hasPackageOption(string const package, string const opt) const
3060 for (auto const & p : documentClass().packageOptions())
3061 if (package == p.first && opt == p.second)
3067 string BufferParams::getPackageOptions(string const package) const
3069 for (auto const & p : documentClass().packageOptions())
3070 if (package == p.first)
3076 bool BufferParams::useBidiPackage(OutputParams const & rp) const
3078 return (rp.use_polyglossia
3079 // as of babel 3.29, bidi=bidi-* is supported by babel
3080 // So we check whether we use a respective version and
3081 // whethert bidi-r or bidi-l have been requested either via class
3082 // or package options
3084 && LaTeXFeatures::isAvailableAtLeastFrom("babel", 2019, 4, 3)
3087 && rp.flavor == Flavor::XeTeX;
3091 void BufferParams::readPreamble(Lexer & lex)
3093 if (lex.getString() != "\\begin_preamble")
3094 lyxerr << "Error (BufferParams::readPreamble):"
3095 "consistency check failed." << endl;
3097 preamble = lex.getLongString(from_ascii("\\end_preamble"));
3101 void BufferParams::readDocumentMetadata(Lexer & lex)
3103 if (lex.getString() != "\\begin_metadata")
3104 lyxerr << "Error (BufferParams::readDocumentMetadata):"
3105 "consistency check failed." << endl;
3107 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
3111 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
3113 string const expected = forced ? "\\begin_forced_local_layout" :
3114 "\\begin_local_layout";
3115 if (lex.getString() != expected)
3116 lyxerr << "Error (BufferParams::readLocalLayout):"
3117 "consistency check failed." << endl;
3120 forced_local_layout_ =
3121 lex.getLongString(from_ascii("\\end_forced_local_layout"));
3123 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
3127 bool BufferParams::setLanguage(string const & lang)
3129 Language const *new_language = languages.getLanguage(lang);
3130 if (!new_language) {
3131 // Language lang was not found
3134 language = new_language;
3139 void BufferParams::readLanguage(Lexer & lex)
3141 if (!lex.next()) return;
3143 string const tmptok = lex.getString();
3145 // check if tmptok is part of tex_babel in tex-defs.h
3146 if (!setLanguage(tmptok)) {
3147 // Language tmptok was not found
3148 language = default_language;
3149 lyxerr << "Warning: Setting language `"
3150 << tmptok << "' to `" << language->lang()
3156 void BufferParams::readGraphicsDriver(Lexer & lex)
3161 string const tmptok = lex.getString();
3162 // check if tmptok is part of tex_graphics in tex_defs.h
3165 string const test = tex_graphics[n++];
3167 if (test == tmptok) {
3168 graphics_driver = tmptok;
3173 "Warning: graphics driver `$$Token' not recognized!\n"
3174 " Setting graphics driver to `default'.\n");
3175 graphics_driver = "default";
3182 void BufferParams::readBullets(Lexer & lex)
3187 int const index = lex.getInteger();
3189 int temp_int = lex.getInteger();
3190 user_defined_bullet(index).setFont(temp_int);
3191 temp_bullet(index).setFont(temp_int);
3193 user_defined_bullet(index).setCharacter(temp_int);
3194 temp_bullet(index).setCharacter(temp_int);
3196 user_defined_bullet(index).setSize(temp_int);
3197 temp_bullet(index).setSize(temp_int);
3201 void BufferParams::readBulletsLaTeX(Lexer & lex)
3203 // The bullet class should be able to read this.
3206 int const index = lex.getInteger();
3208 docstring const temp_str = lex.getDocString();
3210 user_defined_bullet(index).setText(temp_str);
3211 temp_bullet(index).setText(temp_str);
3215 void BufferParams::readModules(Lexer & lex)
3217 if (!lex.eatLine()) {
3218 lyxerr << "Error (BufferParams::readModules):"
3219 "Unexpected end of input." << endl;
3223 string mod = lex.getString();
3224 if (mod == "\\end_modules")
3226 addLayoutModule(mod);
3232 void BufferParams::readRemovedModules(Lexer & lex)
3234 if (!lex.eatLine()) {
3235 lyxerr << "Error (BufferParams::readRemovedModules):"
3236 "Unexpected end of input." << endl;
3240 string mod = lex.getString();
3241 if (mod == "\\end_removed_modules")
3243 removed_modules_.push_back(mod);
3246 // now we want to remove any removed modules that were previously
3247 // added. normally, that will be because default modules were added in
3248 // setBaseClass(), which gets called when \textclass is read at the
3249 // start of the read.
3250 for (auto const & rm : removed_modules_) {
3251 LayoutModuleList::iterator const mit = layout_modules_.begin();
3252 LayoutModuleList::iterator const men = layout_modules_.end();
3253 LayoutModuleList::iterator found = find(mit, men, rm);
3256 layout_modules_.erase(found);
3261 void BufferParams::readIncludeonly(Lexer & lex)
3263 if (!lex.eatLine()) {
3264 lyxerr << "Error (BufferParams::readIncludeonly):"
3265 "Unexpected end of input." << endl;
3269 string child = lex.getString();
3270 if (child == "\\end_includeonly")
3272 included_children_.push_back(child);
3278 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3280 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3283 if (documentClass().pagesize() == "default")
3284 // could be anything, so don't guess
3286 return paperSizeName(purpose, documentClass().pagesize());
3287 case PAPER_CUSTOM: {
3288 if (purpose == XDVI && !paperwidth.empty() &&
3289 !paperheight.empty()) {
3290 // heightxwidth<unit>
3291 string first = paperwidth;
3292 string second = paperheight;
3293 if (orientation == ORIENTATION_LANDSCAPE)
3296 return first.erase(first.length() - 2)
3302 // dvips and dvipdfm do not know this
3303 if (purpose == DVIPS || purpose == DVIPDFM)
3307 if (purpose == DVIPS || purpose == DVIPDFM)
3311 if (purpose == DVIPS || purpose == DVIPDFM)
3321 if (purpose == DVIPS || purpose == DVIPDFM)
3325 if (purpose == DVIPS || purpose == DVIPDFM)
3329 if (purpose == DVIPS || purpose == DVIPDFM)
3333 if (purpose == DVIPS || purpose == DVIPDFM)
3337 if (purpose == DVIPS || purpose == DVIPDFM)
3341 // dvipdfm does not know this
3342 if (purpose == DVIPDFM)
3346 if (purpose == DVIPDFM)
3350 if (purpose == DVIPS || purpose == DVIPDFM)
3354 if (purpose == DVIPS || purpose == DVIPDFM)
3358 if (purpose == DVIPS || purpose == DVIPDFM)
3362 if (purpose == DVIPS || purpose == DVIPDFM)
3366 if (purpose == DVIPS || purpose == DVIPDFM)
3370 if (purpose == DVIPS || purpose == DVIPDFM)
3374 if (purpose == DVIPS || purpose == DVIPDFM)
3378 if (purpose == DVIPS || purpose == DVIPDFM)
3382 if (purpose == DVIPS || purpose == DVIPDFM)
3386 if (purpose == DVIPS || purpose == DVIPDFM)
3390 if (purpose == DVIPS || purpose == DVIPDFM)
3394 if (purpose == DVIPS || purpose == DVIPDFM)
3398 if (purpose == DVIPS || purpose == DVIPDFM)
3402 if (purpose == DVIPS || purpose == DVIPDFM)
3406 if (purpose == DVIPS || purpose == DVIPDFM)
3409 case PAPER_USEXECUTIVE:
3410 // dvipdfm does not know this
3411 if (purpose == DVIPDFM)
3416 case PAPER_USLETTER:
3418 if (purpose == XDVI)
3425 string const BufferParams::dvips_options() const
3429 // If the class loads the geometry package, we do not know which
3430 // paper size is used, since we do not set it (bug 7013).
3431 // Therefore we must not specify any argument here.
3432 // dvips gets the correct paper size via DVI specials in this case
3433 // (if the class uses the geometry package correctly).
3434 if (documentClass().provides("geometry"))
3438 && papersize == PAPER_CUSTOM
3439 && !lyxrc.print_paper_dimension_flag.empty()
3440 && !paperwidth.empty()
3441 && !paperheight.empty()) {
3442 // using a custom papersize
3443 result = lyxrc.print_paper_dimension_flag;
3444 result += ' ' + paperwidth;
3445 result += ',' + paperheight;
3447 string const paper_option = paperSizeName(DVIPS);
3448 if (!paper_option.empty() && (paper_option != "letter" ||
3449 orientation != ORIENTATION_LANDSCAPE)) {
3450 // dvips won't accept -t letter -t landscape.
3451 // In all other cases, include the paper size
3453 result = lyxrc.print_paper_flag;
3454 result += ' ' + paper_option;
3457 if (orientation == ORIENTATION_LANDSCAPE &&
3458 papersize != PAPER_CUSTOM)
3459 result += ' ' + lyxrc.print_landscape_flag;
3464 string const BufferParams::main_font_encoding() const
3466 vector<string> const fencs = font_encodings();
3467 if (fencs.empty()) {
3468 if (ascii_lowercase(language->fontenc(*this)) == "none")
3472 return fencs.back();
3476 vector<string> const BufferParams::font_encodings() const
3478 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3480 vector<string> fontencs;
3482 // "default" means "no explicit font encoding"
3483 if (doc_fontenc != "default") {
3484 if (!doc_fontenc.empty())
3485 // If we have a custom setting, we use only that!
3486 return getVectorFromString(doc_fontenc);
3487 string const lfe = language->fontenc(*this);
3489 && ascii_lowercase(language->fontenc(*this)) != "none") {
3490 vector<string> fencs = getVectorFromString(lfe);
3491 for (auto & fe : fencs) {
3492 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3493 fontencs.push_back(fe);
3502 string BufferParams::babelCall(LaTeXFeatures const & features, string lang_opts,
3503 bool const langoptions) const
3505 // suppress the babel call if there is no BabelName defined
3506 // for the document language in the lib/languages file and if no
3507 // other languages are used (lang_opts is then empty)
3508 if (lang_opts.empty())
3510 // get language options with modifiers
3511 bool have_mods = false;
3512 vector<string> blangs;
3513 std::set<Language const *> langs = features.getLanguages();
3514 // add main language
3515 langs.insert(language);
3517 string force_provide;
3518 bool have_main_forceprovide = false;
3519 bool have_other_forceprovide = useNonTeXFonts
3520 ? languages.haveOtherForceProvide()
3522 for (auto const & l : langs) {
3523 string blang = l->babel();
3524 bool use_opt = langoptions;
3527 int const bp = l->useBabelProvide();
3528 // pass option as modifier if apt
3529 if (bp != 2 && !have_other_forceprovide && l->babelOptFormat() == "modifier") {
3530 vector<string> opts = getVectorFromString(babelLangOptions(l->lang()));
3531 bool have_one = false;
3532 for (string const & s : opts) {
3534 if (langoptions || have_one)
3537 blang = "modifiers." + blang + "=" + s;
3543 // language that always requires \babelprovide
3544 if (bp == 1 && !have_other_forceprovide) {
3545 os << "\n\\babelprovide[import";
3548 if (!babelLangOptions(l->lang(), true).empty())
3549 os << ", " << babelLangOptions(l->lang());
3550 os << "]{" << blang << "}";
3553 // language that only requires \babelprovide with nonTeXFonts
3554 if (bp == 2 && useNonTeXFonts) {
3555 // here we need to tell babel to use the *.ini
3556 // even though an *.ldf exists.
3557 // This imports the *ini, so no "import" needed.
3558 if (l == language) {
3559 force_provide = force_provide.empty()
3562 have_main_forceprovide = true;
3564 force_provide = have_main_forceprovide
3569 if ((bp == 2 && useNonTeXFonts) || have_other_forceprovide) {
3570 // Options need to go to \babeprovide
3571 // but only those set in document settings
3572 if (!babelLangOptions(l->lang(), true).empty())
3573 os << "\n\\babelprovide["
3574 << babelLangOptions(l->lang())
3575 << "]{" << blang << "}";
3577 if (bp != 1 && use_opt)
3578 blangs.push_back(blang);
3581 lang_opts = getStringFromVector(blangs);
3582 if (!force_provide.empty()) {
3583 if (!lang_opts.empty())
3585 lang_opts += force_provide;
3588 if (useNonTeXFonts && features.hasRTLLanguage()) {
3589 if (!lang_opts.empty())
3591 if (features.runparams().flavor == Flavor::XeTeX) {
3592 // main language RTL?
3593 if (language->rightToLeft())
3594 lang_opts += "bidi=bidi-r";
3596 lang_opts += "bidi=bidi-l";
3598 lang_opts += "bidi=basic";
3600 // The prefs may require the languages to
3601 // be submitted to babel itself (not the class).
3602 if ((langoptions || have_mods) && !lang_opts.empty())
3603 return "\\usepackage[" + lang_opts + "]{babel}" + os.str();
3604 return "\\usepackage{babel}" + os.str();
3608 docstring BufferParams::getGraphicsDriver(string const & package) const
3612 if (package == "geometry") {
3613 if (graphics_driver == "dvips"
3614 || graphics_driver == "dvipdfm"
3615 || graphics_driver == "pdftex"
3616 || graphics_driver == "vtex")
3617 result = from_ascii(graphics_driver);
3618 else if (graphics_driver == "dvipdfmx")
3619 result = from_ascii("dvipdfm");
3626 void BufferParams::writeEncodingPreamble(otexstream & os,
3627 LaTeXFeatures & features) const
3629 // With no-TeX fonts we use utf8-plain without encoding package.
3633 string const doc_encoding = encoding().latexName();
3634 Encoding::Package const package = encoding().package();
3635 // (dvi)lualatex uses luainputenc rather than inputenc
3636 string const inputenc_package =
3637 (features.runparams().flavor == Flavor::LuaTeX
3638 || features.runparams().flavor == Flavor::DviLuaTeX)
3639 ? "luainputenc" : "inputenc";
3641 if (inputenc == "auto-legacy") {
3642 // The "japanese" babel language requires the pLaTeX engine
3643 // which conflicts with "inputenc".
3644 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3645 if (!features.isRequired("japanese")
3646 && !features.isProvided("inputenc")) {
3647 if (package == Encoding::inputenc) {
3648 // Main language requires (lua)inputenc
3649 os << "\\usepackage[" << doc_encoding << "]{"
3650 << inputenc_package << "}\n";
3652 // We might have an additional language that requires inputenc
3653 set<string> encoding_set = features.getEncodingSet(doc_encoding);
3654 bool inputenc = false;
3655 for (auto const & enc : encoding_set) {
3656 if (encodings.fromLaTeXName(enc)
3657 && encodings.fromLaTeXName(enc)->package() == Encoding::inputenc) {
3663 // load (lua)inputenc without options
3664 // (the encoding is loaded later)
3665 os << "\\usepackage{" << inputenc_package << "}\n";
3668 } else if (inputenc != "auto-legacy-plain") {
3670 case Encoding::none:
3672 case Encoding::japanese:
3673 if (encoding().iconvName() != "UTF-8"
3674 && !features.runparams().isFullUnicode()
3675 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3676 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3677 os << "\\UseRawInputEncoding\n";
3679 case Encoding::inputenc:
3680 // do not load inputenc if japanese is used
3681 // or if the class provides inputenc
3682 if (features.isRequired("japanese")
3683 || features.isProvided("inputenc"))
3685 // The 2022 release of ucs.sty uses the default utf8
3686 // inputenc encoding with 'utf8x' inputenc if the ucs
3687 // package is not loaded before inputenc.
3688 // This breaks existing documents that use utf8x
3689 // and also makes utf8x redundant.
3690 // Thus we load ucs.sty in order to keep functionality
3691 // that would otherwise be silently dropped.
3692 if (doc_encoding == "utf8x"
3693 && features.isAvailableAtLeastFrom("ucs", 2022, 8, 7)
3694 && !features.isProvided("ucs"))
3695 os << "\\usepackage{ucs}\n";
3696 os << "\\usepackage[" << doc_encoding << "]{"
3697 << inputenc_package << "}\n";
3701 if ((inputenc == "auto-legacy-plain" || features.isRequired("japanese"))
3702 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3703 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3704 os << "\\UseRawInputEncoding\n";
3708 string const BufferParams::parseFontName(string const & name) const
3710 string mangled = name;
3711 size_t const idx = mangled.find('[');
3712 if (idx == string::npos || idx == 0)
3715 return mangled.substr(0, idx - 1);
3719 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3721 if (fontsRoman() == "default" && fontsSans() == "default"
3722 && fontsTypewriter() == "default"
3723 && (fontsMath() == "default" || fontsMath() == "auto"))
3729 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3730 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3731 * Mapping=tex-text option assures TeX ligatures (such as "--")
3732 * are resolved. Note that tt does not use these ligatures.
3734 * -- add more GUI options?
3735 * -- add more fonts (fonts for other scripts)
3736 * -- if there's a way to find out if a font really supports
3737 * OldStyle, enable/disable the widget accordingly.
3739 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3740 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3741 // However, until v.2 (2010/07/11) fontspec only knew
3742 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3743 // was introduced for both XeTeX and LuaTeX (LuaTeX
3744 // didn't understand "Mapping=tex-text", while XeTeX
3745 // understood both. With most recent versions, both
3746 // variants are understood by both engines. However,
3747 // we want to provide support for at least TeXLive 2009
3748 // (for XeTeX; LuaTeX is only supported as of v.2)
3749 // As of 2017/11/03, Babel has its own higher-level
3750 // interface on top of fontspec that is to be used.
3751 bool const babelfonts = features.useBabel()
3752 && features.isAvailableAtLeastFrom("babel", 2017, 11, 3);
3753 string const texmapping =
3754 (features.runparams().flavor == Flavor::XeTeX) ?
3755 "Mapping=tex-text" : "Ligatures=TeX";
3756 if (fontsRoman() != "default") {
3758 os << "\\babelfont{rm}[";
3760 os << "\\setmainfont[";
3762 if (fonts_roman_osf)
3763 os << ",Numbers=OldStyle";
3764 if (!font_roman_opts.empty())
3765 os << ',' << font_roman_opts;
3766 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3768 if (fontsSans() != "default") {
3769 string const sans = parseFontName(fontsSans());
3770 if (fontsSansScale() != 100) {
3772 os << "\\babelfont{sf}";
3774 os << "\\setsansfont";
3776 << float(fontsSansScale()) / 100 << ',';
3778 os << "Numbers=OldStyle,";
3780 if (!font_sans_opts.empty())
3781 os << ',' << font_sans_opts;
3782 os << "]{" << sans << "}\n";
3785 os << "\\babelfont{sf}[";
3787 os << "\\setsansfont[";
3789 os << "Numbers=OldStyle,";
3791 if (!font_sans_opts.empty())
3792 os << ',' << font_sans_opts;
3793 os << "]{" << sans << "}\n";
3796 if (fontsTypewriter() != "default") {
3797 string const mono = parseFontName(fontsTypewriter());
3798 if (fontsTypewriterScale() != 100) {
3800 os << "\\babelfont{tt}";
3802 os << "\\setmonofont";
3804 << float(fontsTypewriterScale()) / 100;
3805 if (fonts_typewriter_osf)
3806 os << ",Numbers=OldStyle";
3807 if (!font_typewriter_opts.empty())
3808 os << ',' << font_typewriter_opts;
3813 os << "\\babelfont{tt}";
3815 os << "\\setmonofont";
3816 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3818 if (fonts_typewriter_osf)
3819 os << "Numbers=OldStyle";
3820 if (!font_typewriter_opts.empty()) {
3821 if (fonts_typewriter_osf)
3823 os << font_typewriter_opts;
3827 os << '{' << mono << "}\n";
3834 bool const ot1 = (features.runparams().main_fontenc == "default"
3835 || features.runparams().main_fontenc == "OT1");
3836 bool const dryrun = features.runparams().dryrun;
3837 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3838 bool const nomath = (fontsMath() != "auto");
3841 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3842 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3843 nomath, font_roman_opts);
3846 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3847 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3848 nomath, font_sans_opts, fontsSansScale());
3850 // MONOSPACED/TYPEWRITER
3851 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3852 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3853 nomath, font_typewriter_opts, fontsTypewriterScale());
3856 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3857 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3864 Encoding const & BufferParams::encoding() const
3866 // Main encoding for LaTeX output.
3868 return *(encodings.fromLyXName("utf8-plain"));
3869 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3870 return *language->encoding();
3871 if (inputenc == "utf8" && language->lang() == "japanese")
3872 return *(encodings.fromLyXName("utf8-platex"));
3873 Encoding const * const enc = encodings.fromLyXName(inputenc);
3876 LYXERR0("Unknown inputenc value `" << inputenc
3877 << "'. Using `auto' instead.");
3878 return *language->encoding();
3882 string const & BufferParams::defaultBiblioStyle() const
3884 if (!biblio_style.empty())
3885 return biblio_style;
3887 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3888 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3889 if (cit != bs.end())
3892 return empty_string();
3896 bool BufferParams::fullAuthorList() const
3898 return documentClass().fullAuthorList();
3902 string BufferParams::getCiteAlias(string const & s) const
3904 bool realcmd = false;
3905 vector<CitationStyle> const styles = citeStyles();
3906 for (size_t i = 0; i != styles.size(); ++i) {
3907 // only include variants that are supported in the current style
3908 if (styles[i].name == s && isActiveCiteStyle(styles[i])) {
3913 // If it is a real command, don't treat it as an alias
3916 map<string,string> aliases = documentClass().citeCommandAliases();
3917 if (aliases.find(s) != aliases.end())
3923 vector<string> BufferParams::citeCommands() const
3925 static CitationStyle const default_style;
3926 vector<string> commands =
3927 documentClass().citeCommands(citeEngineType());
3928 if (commands.empty())
3929 commands.push_back(default_style.name);
3934 vector<CitationStyle> BufferParams::citeStyles() const
3936 static CitationStyle const default_style;
3937 vector<CitationStyle> styles =
3938 documentClass().citeStyles(citeEngineType());
3940 styles.push_back(default_style);
3945 bool BufferParams::isActiveCiteStyle(CitationStyle const & cs) const
3948 // outside biblatex, all cite styles are active
3951 if (cs.styles.empty() && cs.nostyles.empty())
3955 // exclude variants that are excluded in the current style
3956 for (string const & s: cs.nostyles) {
3957 if (s == biblatex_citestyle)
3958 // explicitly excluded style
3961 if (cs.styles.empty())
3965 // only include variants that are supported in the current style
3966 for (string const & s: cs.styles) {
3967 if (s == biblatex_citestyle)
3973 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3975 // split from options
3977 split(cmd, command_in, ' ');
3979 // Look if the requested command is available. If so, use that.
3980 for (auto const & alts : lyxrc.bibtex_alternatives) {
3981 string command_prov;
3982 split(alts, command_prov, ' ');
3983 if (command_in == command_prov)
3987 // If not, find the most suitable fallback for the current cite framework,
3988 // and warn. Note that we omit options in any such case.
3990 if (useBiblatex()) {
3991 // For Biblatex, we prefer biber (also for Japanese)
3992 // and try to fall back to bibtex8
3993 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3995 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3996 fallback = "bibtex8";
3998 // For classic BibTeX and as last resort for biblatex, try bibtex
3999 if (fallback.empty()) {
4000 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
4001 fallback = "bibtex";
4007 if (fallback.empty()) {
4008 frontend::Alert::warning(
4009 _("No bibliography processor found!"),
4011 _("The bibliography processor requested by this document "
4012 "(%1$s) is not available and no appropriate "
4013 "alternative has been found. "
4014 "No bibliography and references will be generated.\n"
4015 "Please fix your installation!"),
4018 frontend::Alert::warning(
4019 _("Requested bibliography processor not found!"),
4021 _("The bibliography processor requested by this document "
4022 "(%1$s) is not available. "
4023 "As a fallback, '%2$s' will be used, options are omitted. "
4024 "This might result in errors or unwanted changes in "
4025 "the bibliography. Please check carefully!\n"
4026 "It is suggested to install the missing processor."),
4027 from_utf8(cmd), from_utf8(fallback)));
4033 string const BufferParams::bibtexCommand(bool const warn) const
4035 // Return document-specific setting if available
4036 if (bibtex_command != "default")
4037 return getBibtexCommand(bibtex_command, warn);
4039 // If we have "default" in document settings, consult the prefs
4040 // 1. Japanese (uses a specific processor)
4041 if (encoding().package() == Encoding::japanese) {
4042 if (lyxrc.jbibtex_command != "automatic")
4043 // Return the specified program, if "automatic" is not set
4044 return lyxrc.jbibtex_command;
4045 else if (!useBiblatex()) {
4046 // With classic BibTeX, return pbibtex, jbibtex, bibtex
4047 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
4049 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
4054 // 2. All other languages
4055 else if (lyxrc.bibtex_command != "automatic")
4056 // Return the specified program, if "automatic" is not set
4057 return getBibtexCommand(lyxrc.bibtex_command, warn);
4059 // 3. Automatic: find the most suitable for the current cite framework
4060 if (useBiblatex()) {
4061 // For Biblatex, we prefer biber (also for Japanese)
4062 // and fall back to bibtex8 and, as last resort, bibtex
4063 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
4065 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
4072 bool BufferParams::useBiblatex() const
4074 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
4078 void BufferParams::invalidateConverterCache() const
4080 pimpl_->isExportCacheValid = false;
4081 pimpl_->isViewCacheValid = false;
4085 // We shouldn't need to reset the params here, since anything
4086 // we need will be recopied.
4087 void BufferParams::copyForAdvFR(const BufferParams & bp)
4089 string const & lang = bp.language->lang();
4091 quotes_style = bp.quotes_style;
4092 layout_modules_ = bp.layout_modules_;
4093 string const & doc_class = bp.documentClass().name();
4094 setBaseClass(doc_class);
4098 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
4100 bib_encodings[file] = enc;
4104 string const BufferParams::bibFileEncoding(string const & file) const
4106 if (bib_encodings.find(file) == bib_encodings.end())
4108 return bib_encodings.find(file)->second;
4112 string const BufferParams::babelLangOptions(string const & lang, bool const onlycust) const
4114 if (lang_options_babel_.find(lang) == lang_options_babel_.end()) {
4115 Language const * l = languages.getLanguage(lang);
4116 return (l && !onlycust) ? l->babelOpts() : string();
4118 return lang_options_babel_.find(lang)->second;
4122 string const BufferParams::polyglossiaLangOptions(string const & lang) const
4124 if (lang_options_polyglossia_.find(lang) == lang_options_polyglossia_.end()) {
4125 Language const * l = languages.getLanguage(lang);
4126 return l ? l->polyglossiaOpts() : string();
4128 return lang_options_polyglossia_.find(lang)->second;
4132 BufferParams const & defaultBufferParams()
4134 static BufferParams default_params;
4135 return default_params;