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"
38 #include "OutputParams.h"
40 #include "texstream.h"
43 #include "PDFOptions.h"
45 #include "frontends/alert.h"
47 #include "insets/InsetListingsParams.h"
48 #include "insets/InsetQuotes.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Length.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",
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);
165 QuotesStyleTranslator const & quotesstyletranslator()
167 static QuotesStyleTranslator const translator =
168 init_quotesstyletranslator();
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
177 static PaperSizeTranslator initPaperSizeTranslator()
179 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180 translator.addPair(string_papersize[1], PAPER_CUSTOM);
181 translator.addPair(string_papersize[2], PAPER_USLETTER);
182 translator.addPair(string_papersize[3], PAPER_USLEGAL);
183 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184 translator.addPair(string_papersize[5], PAPER_A0);
185 translator.addPair(string_papersize[6], PAPER_A1);
186 translator.addPair(string_papersize[7], PAPER_A2);
187 translator.addPair(string_papersize[8], PAPER_A3);
188 translator.addPair(string_papersize[9], PAPER_A4);
189 translator.addPair(string_papersize[10], PAPER_A5);
190 translator.addPair(string_papersize[11], PAPER_A6);
191 translator.addPair(string_papersize[12], PAPER_B0);
192 translator.addPair(string_papersize[13], PAPER_B1);
193 translator.addPair(string_papersize[14], PAPER_B2);
194 translator.addPair(string_papersize[15], PAPER_B3);
195 translator.addPair(string_papersize[16], PAPER_B4);
196 translator.addPair(string_papersize[17], PAPER_B5);
197 translator.addPair(string_papersize[18], PAPER_B6);
198 translator.addPair(string_papersize[19], PAPER_C0);
199 translator.addPair(string_papersize[20], PAPER_C1);
200 translator.addPair(string_papersize[21], PAPER_C2);
201 translator.addPair(string_papersize[22], PAPER_C3);
202 translator.addPair(string_papersize[23], PAPER_C4);
203 translator.addPair(string_papersize[24], PAPER_C5);
204 translator.addPair(string_papersize[25], PAPER_C6);
205 translator.addPair(string_papersize[26], PAPER_JISB0);
206 translator.addPair(string_papersize[27], PAPER_JISB1);
207 translator.addPair(string_papersize[28], PAPER_JISB2);
208 translator.addPair(string_papersize[29], PAPER_JISB3);
209 translator.addPair(string_papersize[30], PAPER_JISB4);
210 translator.addPair(string_papersize[31], PAPER_JISB5);
211 translator.addPair(string_papersize[32], PAPER_JISB6);
216 PaperSizeTranslator const & papersizetranslator()
218 static PaperSizeTranslator const translator =
219 initPaperSizeTranslator();
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
228 PaperOrientationTranslator const init_paperorientationtranslator()
230 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
236 PaperOrientationTranslator const & paperorientationtranslator()
238 static PaperOrientationTranslator const translator =
239 init_paperorientationtranslator();
245 typedef Translator<int, PageSides> SidesTranslator;
248 SidesTranslator const init_sidestranslator()
250 SidesTranslator translator(1, OneSide);
251 translator.addPair(2, TwoSides);
256 SidesTranslator const & sidestranslator()
258 static SidesTranslator const translator = init_sidestranslator();
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
267 PackageTranslator const init_packagetranslator()
269 PackageTranslator translator(0, BufferParams::package_off);
270 translator.addPair(1, BufferParams::package_auto);
271 translator.addPair(2, BufferParams::package_on);
276 PackageTranslator const & packagetranslator()
278 static PackageTranslator const translator =
279 init_packagetranslator();
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
288 SpaceTranslator const init_spacetranslator()
290 SpaceTranslator translator("default", Spacing::Default);
291 translator.addPair("single", Spacing::Single);
292 translator.addPair("onehalf", Spacing::Onehalf);
293 translator.addPair("double", Spacing::Double);
294 translator.addPair("other", Spacing::Other);
299 SpaceTranslator const & spacetranslator()
301 static SpaceTranslator const translator = init_spacetranslator();
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
308 // A document is assumed to be in a system LyX directory (not
309 // necessarily the system directory of the running instance)
310 // if both "configure.py" and "chkconfig.ltx" are found in
311 // either document_dir/../ or document_dir/../../.
312 // If true, the system directory path is returned in system_dir
313 // with a trailing path separator.
315 string const msg = "Checking whether document is in a system dir...";
317 string dir = document_dir.absFileName();
319 for (int i = 0; i < 3; ++i) {
320 dir = addPath(dir, "..");
321 if (!fileSearch(dir, "configure.py").empty() &&
322 !fileSearch(dir, "chkconfig.ltx").empty()) {
323 LYXERR(Debug::FILES, msg << " yes");
324 system_dir = addPath(FileName(dir).realPath(), "");
329 LYXERR(Debug::FILES, msg << " no");
330 system_dir = string();
337 class BufferParams::Impl
342 AuthorList authorlist;
343 BranchList branchlist;
344 WordLangTable spellignore;
345 Bullet temp_bullets[4];
346 Bullet user_defined_bullets[4];
347 IndicesList indiceslist;
351 /** This is the amount of space used for paragraph_separation "skip",
352 * and for detached paragraphs in "indented" documents.
355 PDFOptions pdfoptions;
356 LayoutFileIndex baseClass_;
357 FormatList exportableFormatList;
358 FormatList viewableFormatList;
359 bool isViewCacheValid;
360 bool isExportCacheValid;
364 BufferParams::Impl::Impl()
365 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
366 isViewCacheValid(false), isExportCacheValid(false)
368 // set initial author
370 authorlist.record(Author(from_utf8(lyxrc.user_name),
371 from_utf8(lyxrc.user_email),
372 from_utf8(lyxrc.user_initials)));
377 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
380 return new BufferParams::Impl(*ptr);
384 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
390 BufferParams::BufferParams()
393 setBaseClass(defaultBaseclass());
394 cite_engine_ = "basic";
395 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
397 paragraph_separation = ParagraphIndentSeparation;
398 is_math_indent = false;
399 math_numbering_side = DEFAULT;
400 quotes_style = QuoteStyle::English;
401 dynamic_quotes = false;
402 fontsize = "default";
405 papersize = PAPER_DEFAULT;
406 orientation = ORIENTATION_PORTRAIT;
407 use_geometry = false;
408 biblio_style = string();
409 use_bibtopic = false;
412 save_transient_properties = true;
413 track_changes = false;
414 output_changes = false;
416 postpone_fragile_content = true;
417 use_default_options = true;
418 maintain_unincluded_children = CM_None;
421 language = default_language;
423 fonts_roman[0] = "default";
424 fonts_roman[1] = "default";
425 fonts_sans[0] = "default";
426 fonts_sans[1] = "default";
427 fonts_typewriter[0] = "default";
428 fonts_typewriter[1] = "default";
429 fonts_math[0] = "auto";
430 fonts_math[1] = "auto";
431 fonts_default_family = "default";
432 useNonTeXFonts = false;
433 use_microtype = false;
434 use_dash_ligatures = true;
435 fonts_expert_sc = false;
436 fonts_roman_osf = false;
437 fonts_sans_osf = false;
438 fonts_typewriter_osf = false;
439 fonts_sans_scale[0] = 100;
440 fonts_sans_scale[1] = 100;
441 fonts_typewriter_scale[0] = 100;
442 fonts_typewriter_scale[1] = 100;
444 lang_package = "default";
445 graphics_driver = "default";
446 default_output_format = "default";
447 bibtex_command = "default";
448 index_command = "default";
451 listings_params = string();
452 pagestyle = "default";
453 tablestyle = "default";
454 float_alignment = "class";
455 float_placement = "class";
456 suppress_date = false;
457 justification = true;
458 // no color is the default (white)
459 backgroundcolor = lyx::rgbFromHexName("#ffffff");
460 isbackgroundcolor = false;
461 // no color is the default (black)
462 fontcolor = lyx::rgbFromHexName("#000000");
464 // light gray is the default font color for greyed-out notes
465 notefontcolor = lyx::rgbFromHexName("#cccccc");
466 isnotefontcolor = false;
467 boxbgcolor = lyx::rgbFromHexName("#ff0000");
468 isboxbgcolor = false;
469 compressed = lyxrc.save_compressed;
470 for (int iter = 0; iter < 4; ++iter) {
471 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
475 indiceslist().addDefault(B_("Index"));
476 html_be_strict = false;
477 html_math_output = MathML;
478 html_math_img_scale = 1.0;
479 html_css_as_file = false;
480 docbook_table_output = HTMLTable;
481 docbook_mathml_prefix = MPrefix;
482 display_pixel_ratio = 1.0;
484 shell_escape = false;
490 // map current author
491 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
495 docstring BufferParams::B_(string const & l10n) const
497 LASSERT(language, return from_utf8(l10n));
498 return getMessages(language->code()).get(l10n);
502 BufferParams::Package BufferParams::use_package(std::string const & p) const
504 PackageMap::const_iterator it = use_packages.find(p);
505 if (it == use_packages.end())
511 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
517 map<string, string> const & BufferParams::auto_packages()
519 static map<string, string> packages;
520 if (packages.empty()) {
521 // We could have a race condition here that two threads
522 // discover an empty map at the same time and want to fill
523 // it, but that is no problem, since the same contents is
524 // filled in twice then. Having the locker inside the
525 // packages.empty() condition has the advantage that we
526 // don't need the mutex overhead for simple reading.
528 Mutex::Locker locker(&mutex);
529 // adding a package here implies a file format change!
530 packages["amsmath"] =
531 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
532 packages["amssymb"] =
533 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
535 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
537 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
538 packages["mathdots"] =
539 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
540 packages["mathtools"] =
541 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
543 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
544 packages["stackrel"] =
545 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
546 packages["stmaryrd"] =
547 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");
548 packages["undertilde"] =
549 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
555 bool BufferParams::useBibtopic() const
559 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
563 AuthorList & BufferParams::authors()
565 return pimpl_->authorlist;
569 AuthorList const & BufferParams::authors() const
571 return pimpl_->authorlist;
575 void BufferParams::addAuthor(Author const & a)
577 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
581 BranchList & BufferParams::branchlist()
583 return pimpl_->branchlist;
587 BranchList const & BufferParams::branchlist() const
589 return pimpl_->branchlist;
593 IndicesList & BufferParams::indiceslist()
595 return pimpl_->indiceslist;
599 IndicesList const & BufferParams::indiceslist() const
601 return pimpl_->indiceslist;
605 WordLangTable & BufferParams::spellignore()
607 return pimpl_->spellignore;
611 WordLangTable const & BufferParams::spellignore() const
613 return pimpl_->spellignore;
617 bool BufferParams::spellignored(WordLangTuple const & wl) const
619 bool has_item = false;
620 vector<WordLangTuple> il = spellignore();
621 vector<WordLangTuple>::const_iterator it = il.begin();
622 for (; it != il.end(); ++it) {
623 if (it->lang()->code() != wl.lang()->code())
625 if (it->word() == wl.word()) {
634 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
637 return pimpl_->temp_bullets[index];
638 // Fallback bullet if we are too deeply nested
639 docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
640 Bullet const & res = Bullet(fb);
641 return const_cast<Bullet&>(res);
645 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
648 return pimpl_->temp_bullets[index];
649 // Fallback bullet if we are too deeply nested
650 docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
651 Bullet const & res = Bullet(fb);
656 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
659 return pimpl_->user_defined_bullets[index];
660 // Fallback bullet if we are too deeply nested
661 docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
662 Bullet const & res = Bullet(fb);
663 return const_cast<Bullet&>(res);
667 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
670 return pimpl_->user_defined_bullets[index];
671 // Fallback bullet if we are too deeply nested
672 docstring const fb = from_ascii("?") + convert<docstring>(index + 1);
673 Bullet const & res = Bullet(fb);
678 Spacing & BufferParams::spacing()
680 return pimpl_->spacing;
684 Spacing const & BufferParams::spacing() const
686 return pimpl_->spacing;
690 PDFOptions & BufferParams::pdfoptions()
692 return pimpl_->pdfoptions;
696 PDFOptions const & BufferParams::pdfoptions() const
698 return pimpl_->pdfoptions;
702 Length const & BufferParams::getMathIndent() const
704 return pimpl_->mathindent;
708 void BufferParams::setMathIndent(Length const & indent)
710 pimpl_->mathindent = indent;
714 Length const & BufferParams::getParIndent() const
716 return pimpl_->parindent;
720 void BufferParams::setParIndent(Length const & indent)
722 pimpl_->parindent = indent;
726 VSpace const & BufferParams::getDefSkip() const
728 return pimpl_->defskip;
732 void BufferParams::setDefSkip(VSpace const & vs)
734 // DEFSKIP will cause an infinite loop
735 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
736 pimpl_->defskip = vs;
740 BufferParams::MathNumber BufferParams::getMathNumber() const
742 if (math_numbering_side != DEFAULT)
743 return math_numbering_side;
744 // FIXME: do not hardcode language here
745 else if (language->lang() == "arabic_arabi"
746 || documentClass().provides("leqno"))
753 string BufferParams::readToken(Lexer & lex, string const & token,
754 FileName const & filename)
757 FileName const & filepath = filename.onlyPath();
759 if (token == "\\textclass") {
761 string const classname = lex.getString();
762 // if there exists a local layout file, ignore the system one
763 // NOTE: in this case, the textclass (.cls file) is assumed to
766 LayoutFileList & bcl = LayoutFileList::get();
767 if (!filepath.empty()) {
768 // If classname is an absolute path, the document is
769 // using a local layout file which could not be accessed
770 // by a relative path. In this case the path is correct
771 // even if the document was moved to a different
772 // location. However, we will have a problem if the
773 // document was generated on a different platform.
774 bool isabsolute = FileName::isAbsolute(classname);
775 string const classpath = onlyPath(classname);
776 string const path = isabsolute ? classpath
777 : FileName(addPath(filepath.absFileName(),
778 classpath)).realPath();
779 string const oldpath = isabsolute ? string()
780 : FileName(addPath(origin, classpath)).realPath();
781 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
783 // that returns non-empty if a "local" layout file is found.
785 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
786 from_utf8(filepath.absFileName())));
789 setBaseClass(onlyFileName(tcp));
791 setBaseClass(onlyFileName(classname));
792 // We assume that a tex class exists for local or unknown
793 // layouts so this warning, will only be given for system layouts.
794 if (!baseClass()->isTeXClassAvailable()) {
795 docstring const desc =
796 translateIfPossible(from_utf8(baseClass()->description()));
797 docstring const prereqs =
798 from_utf8(baseClass()->prerequisites());
799 docstring const msg =
800 bformat(_("The selected document class\n"
802 "requires external files that are not available.\n"
803 "The document class can still be used, but the\n"
804 "document cannot be compiled until the following\n"
805 "prerequisites are installed:\n"
807 "See section 3.1.2.2 (Class Availability) of the\n"
808 "User's Guide for more information."), desc, prereqs);
809 frontend::Alert::warning(_("Document class not available"),
812 } else if (token == "\\save_transient_properties") {
813 lex >> save_transient_properties;
814 } else if (token == "\\origin") {
816 origin = lex.getString();
817 string const sysdirprefix = "/systemlyxdir/";
818 if (prefixIs(origin, sysdirprefix)) {
820 if (inSystemDir(filepath, docsys))
821 origin.replace(0, sysdirprefix.length() - 1, docsys);
823 origin.replace(0, sysdirprefix.length() - 1,
824 package().system_support().absFileName());
826 } else if (token == "\\begin_metadata") {
827 readDocumentMetadata(lex);
828 } else if (token == "\\begin_preamble") {
830 } else if (token == "\\begin_local_layout") {
831 readLocalLayout(lex, false);
832 } else if (token == "\\begin_forced_local_layout") {
833 readLocalLayout(lex, true);
834 } else if (token == "\\begin_modules") {
836 } else if (token == "\\begin_removed_modules") {
837 readRemovedModules(lex);
838 } else if (token == "\\begin_includeonly") {
839 readIncludeonly(lex);
840 } else if (token == "\\maintain_unincluded_children") {
844 maintain_unincluded_children = CM_None;
845 else if (tmp == "mostly")
846 maintain_unincluded_children = CM_Mostly;
847 else if (tmp == "strict")
848 maintain_unincluded_children = CM_Strict;
849 } else if (token == "\\options") {
851 options = lex.getString();
852 } else if (token == "\\use_default_options") {
853 lex >> use_default_options;
854 } else if (token == "\\master") {
856 master = lex.getString();
857 if (!filepath.empty() && FileName::isAbsolute(origin)) {
858 bool const isabs = FileName::isAbsolute(master);
859 FileName const abspath(isabs ? master : origin + master);
860 bool const moved = filepath != FileName(origin);
861 if (moved && abspath.exists()) {
862 docstring const path = isabs
864 : from_utf8(abspath.realPath());
865 docstring const refpath =
866 from_utf8(filepath.absFileName());
867 master = to_utf8(makeRelPath(path, refpath));
870 } else if (token == "\\suppress_date") {
871 lex >> suppress_date;
872 } else if (token == "\\justification") {
873 lex >> justification;
874 } else if (token == "\\language") {
876 } else if (token == "\\language_package") {
878 lang_package = lex.getString();
879 } else if (token == "\\inputencoding") {
881 } else if (token == "\\graphics") {
882 readGraphicsDriver(lex);
883 } else if (token == "\\default_output_format") {
884 lex >> default_output_format;
885 } else if (token == "\\bibtex_command") {
887 bibtex_command = lex.getString();
888 } else if (token == "\\index_command") {
890 index_command = lex.getString();
891 } else if (token == "\\fontencoding") {
893 fontenc = lex.getString();
894 } else if (token == "\\font_roman") {
895 lex >> fonts_roman[0];
896 lex >> fonts_roman[1];
897 } else if (token == "\\font_sans") {
898 lex >> fonts_sans[0];
899 lex >> fonts_sans[1];
900 } else if (token == "\\font_typewriter") {
901 lex >> fonts_typewriter[0];
902 lex >> fonts_typewriter[1];
903 } else if (token == "\\font_math") {
904 lex >> fonts_math[0];
905 lex >> fonts_math[1];
906 } else if (token == "\\font_default_family") {
907 lex >> fonts_default_family;
908 } else if (token == "\\use_non_tex_fonts") {
909 lex >> useNonTeXFonts;
910 } else if (token == "\\font_sc") {
911 lex >> fonts_expert_sc;
912 } else if (token == "\\font_roman_osf") {
913 lex >> fonts_roman_osf;
914 } else if (token == "\\font_sans_osf") {
915 lex >> fonts_sans_osf;
916 } else if (token == "\\font_typewriter_osf") {
917 lex >> fonts_typewriter_osf;
918 } else if (token == "\\font_roman_opts") {
919 lex >> font_roman_opts;
920 } else if (token == "\\font_sf_scale") {
921 lex >> fonts_sans_scale[0];
922 lex >> fonts_sans_scale[1];
923 } else if (token == "\\font_sans_opts") {
924 lex >> font_sans_opts;
925 } else if (token == "\\font_tt_scale") {
926 lex >> fonts_typewriter_scale[0];
927 lex >> fonts_typewriter_scale[1];
928 } else if (token == "\\font_typewriter_opts") {
929 lex >> font_typewriter_opts;
930 } else if (token == "\\font_cjk") {
932 } else if (token == "\\use_microtype") {
933 lex >> use_microtype;
934 } else if (token == "\\use_dash_ligatures") {
935 lex >> use_dash_ligatures;
936 } else if (token == "\\paragraph_separation") {
939 paragraph_separation = parseptranslator().find(parsep);
940 } else if (token == "\\paragraph_indentation") {
942 string parindent = lex.getString();
943 if (parindent == "default")
944 pimpl_->parindent = Length();
946 pimpl_->parindent = Length(parindent);
947 } else if (token == "\\defskip") {
949 string const defskip = lex.getString();
950 pimpl_->defskip = VSpace(defskip);
951 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
953 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
954 } else if (token == "\\is_math_indent") {
955 lex >> is_math_indent;
956 } else if (token == "\\math_indentation") {
958 string mathindent = lex.getString();
959 if (mathindent == "default")
960 pimpl_->mathindent = Length();
962 pimpl_->mathindent = Length(mathindent);
963 } else if (token == "\\math_numbering_side") {
967 math_numbering_side = LEFT;
968 else if (tmp == "right")
969 math_numbering_side = RIGHT;
971 math_numbering_side = DEFAULT;
972 } else if (token == "\\quotes_style") {
975 quotes_style = quotesstyletranslator().find(qstyle);
976 } else if (token == "\\dynamic_quotes") {
977 lex >> dynamic_quotes;
978 } else if (token == "\\papersize") {
981 papersize = papersizetranslator().find(ppsize);
982 } else if (token == "\\use_geometry") {
984 } else if (token == "\\use_package") {
989 use_package(package, packagetranslator().find(use));
990 } else if (token == "\\cite_engine") {
992 cite_engine_ = lex.getString();
993 } else if (token == "\\cite_engine_type") {
996 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
997 } else if (token == "\\biblio_style") {
999 biblio_style = lex.getString();
1000 } else if (token == "\\biblio_options") {
1002 biblio_opts = trim(lex.getString());
1003 } else if (token == "\\biblatex_bibstyle") {
1005 biblatex_bibstyle = trim(lex.getString());
1006 } else if (token == "\\biblatex_citestyle") {
1008 biblatex_citestyle = trim(lex.getString());
1009 } else if (token == "\\use_bibtopic") {
1010 lex >> use_bibtopic;
1011 } else if (token == "\\multibib") {
1013 } else if (token == "\\use_indices") {
1015 } else if (token == "\\tracking_changes") {
1016 lex >> track_changes;
1017 } else if (token == "\\output_changes") {
1018 lex >> output_changes;
1019 } else if (token == "\\change_bars") {
1021 } else if (token == "\\postpone_fragile_content") {
1022 lex >> postpone_fragile_content;
1023 } else if (token == "\\branch") {
1025 docstring branch = lex.getDocString();
1026 branchlist().add(branch);
1029 string const tok = lex.getString();
1030 if (tok == "\\end_branch")
1032 Branch * branch_ptr = branchlist().find(branch);
1033 if (tok == "\\selected") {
1036 branch_ptr->setSelected(lex.getInteger());
1038 if (tok == "\\filename_suffix") {
1041 branch_ptr->setFileNameSuffix(lex.getInteger());
1043 if (tok == "\\color") {
1045 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1046 string const lmcolor = colors.front();
1048 if (colors.size() > 1)
1049 dmcolor = colors.back();
1051 branch_ptr->setColors(lmcolor, dmcolor);
1054 } else if (token == "\\index") {
1056 docstring index = lex.getDocString();
1058 indiceslist().add(index);
1061 string const tok = lex.getString();
1062 if (tok == "\\end_index")
1064 Index * index_ptr = indiceslist().find(index);
1065 if (tok == "\\shortcut") {
1067 shortcut = lex.getDocString();
1069 index_ptr->setShortcut(shortcut);
1071 if (tok == "\\color") {
1073 string color = lex.getString();
1075 index_ptr->setColor(color);
1076 // Update also the Color table:
1077 if (color == "none")
1078 color = lcolor.getX11HexName(Color_background);
1080 if (!shortcut.empty())
1081 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1084 } else if (token == "\\spellchecker_ignore") {
1086 docstring wl = lex.getDocString();
1088 docstring word = split(wl, language, ' ');
1089 Language const * lang = languages.getLanguage(to_ascii(language));
1091 spellignore().push_back(WordLangTuple(word, lang));
1092 } else if (token == "\\author") {
1094 istringstream ss(lex.getString());
1098 } else if (token == "\\paperorientation") {
1101 orientation = paperorientationtranslator().find(orient);
1102 } else if (token == "\\backgroundcolor") {
1104 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1105 isbackgroundcolor = true;
1106 } else if (token == "\\fontcolor") {
1108 fontcolor = lyx::rgbFromHexName(lex.getString());
1110 } else if (token == "\\notefontcolor") {
1112 string color = lex.getString();
1113 notefontcolor = lyx::rgbFromHexName(color);
1114 lcolor.setColor("notefontcolor", color);
1115 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1116 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1117 // set a local name for the painter
1118 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1119 isnotefontcolor = true;
1120 } else if (token == "\\boxbgcolor") {
1122 string color = lex.getString();
1123 boxbgcolor = lyx::rgbFromHexName(color);
1124 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1125 isboxbgcolor = true;
1126 } else if (token == "\\paperwidth") {
1128 } else if (token == "\\paperheight") {
1130 } else if (token == "\\leftmargin") {
1132 } else if (token == "\\topmargin") {
1134 } else if (token == "\\rightmargin") {
1136 } else if (token == "\\bottommargin") {
1137 lex >> bottommargin;
1138 } else if (token == "\\headheight") {
1140 } else if (token == "\\headsep") {
1142 } else if (token == "\\footskip") {
1144 } else if (token == "\\columnsep") {
1146 } else if (token == "\\paperfontsize") {
1148 } else if (token == "\\papercolumns") {
1150 } else if (token == "\\listings_params") {
1153 listings_params = InsetListingsParams(par).params();
1154 } else if (token == "\\papersides") {
1157 sides = sidestranslator().find(psides);
1158 } else if (token == "\\paperpagestyle") {
1160 } else if (token == "\\tablestyle") {
1162 } else if (token == "\\bullet") {
1164 } else if (token == "\\bulletLaTeX") {
1165 readBulletsLaTeX(lex);
1166 } else if (token == "\\secnumdepth") {
1168 } else if (token == "\\tocdepth") {
1170 } else if (token == "\\spacing") {
1174 if (nspacing == "other") {
1177 spacing().set(spacetranslator().find(nspacing), tmp_val);
1178 } else if (token == "\\float_placement") {
1179 lex >> float_placement;
1180 } else if (token == "\\float_alignment") {
1181 lex >> float_alignment;
1183 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1184 string toktmp = pdfoptions().readToken(lex, token);
1185 if (!toktmp.empty()) {
1186 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1190 } else if (token == "\\html_math_output") {
1193 html_math_output = static_cast<MathOutput>(temp);
1194 } else if (token == "\\html_be_strict") {
1195 lex >> html_be_strict;
1196 } else if (token == "\\html_css_as_file") {
1197 lex >> html_css_as_file;
1198 } else if (token == "\\html_math_img_scale") {
1199 lex >> html_math_img_scale;
1200 } else if (token == "\\html_latex_start") {
1202 html_latex_start = lex.getString();
1203 } else if (token == "\\html_latex_end") {
1205 html_latex_end = lex.getString();
1206 } else if (token == "\\docbook_table_output") {
1209 docbook_table_output = static_cast<TableOutput>(temp);
1210 } else if (token == "\\docbook_mathml_prefix") {
1213 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1214 } else if (token == "\\output_sync") {
1216 } else if (token == "\\output_sync_macro") {
1217 lex >> output_sync_macro;
1218 } else if (token == "\\use_refstyle") {
1219 lex >> use_refstyle;
1220 } else if (token == "\\use_minted") {
1222 } else if (token == "\\use_lineno") {
1224 } else if (token == "\\lineno_options") {
1226 lineno_opts = trim(lex.getString());
1228 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1238 // Quote argument if it contains spaces
1239 string quoteIfNeeded(string const & str) {
1240 if (contains(str, ' '))
1241 return "\"" + str + "\"";
1247 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1249 // The top of the file is written by the buffer.
1250 // Prints out the buffer info into the .lyx file given by file
1252 os << "\\save_transient_properties "
1253 << convert<string>(save_transient_properties) << '\n';
1255 // the document directory (must end with a path separator)
1256 // realPath() is used to resolve symlinks, while addPath(..., "")
1257 // ensures a trailing path separator.
1259 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1260 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1261 : addPath(package().system_support().realPath(), "");
1262 string const relpath =
1263 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1264 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1265 filepath = addPath("/systemlyxdir", relpath);
1266 else if (!save_transient_properties || !lyxrc.save_origin)
1267 filepath = "unavailable";
1268 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1271 os << "\\textclass "
1272 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1273 baseClass()->name()), "layout"))
1276 // then document metadata
1277 if (!document_metadata.empty()) {
1278 // remove '\n' from the end of document_metadata
1279 docstring const tmpmd = rtrim(document_metadata, "\n");
1280 os << "\\begin_metadata\n"
1282 << "\n\\end_metadata\n";
1285 // then the preamble
1286 if (!preamble.empty()) {
1287 // remove '\n' from the end of preamble
1288 docstring const tmppreamble = rtrim(preamble, "\n");
1289 os << "\\begin_preamble\n"
1290 << to_utf8(tmppreamble)
1291 << "\n\\end_preamble\n";
1295 if (!options.empty()) {
1296 os << "\\options " << options << '\n';
1299 // use the class options defined in the layout?
1300 os << "\\use_default_options "
1301 << convert<string>(use_default_options) << "\n";
1303 // the master document
1304 if (!master.empty()) {
1305 os << "\\master " << master << '\n';
1309 if (!removed_modules_.empty()) {
1310 os << "\\begin_removed_modules" << '\n';
1311 for (auto const & mod : removed_modules_)
1313 os << "\\end_removed_modules" << '\n';
1317 if (!layout_modules_.empty()) {
1318 os << "\\begin_modules" << '\n';
1319 for (auto const & mod : layout_modules_)
1321 os << "\\end_modules" << '\n';
1325 if (!included_children_.empty()) {
1326 os << "\\begin_includeonly" << '\n';
1327 for (auto const & c : included_children_)
1329 os << "\\end_includeonly" << '\n';
1332 switch (maintain_unincluded_children) {
1343 os << "\\maintain_unincluded_children " << muc << '\n';
1345 // local layout information
1346 docstring const local_layout = getLocalLayout(false);
1347 if (!local_layout.empty()) {
1348 // remove '\n' from the end
1349 docstring const tmplocal = rtrim(local_layout, "\n");
1350 os << "\\begin_local_layout\n"
1351 << to_utf8(tmplocal)
1352 << "\n\\end_local_layout\n";
1354 docstring const forced_local_layout = getLocalLayout(true);
1355 if (!forced_local_layout.empty()) {
1356 // remove '\n' from the end
1357 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1358 os << "\\begin_forced_local_layout\n"
1359 << to_utf8(tmplocal)
1360 << "\n\\end_forced_local_layout\n";
1363 // then the text parameters
1364 if (language != ignore_language)
1365 os << "\\language " << language->lang() << '\n';
1366 os << "\\language_package " << lang_package
1367 << "\n\\inputencoding " << inputenc
1368 << "\n\\fontencoding " << fontenc
1369 << "\n\\font_roman \"" << fonts_roman[0]
1370 << "\" \"" << fonts_roman[1] << '"'
1371 << "\n\\font_sans \"" << fonts_sans[0]
1372 << "\" \"" << fonts_sans[1] << '"'
1373 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1374 << "\" \"" << fonts_typewriter[1] << '"'
1375 << "\n\\font_math \"" << fonts_math[0]
1376 << "\" \"" << fonts_math[1] << '"'
1377 << "\n\\font_default_family " << fonts_default_family
1378 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1379 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1380 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1381 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1382 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1383 if (!font_roman_opts.empty())
1384 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1385 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1386 << ' ' << fonts_sans_scale[1];
1387 if (!font_sans_opts.empty())
1388 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1389 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1390 << ' ' << fonts_typewriter_scale[1];
1391 if (!font_typewriter_opts.empty())
1392 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1394 if (!fonts_cjk.empty())
1395 os << "\\font_cjk " << fonts_cjk << '\n';
1396 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1397 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1398 os << "\\graphics " << graphics_driver << '\n';
1399 os << "\\default_output_format " << default_output_format << '\n';
1400 os << "\\output_sync " << output_sync << '\n';
1401 if (!output_sync_macro.empty())
1402 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1403 os << "\\bibtex_command " << bibtex_command << '\n';
1404 os << "\\index_command " << index_command << '\n';
1406 if (!float_placement.empty())
1407 os << "\\float_placement " << float_placement << '\n';
1408 if (!float_alignment.empty())
1409 os << "\\float_alignment " << float_alignment << '\n';
1410 os << "\\paperfontsize " << fontsize << '\n';
1412 spacing().writeFile(os);
1413 pdfoptions().writeFile(os);
1415 os << "\\papersize " << string_papersize[papersize]
1416 << "\n\\use_geometry " << convert<string>(use_geometry);
1417 map<string, string> const & packages = auto_packages();
1418 for (auto const & pack : packages)
1419 os << "\n\\use_package " << pack.first << ' '
1420 << use_package(pack.first);
1422 os << "\n\\cite_engine ";
1424 if (!cite_engine_.empty())
1429 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1431 if (!biblio_style.empty())
1432 os << "\n\\biblio_style " << biblio_style;
1433 if (!biblio_opts.empty())
1434 os << "\n\\biblio_options " << biblio_opts;
1435 if (!biblatex_bibstyle.empty())
1436 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1437 if (!biblatex_citestyle.empty())
1438 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1439 if (!multibib.empty())
1440 os << "\n\\multibib " << multibib;
1442 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1443 << "\n\\use_indices " << convert<string>(use_indices)
1444 << "\n\\paperorientation " << string_orientation[orientation]
1445 << "\n\\suppress_date " << convert<string>(suppress_date)
1446 << "\n\\justification " << convert<string>(justification)
1447 << "\n\\use_refstyle " << use_refstyle
1448 << "\n\\use_minted " << use_minted
1449 << "\n\\use_lineno " << use_lineno
1452 if (!lineno_opts.empty())
1453 os << "\\lineno_options " << lineno_opts << '\n';
1455 if (isbackgroundcolor)
1456 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1458 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1459 if (isnotefontcolor)
1460 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1462 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1464 for (auto const & br : branchlist()) {
1465 os << "\\branch " << to_utf8(br.branch())
1466 << "\n\\selected " << br.isSelected()
1467 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1468 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1473 for (auto const & id : indiceslist()) {
1474 os << "\\index " << to_utf8(id.index())
1475 << "\n\\shortcut " << to_utf8(id.shortcut())
1476 << "\n\\color " << lyx::X11hexname(id.color())
1481 for (auto const & si : spellignore()) {
1482 os << "\\spellchecker_ignore " << si.lang()->lang()
1483 << " " << to_utf8(si.word())
1487 if (!paperwidth.empty())
1488 os << "\\paperwidth "
1489 << VSpace(paperwidth).asLyXCommand() << '\n';
1490 if (!paperheight.empty())
1491 os << "\\paperheight "
1492 << VSpace(paperheight).asLyXCommand() << '\n';
1493 if (!leftmargin.empty())
1494 os << "\\leftmargin "
1495 << VSpace(leftmargin).asLyXCommand() << '\n';
1496 if (!topmargin.empty())
1497 os << "\\topmargin "
1498 << VSpace(topmargin).asLyXCommand() << '\n';
1499 if (!rightmargin.empty())
1500 os << "\\rightmargin "
1501 << VSpace(rightmargin).asLyXCommand() << '\n';
1502 if (!bottommargin.empty())
1503 os << "\\bottommargin "
1504 << VSpace(bottommargin).asLyXCommand() << '\n';
1505 if (!headheight.empty())
1506 os << "\\headheight "
1507 << VSpace(headheight).asLyXCommand() << '\n';
1508 if (!headsep.empty())
1510 << VSpace(headsep).asLyXCommand() << '\n';
1511 if (!footskip.empty())
1513 << VSpace(footskip).asLyXCommand() << '\n';
1514 if (!columnsep.empty())
1515 os << "\\columnsep "
1516 << VSpace(columnsep).asLyXCommand() << '\n';
1517 os << "\\secnumdepth " << secnumdepth
1518 << "\n\\tocdepth " << tocdepth
1519 << "\n\\paragraph_separation "
1520 << string_paragraph_separation[paragraph_separation];
1521 if (!paragraph_separation)
1522 os << "\n\\paragraph_indentation "
1523 << (getParIndent().empty() ? "default" : getParIndent().asString());
1525 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1526 os << "\n\\is_math_indent " << is_math_indent;
1528 os << "\n\\math_indentation "
1529 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1530 os << "\n\\math_numbering_side ";
1531 switch(math_numbering_side) {
1541 os << "\n\\quotes_style "
1542 << string_quotes_style[static_cast<int>(quotes_style)]
1543 << "\n\\dynamic_quotes " << dynamic_quotes
1544 << "\n\\papercolumns " << columns
1545 << "\n\\papersides " << sides
1546 << "\n\\paperpagestyle " << pagestyle
1547 << "\n\\tablestyle " << tablestyle << '\n';
1548 if (!listings_params.empty())
1549 os << "\\listings_params \"" <<
1550 InsetListingsParams(listings_params).encodedString() << "\"\n";
1551 for (int i = 0; i < 4; ++i) {
1552 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1553 if (user_defined_bullet(i).getFont() != -1) {
1554 os << "\\bullet " << i << " "
1555 << user_defined_bullet(i).getFont() << " "
1556 << user_defined_bullet(i).getCharacter() << " "
1557 << user_defined_bullet(i).getSize() << "\n";
1561 os << "\\bulletLaTeX " << i << " \""
1562 << lyx::to_ascii(user_defined_bullet(i).getText())
1568 os << "\\tracking_changes "
1569 << (save_transient_properties ? convert<string>(track_changes) : "false")
1572 os << "\\output_changes "
1573 << (save_transient_properties ? convert<string>(output_changes) : "false")
1576 os << "\\change_bars "
1577 << (save_transient_properties ? convert<string>(change_bars) : "false")
1580 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1582 os << "\\html_math_output " << html_math_output << '\n'
1583 << "\\html_css_as_file " << html_css_as_file << '\n'
1584 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1586 os << "\\docbook_table_output " << docbook_table_output << '\n';
1587 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1589 if (html_math_img_scale != 1.0)
1590 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1591 if (!html_latex_start.empty())
1592 os << "\\html_latex_start " << html_latex_start << '\n';
1593 if (!html_latex_end.empty())
1594 os << "\\html_latex_end " << html_latex_end << '\n';
1596 os << pimpl_->authorlist;
1600 void BufferParams::validate(LaTeXFeatures & features) const
1602 features.require(documentClass().required());
1604 if (columns > 1 && language->rightToLeft())
1605 features.require("rtloutputdblcol");
1607 if (output_changes) {
1608 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1609 LaTeXFeatures::isAvailable("xcolor");
1611 switch (features.runparams().flavor) {
1613 case Flavor::DviLuaTeX:
1615 features.require("ct-xcolor-ulem");
1616 features.require("ulem");
1617 features.require("xcolor");
1619 features.require("ct-none");
1622 case Flavor::LuaTeX:
1623 case Flavor::PdfLaTeX:
1626 features.require("ct-xcolor-ulem");
1627 features.require("ulem");
1628 features.require("xcolor");
1629 // improves color handling in PDF output
1630 features.require("pdfcolmk");
1632 features.require("ct-none");
1639 features.require("changebar");
1642 // Floats with 'Here definitely' as default setting.
1643 if (float_placement.find('H') != string::npos)
1644 features.require("float");
1646 for (auto const & pm : use_packages) {
1647 if (pm.first == "amsmath") {
1648 // AMS Style is at document level
1649 if (pm.second == package_on ||
1650 features.isProvided("amsmath"))
1651 features.require(pm.first);
1652 } else if (pm.second == package_on)
1653 features.require(pm.first);
1656 // Document-level line spacing
1657 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1658 features.require("setspace");
1660 // the bullet shapes are buffer level not paragraph level
1661 // so they are tested here
1662 for (int i = 0; i < 4; ++i) {
1663 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1665 int const font = user_defined_bullet(i).getFont();
1667 int const c = user_defined_bullet(i).getCharacter();
1673 features.require("latexsym");
1675 } else if (font == 1) {
1676 features.require("amssymb");
1677 } else if (font >= 2 && font <= 5) {
1678 features.require("pifont");
1682 if (pdfoptions().use_hyperref) {
1683 features.require("hyperref");
1684 // due to interferences with babel and hyperref, the color package has to
1685 // be loaded after hyperref when hyperref is used with the colorlinks
1686 // option, see http://www.lyx.org/trac/ticket/5291
1687 if (pdfoptions().colorlinks)
1688 features.require("color");
1690 if (!listings_params.empty()) {
1691 // do not test validity because listings_params is
1692 // supposed to be valid
1694 InsetListingsParams(listings_params).separatedParams(true);
1695 // we can't support all packages, but we should load the color package
1696 if (par.find("\\color", 0) != string::npos)
1697 features.require("color");
1700 // some languages are only available via polyglossia
1701 if (features.hasPolyglossiaExclusiveLanguages())
1702 features.require("polyglossia");
1704 if (useNonTeXFonts && fontsMath() != "auto")
1705 features.require("unicode-math");
1708 features.require("microtype");
1710 if (!language->required().empty())
1711 features.require(language->required());
1715 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1716 FileName const & filepath) const
1718 // DocumentMetadata must come before anything else
1719 if (features.isAvailable("LaTeX-2022/06/01")
1720 && !containsOnly(document_metadata, " \n\t")) {
1721 // Check if the user preamble contains uncodable glyphs
1722 odocstringstream doc_metadata;
1723 docstring uncodable_glyphs;
1724 Encoding const * const enc = features.runparams().encoding;
1726 for (char_type c : document_metadata) {
1727 if (!enc->encodable(c)) {
1728 docstring const glyph(1, c);
1729 LYXERR0("Uncodable character '"
1731 << "' in document metadata!");
1732 uncodable_glyphs += glyph;
1733 if (features.runparams().dryrun) {
1734 doc_metadata << "<" << _("LyX Warning: ")
1735 << _("uncodable character") << " '";
1736 doc_metadata.put(c);
1737 doc_metadata << "'>";
1740 doc_metadata.put(c);
1743 doc_metadata << document_metadata;
1745 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1746 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1747 frontend::Alert::warning(
1748 _("Uncodable character in document metadata"),
1750 _("The metadata of your document contains glyphs "
1751 "that are unknown in the current document encoding "
1752 "(namely %1$s).\nThese glyphs are omitted "
1753 " from the output, which may result in "
1754 "incomplete output."
1755 "\n\nPlease select an appropriate "
1756 "document encoding\n"
1757 "(such as utf8) or change the "
1758 "preamble code accordingly."),
1761 if (!doc_metadata.str().empty()) {
1762 os << "\\DocumentMetadata{\n"
1763 << doc_metadata.str()
1768 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1769 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1770 // \RequirePackage to do so, rather than the normal \usepackage
1771 // Do not try to load any other package before the document class, unless you
1772 // have a thorough understanding of the LATEX internals and know exactly what you
1774 if (features.mustProvide("fix-cm"))
1775 os << "\\RequirePackage{fix-cm}\n";
1776 // Likewise for fixltx2e. If other packages conflict with this policy,
1777 // treat it as a package bug (and report it!)
1778 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1779 if (features.mustProvide("fixltx2e"))
1780 os << "\\RequirePackage{fixltx2e}\n";
1782 os << "\\documentclass";
1784 DocumentClass const & tclass = documentClass();
1786 ostringstream clsoptions; // the document class options.
1788 if (tokenPos(tclass.opt_fontsize(),
1789 '|', fontsize) >= 0) {
1790 // only write if existing in list (and not default)
1791 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1794 // paper sizes not supported by the class itself need the
1796 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1797 bool class_supported_papersize = papersize == PAPER_DEFAULT
1798 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1800 if ((!use_geometry || features.isProvided("geometry-light"))
1801 && class_supported_papersize && papersize != PAPER_DEFAULT)
1802 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1805 if (sides != tclass.sides()) {
1808 clsoptions << "oneside,";
1811 clsoptions << "twoside,";
1817 if (columns != tclass.columns()) {
1819 clsoptions << "twocolumn,";
1821 clsoptions << "onecolumn,";
1825 && orientation == ORIENTATION_LANDSCAPE)
1826 clsoptions << "landscape,";
1829 clsoptions << "fleqn,";
1831 switch(math_numbering_side) {
1833 clsoptions << "leqno,";
1836 clsoptions << "reqno,";
1837 features.require("amsmath");
1843 // language should be a parameter to \documentclass
1844 if (language->babel() == "hebrew"
1845 && default_language->babel() != "hebrew")
1846 // This seems necessary
1847 features.useLanguage(default_language);
1849 ostringstream language_options;
1850 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1851 bool const use_polyglossia = features.usePolyglossia();
1852 bool const global = lyxrc.language_global_options;
1853 if (features.useBabel() || (use_polyglossia && global)) {
1854 language_options << features.getBabelLanguages();
1855 if (!language->babel().empty()) {
1856 if (!language_options.str().empty())
1857 language_options << ',';
1858 language_options << language->babel();
1860 if (global && !language_options.str().empty())
1861 clsoptions << language_options.str() << ',';
1864 // the predefined options from the layout
1865 if (use_default_options && !tclass.options().empty())
1866 clsoptions << tclass.options() << ',';
1868 // the user-defined options
1869 if (!options.empty()) {
1870 clsoptions << options << ',';
1873 docstring const strOptions = from_utf8(clsoptions.str());
1874 if (!strOptions.empty()) {
1875 // Check if class options contain uncodable glyphs
1876 docstring uncodable_glyphs;
1877 docstring options_encodable;
1878 Encoding const * const enc = features.runparams().encoding;
1880 for (char_type c : strOptions) {
1881 if (!enc->encodable(c)) {
1882 docstring const glyph(1, c);
1883 LYXERR0("Uncodable character '"
1885 << "' in class options!");
1886 uncodable_glyphs += glyph;
1887 if (features.runparams().dryrun) {
1888 options_encodable += "<" + _("LyX Warning: ")
1889 + _("uncodable character") + " '";
1890 options_encodable += c;
1891 options_encodable += "'>";
1894 options_encodable += c;
1897 options_encodable = strOptions;
1899 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1900 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1901 frontend::Alert::warning(
1902 _("Uncodable character in class options"),
1904 _("The class options of your document contain glyphs "
1905 "that are unknown in the current document encoding "
1906 "(namely %1$s).\nThese glyphs are omitted "
1907 " from the output, which may result in "
1908 "incomplete output."
1909 "\n\nPlease select an appropriate "
1910 "document encoding\n"
1911 "(such as utf8) or change the "
1912 "class options accordingly."),
1915 options_encodable = rtrim(options_encodable, ",");
1916 os << '[' << options_encodable << ']';
1919 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1920 // end of \documentclass defs
1922 // The package options (via \PassOptionsToPackage)
1923 os << from_ascii(features.getPackageOptions());
1925 // if we use fontspec or newtxmath, we have to load the AMS packages here
1926 string const ams = features.loadAMSPackages();
1927 string const main_font_enc = features.runparams().main_fontenc;
1928 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1929 bool const use_newtxmath =
1930 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1931 ot1, false, false) == "newtxmath";
1932 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1933 os << from_ascii(ams);
1935 if (useNonTeXFonts) {
1936 // Babel (as of 2017/11/03) loads fontspec itself
1937 if (!features.isProvided("fontspec")
1938 && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1939 os << "\\usepackage{fontspec}\n";
1940 if (features.mustProvide("unicode-math")
1941 && features.isAvailable("unicode-math"))
1942 os << "\\usepackage{unicode-math}\n";
1945 // load CJK support package before font selection
1946 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1947 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1948 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1949 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1950 os << "\\usepackage{CJKutf8}\n";
1952 os << "\\usepackage[encapsulated]{CJK}\n";
1955 // font selection must be done before loading fontenc.sty
1956 // but after babel with non-TeX fonts
1957 string const fonts = loadFonts(features);
1958 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1959 os << from_utf8(fonts);
1961 if (fonts_default_family != "default")
1962 os << "\\renewcommand{\\familydefault}{\\"
1963 << from_ascii(fonts_default_family) << "}\n";
1965 // set font encoding
1966 // non-TeX fonts use font encoding TU (set by fontspec)
1967 if (!useNonTeXFonts && !features.isProvided("fontenc")
1968 && main_font_enc != "default") {
1969 // get main font encodings
1970 vector<string> fontencs = font_encodings();
1971 // get font encodings of secondary languages
1972 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1973 // option (for text in other languages).
1974 features.getFontEncodings(fontencs);
1975 if (!fontencs.empty()) {
1976 os << "\\usepackage["
1977 << from_ascii(getStringFromVector(fontencs))
1982 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1983 if (features.mustProvide("textcomp"))
1984 os << "\\usepackage{textcomp}\n";
1985 if (features.mustProvide("pmboxdraw"))
1986 os << "\\usepackage{pmboxdraw}\n";
1988 // handle inputenc etc.
1989 // (In documents containing text in Thai language,
1990 // we must load inputenc after babel, see lib/languages).
1991 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1992 writeEncodingPreamble(os, features);
1995 if (!features.runparams().includeall && !included_children_.empty()) {
1996 os << "\\includeonly{";
1998 for (auto incfile : included_children_) {
1999 FileName inc = makeAbsPath(incfile, filepath.absFileName());
2000 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
2002 if (!features.runparams().nice)
2004 // \includeonly doesn't want an extension
2005 incfile = changeExtension(incfile, string());
2006 incfile = support::latex_path(incfile);
2007 if (!incfile.empty()) {
2010 os << from_utf8(incfile);
2017 if (!features.isProvided("geometry")
2018 && (use_geometry || !class_supported_papersize)) {
2019 odocstringstream ods;
2020 if (!getGraphicsDriver("geometry").empty())
2021 ods << getGraphicsDriver("geometry");
2022 if (orientation == ORIENTATION_LANDSCAPE)
2023 ods << ",landscape";
2024 switch (papersize) {
2026 if (!paperwidth.empty())
2027 ods << ",paperwidth="
2028 << from_ascii(paperwidth);
2029 if (!paperheight.empty())
2030 ods << ",paperheight="
2031 << from_ascii(paperheight);
2033 case PAPER_USLETTER:
2035 case PAPER_USEXECUTIVE:
2064 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2069 docstring g_options = trim(ods.str(), ",");
2070 os << "\\usepackage";
2071 // geometry-light means that the class works with geometry, but overwrites
2072 // the package options and paper sizes (memoir does this).
2073 // In this case, all options need to go to \geometry
2074 // and the standard paper sizes need to go to the class options.
2075 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2076 os << '[' << g_options << ']';
2079 os << "{geometry}\n";
2080 if (use_geometry || features.isProvided("geometry-light")) {
2081 os << "\\geometry{verbose";
2082 if (!g_options.empty())
2083 // Output general options here with "geometry light".
2084 os << "," << g_options;
2085 // output this only if use_geometry is true
2087 if (!topmargin.empty())
2088 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2089 if (!bottommargin.empty())
2090 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2091 if (!leftmargin.empty())
2092 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2093 if (!rightmargin.empty())
2094 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2095 if (!headheight.empty())
2096 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2097 if (!headsep.empty())
2098 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2099 if (!footskip.empty())
2100 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2101 if (!columnsep.empty())
2102 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2106 } else if (orientation == ORIENTATION_LANDSCAPE
2107 || papersize != PAPER_DEFAULT) {
2108 features.require("papersize");
2111 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2112 if (pagestyle == "fancy")
2113 os << "\\usepackage{fancyhdr}\n";
2114 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2117 // only output when the background color is not default
2118 if (isbackgroundcolor) {
2119 // only require color here, the background color will be defined
2120 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2122 features.require("color");
2123 features.require("pagecolor");
2126 // only output when the font color is not default
2128 // only require color here, the font color will be defined
2129 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2131 features.require("color");
2132 features.require("fontcolor");
2135 // Only if class has a ToC hierarchy
2136 if (tclass.hasTocLevels()) {
2137 if (secnumdepth != tclass.secnumdepth()) {
2138 os << "\\setcounter{secnumdepth}{"
2142 if (tocdepth != tclass.tocdepth()) {
2143 os << "\\setcounter{tocdepth}{"
2149 if (paragraph_separation) {
2150 // when skip separation
2152 switch (getDefSkip().kind()) {
2153 case VSpace::SMALLSKIP:
2154 psopt = "\\smallskipamount";
2156 case VSpace::MEDSKIP:
2157 psopt = "\\medskipamount";
2159 case VSpace::BIGSKIP:
2160 psopt = "\\bigskipamount";
2162 case VSpace::HALFLINE:
2163 // default (no option)
2165 case VSpace::FULLLINE:
2166 psopt = "\\baselineskip";
2168 case VSpace::LENGTH:
2169 psopt = getDefSkip().length().asLatexString();
2174 if (!features.isProvided("parskip")) {
2176 psopt = "[skip=" + psopt + "]";
2177 os << "\\usepackage" + psopt + "{parskip}\n";
2179 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2182 // when separation by indentation
2183 // only output something when a width is given
2184 if (!getParIndent().empty()) {
2185 os << "\\setlength{\\parindent}{"
2186 << from_utf8(getParIndent().asLatexString())
2191 if (is_math_indent) {
2192 // when formula indentation
2193 // only output something when it is not the default
2194 if (!getMathIndent().empty()) {
2195 os << "\\setlength{\\mathindent}{"
2196 << from_utf8(getMathIndent().asString())
2201 // Now insert the LyX specific LaTeX commands...
2202 features.resolveAlternatives();
2203 features.expandMultiples();
2206 if (!output_sync_macro.empty())
2207 os << from_utf8(output_sync_macro) +"\n";
2208 else if (features.runparams().flavor == Flavor::LaTeX)
2209 os << "\\usepackage[active]{srcltx}\n";
2210 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2211 os << "\\synctex=-1\n";
2214 // due to interferences with babel and hyperref, the color package has to
2215 // be loaded (when it is not already loaded) before babel when hyperref
2216 // is used with the colorlinks option, see
2217 // http://www.lyx.org/trac/ticket/5291
2218 // we decided therefore to load color always before babel, see
2219 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2220 os << from_ascii(features.getColorOptions());
2222 // If we use hyperref, jurabib, japanese or varioref,
2223 // we have to call babel before
2225 && (features.isRequired("jurabib")
2226 || features.isRequired("hyperref")
2227 || features.isRequired("varioref")
2228 || features.isRequired("japanese"))) {
2229 os << features.getBabelPresettings();
2231 os << from_utf8(babelCall(language_options.str(),
2232 !lyxrc.language_global_options)) + '\n';
2233 os << features.getBabelPostsettings();
2236 // The optional packages;
2237 os << from_ascii(features.getPackages());
2239 // Additional Indices
2240 if (features.isRequired("splitidx")) {
2241 for (auto const & idx : indiceslist()) {
2242 os << "\\newindex{";
2243 os << escape(idx.shortcut());
2249 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2252 // * Hyperref manual: "Make sure it comes last of your loaded
2253 // packages, to give it a fighting chance of not being over-written,
2254 // since its job is to redefine many LaTeX commands."
2255 // * Email from Heiko Oberdiek: "It is usually better to load babel
2256 // before hyperref. Then hyperref has a chance to detect babel.
2257 // * Has to be loaded before the "LyX specific LaTeX commands" to
2258 // avoid errors with algorithm floats.
2259 // use hyperref explicitly if it is required
2260 if (features.isRequired("hyperref")) {
2261 OutputParams tmp_params = features.runparams();
2262 pdfoptions().writeLaTeX(tmp_params, os,
2263 features.isProvided("hyperref"));
2264 // correctly break URLs with hyperref and dvi/ps output
2265 if (features.runparams().hyperref_driver == "dvips"
2266 && features.isAvailable("breakurl"))
2267 os << "\\usepackage{breakurl}\n";
2268 } else if (features.isRequired("nameref"))
2269 // hyperref loads this automatically
2270 os << "\\usepackage{nameref}\n";
2273 os << "\\usepackage";
2274 if (!lineno_opts.empty())
2275 os << "[" << lineno_opts << "]";
2277 os << "\\linenumbers\n";
2280 // bibtopic needs to be loaded after hyperref.
2281 // the dot provides the aux file naming which LyX can detect.
2282 if (features.mustProvide("bibtopic"))
2283 os << "\\usepackage[dot]{bibtopic}\n";
2285 // Will be surrounded by \makeatletter and \makeatother when not empty
2286 otexstringstream atlyxpreamble;
2288 // Some macros LyX will need
2290 TexString tmppreamble = features.getMacros();
2291 if (!tmppreamble.str.empty())
2292 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2293 "LyX specific LaTeX commands.\n"
2294 << move(tmppreamble)
2297 // the text class specific preamble
2299 docstring tmppreamble = features.getTClassPreamble();
2300 if (!tmppreamble.empty())
2301 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2302 "Textclass specific LaTeX commands.\n"
2306 // suppress date if selected
2307 // use \@ifundefined because we cannot be sure that every document class
2308 // has a \date command
2310 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2312 /* the user-defined preamble */
2313 if (!containsOnly(preamble, " \n\t")) {
2315 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2316 "User specified LaTeX commands.\n";
2318 // Check if the user preamble contains uncodable glyphs
2319 odocstringstream user_preamble;
2320 docstring uncodable_glyphs;
2321 Encoding const * const enc = features.runparams().encoding;
2323 for (char_type c : preamble) {
2324 if (!enc->encodable(c)) {
2325 docstring const glyph(1, c);
2326 LYXERR0("Uncodable character '"
2328 << "' in user preamble!");
2329 uncodable_glyphs += glyph;
2330 if (features.runparams().dryrun) {
2331 user_preamble << "<" << _("LyX Warning: ")
2332 << _("uncodable character") << " '";
2333 user_preamble.put(c);
2334 user_preamble << "'>";
2337 user_preamble.put(c);
2340 user_preamble << preamble;
2342 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2343 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2344 frontend::Alert::warning(
2345 _("Uncodable character in user preamble"),
2347 _("The user preamble of your document contains glyphs "
2348 "that are unknown in the current document encoding "
2349 "(namely %1$s).\nThese glyphs are omitted "
2350 " from the output, which may result in "
2351 "incomplete output."
2352 "\n\nPlease select an appropriate "
2353 "document encoding\n"
2354 "(such as utf8) or change the "
2355 "preamble code accordingly."),
2358 atlyxpreamble << user_preamble.str() << '\n';
2361 // footmisc must be loaded after setspace
2362 // Load it here to avoid clashes with footmisc loaded in the user
2363 // preamble. For that reason we also pass the options via
2364 // \PassOptionsToPackage in getPreamble() and not here.
2365 if (features.mustProvide("footmisc"))
2366 atlyxpreamble << "\\usepackage{footmisc}\n";
2368 // subfig loads internally the LaTeX package "caption". As
2369 // caption is a very popular package, users will load it in
2370 // the preamble. Therefore we must load subfig behind the
2371 // user-defined preamble and check if the caption package was
2372 // loaded or not. For the case that caption is loaded before
2373 // subfig, there is the subfig option "caption=false". This
2374 // option also works when a koma-script class is used and
2375 // koma's own caption commands are used instead of caption. We
2376 // use \PassOptionsToPackage here because the user could have
2377 // already loaded subfig in the preamble.
2378 if (features.mustProvide("subfig"))
2379 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2380 " % Caption package is used. Advise subfig not to load it again.\n"
2381 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2383 "\\usepackage{subfig}\n";
2385 // Itemize bullet settings need to be last in case the user
2386 // defines their own bullets that use a package included
2387 // in the user-defined preamble -- ARRae
2388 // Actually it has to be done much later than that
2389 // since some packages like frenchb make modifications
2390 // at \begin{document} time -- JMarc
2391 docstring bullets_def;
2392 for (int i = 0; i < 4; ++i) {
2393 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2394 if (bullets_def.empty())
2395 bullets_def += "\\AtBeginDocument{\n";
2396 bullets_def += " \\def\\labelitemi";
2398 // `i' is one less than the item to modify
2405 bullets_def += "ii";
2411 bullets_def += '{' +
2412 user_defined_bullet(i).getText()
2417 if (!bullets_def.empty())
2418 atlyxpreamble << bullets_def << "}\n\n";
2420 if (!atlyxpreamble.empty())
2421 os << "\n\\makeatletter\n"
2422 << atlyxpreamble.release()
2423 << "\\makeatother\n\n";
2425 // We try to load babel late, in case it interferes with other packages.
2426 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2427 // have to be called after babel, though.
2428 if (use_babel && !features.isRequired("jurabib")
2429 && !features.isRequired("hyperref")
2430 && !features.isRequired("varioref")
2431 && !features.isRequired("japanese")) {
2432 os << features.getBabelPresettings();
2434 os << from_utf8(babelCall(language_options.str(),
2435 !lyxrc.language_global_options)) + '\n';
2436 os << features.getBabelPostsettings();
2438 // In documents containing text in Thai language,
2439 // we must load inputenc after babel (see lib/languages).
2440 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2441 writeEncodingPreamble(os, features);
2443 // font selection must be done after babel with non-TeX fonts
2444 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2445 os << from_utf8(fonts);
2447 if (features.isRequired("bicaption"))
2448 os << "\\usepackage{bicaption}\n";
2449 if (!listings_params.empty()
2450 || features.mustProvide("listings")
2451 || features.mustProvide("minted")) {
2453 os << "\\usepackage{minted}\n";
2455 os << "\\usepackage{listings}\n";
2457 string lst_params = listings_params;
2458 // If minted, do not output the language option (bug 11203)
2459 if (use_minted && contains(lst_params, "language=")) {
2460 vector<string> opts =
2461 getVectorFromString(lst_params, ",", false);
2462 for (size_t i = 0; i < opts.size(); ++i) {
2463 if (prefixIs(opts[i], "language="))
2464 opts.erase(opts.begin() + i--);
2466 lst_params = getStringFromVector(opts, ",");
2468 if (!lst_params.empty()) {
2470 os << "\\setminted{";
2473 // do not test validity because listings_params is
2474 // supposed to be valid
2476 InsetListingsParams(lst_params).separatedParams(true);
2477 os << from_utf8(par);
2481 // xunicode only needs to be loaded if tipa is used
2482 // (the rest is obsoleted by the new TU encoding).
2483 // It needs to be loaded at least after amsmath, amssymb,
2484 // esint and the other packages that provide special glyphs
2485 if (features.mustProvide("tipa") && useNonTeXFonts
2486 && !features.isProvided("xunicode")) {
2487 // The `xunicode` package officially only supports XeTeX,
2488 // but also works with LuaTeX. We work around its XeTeX test.
2489 if (features.runparams().flavor != Flavor::XeTeX) {
2490 os << "% Pretend to xunicode that we are XeTeX\n"
2491 << "\\def\\XeTeXpicfile{}\n";
2493 os << "\\usepackage{xunicode}\n";
2496 // covington must be loaded after beamerarticle
2497 if (features.isRequired("covington"))
2498 os << "\\usepackage{covington}\n";
2500 // Polyglossia must be loaded last ...
2501 if (use_polyglossia) {
2503 os << "\\usepackage{polyglossia}\n";
2504 // set the main language
2505 os << "\\setdefaultlanguage";
2506 if (!language->polyglossiaOpts().empty())
2507 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2508 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2509 // now setup the other languages
2510 set<string> const polylangs =
2511 features.getPolyglossiaLanguages();
2512 for (auto const & pl : polylangs) {
2513 // We do not output the options here; they are output in
2514 // the language switch commands. This is safer if multiple
2515 // varieties are used.
2516 if (pl == language->polyglossia())
2518 os << "\\setotherlanguage";
2519 os << "{" << from_ascii(pl) << "}\n";
2523 // ... but before biblatex (see #7065)
2524 if ((features.mustProvide("biblatex")
2525 || features.isRequired("biblatex-chicago"))
2526 && !features.isProvided("biblatex-chicago")
2527 && !features.isProvided("biblatex-natbib")
2528 && !features.isProvided("natbib-internal")
2529 && !features.isProvided("natbib")
2530 && !features.isProvided("jurabib")) {
2531 // The biblatex-chicago package has a differing interface
2532 // it uses a wrapper package and loads styles via fixed options
2533 bool const chicago = features.isRequired("biblatex-chicago");
2536 os << "\\usepackage";
2537 if (!biblatex_bibstyle.empty()
2538 && (biblatex_bibstyle == biblatex_citestyle)
2540 opts = "style=" + biblatex_bibstyle;
2542 } else if (!chicago) {
2543 if (!biblatex_bibstyle.empty()) {
2544 opts = "bibstyle=" + biblatex_bibstyle;
2547 if (!biblatex_citestyle.empty()) {
2548 opts += delim + "citestyle=" + biblatex_citestyle;
2552 if (!multibib.empty() && multibib != "child") {
2553 opts += delim + "refsection=" + multibib;
2556 if (bibtexCommand() == "bibtex8"
2557 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2558 opts += delim + "backend=bibtex8";
2560 } else if (bibtexCommand() == "bibtex"
2561 || prefixIs(bibtexCommand(), "bibtex ")) {
2562 opts += delim + "backend=bibtex";
2565 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2566 opts += delim + "bibencoding="
2567 + encodings.fromLyXName(bib_encoding)->latexName();
2570 if (!biblio_opts.empty())
2571 opts += delim + biblio_opts;
2573 os << "[" << opts << "]";
2575 os << "{biblatex-chicago}\n";
2577 os << "{biblatex}\n";
2581 // Load custom language package here
2582 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2583 if (lang_package == "default")
2584 os << from_utf8(lyxrc.language_custom_package);
2586 os << from_utf8(lang_package);
2590 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2591 // it is recommended to load menukeys as the last package (even after hyperref)
2592 if (features.isRequired("menukeys"))
2593 os << "\\usepackage{menukeys}\n";
2595 docstring const i18npreamble =
2596 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2598 if (!i18npreamble.empty())
2599 os << i18npreamble + '\n';
2605 void BufferParams::useClassDefaults()
2607 DocumentClass const & tclass = documentClass();
2609 sides = tclass.sides();
2610 columns = tclass.columns();
2611 pagestyle = tclass.pagestyle();
2612 tablestyle = tclass.tablestyle();
2613 use_default_options = true;
2614 // Only if class has a ToC hierarchy
2615 if (tclass.hasTocLevels()) {
2616 secnumdepth = tclass.secnumdepth();
2617 tocdepth = tclass.tocdepth();
2622 bool BufferParams::hasClassDefaults() const
2624 DocumentClass const & tclass = documentClass();
2626 return sides == tclass.sides()
2627 && columns == tclass.columns()
2628 && pagestyle == tclass.pagestyle()
2629 && tablestyle == tclass.tablestyle()
2630 && use_default_options
2631 && secnumdepth == tclass.secnumdepth()
2632 && tocdepth == tclass.tocdepth();
2636 DocumentClass const & BufferParams::documentClass() const
2642 DocumentClassConstPtr BufferParams::documentClassPtr() const
2648 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2650 // evil, but this function is evil
2651 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2652 invalidateConverterCache();
2656 bool BufferParams::setBaseClass(string const & classname, string const & path)
2658 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2659 LayoutFileList & bcl = LayoutFileList::get();
2660 if (!bcl.haveClass(classname)) {
2662 bformat(_("The layout file:\n"
2664 "could not be found. A default textclass with default\n"
2665 "layouts will be used. LyX will not be able to produce\n"
2667 from_utf8(classname));
2668 frontend::Alert::error(_("Document class not found"), s);
2669 bcl.addEmptyClass(classname);
2672 bool const success = bcl[classname].load(path);
2675 bformat(_("Due to some error in it, the layout file:\n"
2677 "could not be loaded. A default textclass with default\n"
2678 "layouts will be used. LyX will not be able to produce\n"
2680 from_utf8(classname));
2681 frontend::Alert::error(_("Could not load class"), s);
2682 bcl.addEmptyClass(classname);
2685 pimpl_->baseClass_ = classname;
2686 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2691 LayoutFile const * BufferParams::baseClass() const
2693 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2694 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2700 LayoutFileIndex const & BufferParams::baseClassID() const
2702 return pimpl_->baseClass_;
2706 void BufferParams::makeDocumentClass(bool clone, bool internal)
2711 invalidateConverterCache();
2712 LayoutModuleList mods;
2713 for (auto const & mod : layout_modules_)
2714 mods.push_back(mod);
2716 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2718 TextClass::ReturnValues success = TextClass::OK;
2719 if (!forced_local_layout_.empty())
2720 success = doc_class_->read(to_utf8(forced_local_layout_),
2722 if (!local_layout_.empty() &&
2723 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2724 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2725 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2726 docstring const msg = _("Error reading internal layout information");
2727 frontend::Alert::warning(_("Read Error"), msg);
2732 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2734 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2738 docstring BufferParams::getLocalLayout(bool forced) const
2741 return from_utf8(doc_class_->forcedLayouts());
2743 return local_layout_;
2747 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2750 forced_local_layout_ = layout;
2752 local_layout_ = layout;
2756 bool BufferParams::addLayoutModule(string const & modName)
2758 for (auto const & mod : layout_modules_)
2761 layout_modules_.push_back(modName);
2766 string BufferParams::bufferFormat() const
2768 return documentClass().outputFormat();
2772 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2774 FormatList const & formats = exportableFormats(need_viewable);
2775 for (auto const & fmt : formats) {
2776 if (fmt->name() == format)
2783 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2785 FormatList & cached = only_viewable ?
2786 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2787 bool & valid = only_viewable ?
2788 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2792 vector<string> const backs = backends();
2793 set<string> excludes;
2794 if (useNonTeXFonts) {
2795 excludes.insert("latex");
2796 excludes.insert("pdflatex");
2797 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2798 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2799 excludes.insert("xetex");
2803 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2804 vector<string>::const_iterator it = backs.begin() + 1;
2805 for (; it != backs.end(); ++it) {
2806 FormatList r = theConverters().getReachable(*it, only_viewable,
2808 result.insert(result.end(), r.begin(), r.end());
2810 sort(result.begin(), result.end(), Format::formatSorter);
2817 vector<string> BufferParams::backends() const
2820 string const buffmt = bufferFormat();
2822 // FIXME: Don't hardcode format names here, but use a flag
2823 if (buffmt == "latex") {
2824 if (encoding().package() == Encoding::japanese)
2825 v.push_back("platex");
2827 if (!useNonTeXFonts) {
2828 v.push_back("pdflatex");
2829 v.push_back("latex");
2832 || inputenc == "ascii" || inputenc == "utf8-plain")
2833 v.push_back("xetex");
2834 v.push_back("luatex");
2835 v.push_back("dviluatex");
2838 string rbuffmt = buffmt;
2839 // If we use an OutputFormat in Japanese docs,
2840 // we need special format in order to get the path
2841 // via pLaTeX (#8823)
2842 if (documentClass().hasOutputFormat()
2843 && encoding().package() == Encoding::japanese)
2845 v.push_back(rbuffmt);
2848 v.push_back("xhtml");
2849 v.push_back("docbook5");
2850 v.push_back("text");
2856 Flavor BufferParams::getOutputFlavor(string const & format) const
2858 string const dformat = (format.empty() || format == "default") ?
2859 getDefaultOutputFormat() : format;
2860 DefaultFlavorCache::const_iterator it =
2861 default_flavors_.find(dformat);
2863 if (it != default_flavors_.end())
2866 Flavor result = Flavor::LaTeX;
2868 // FIXME It'd be better not to hardcode this, but to do
2869 // something with formats.
2870 if (dformat == "xhtml")
2871 result = Flavor::Html;
2872 else if (dformat == "docbook5")
2873 result = Flavor::DocBook5;
2874 else if (dformat == "text")
2875 result = Flavor::Text;
2876 else if (dformat == "lyx")
2877 result = Flavor::LyX;
2878 else if (dformat == "pdflatex")
2879 result = Flavor::PdfLaTeX;
2880 else if (dformat == "xetex")
2881 result = Flavor::XeTeX;
2882 else if (dformat == "luatex")
2883 result = Flavor::LuaTeX;
2884 else if (dformat == "dviluatex")
2885 result = Flavor::DviLuaTeX;
2887 // Try to determine flavor of default output format
2888 vector<string> backs = backends();
2889 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2890 // Get shortest path to format
2891 Graph::EdgePath path;
2892 for (auto const & bvar : backs) {
2893 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2894 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2899 result = theConverters().getFlavor(path);
2902 // cache this flavor
2903 default_flavors_[dformat] = result;
2908 string BufferParams::getDefaultOutputFormat() const
2910 if (!default_output_format.empty()
2911 && default_output_format != "default")
2912 return default_output_format;
2913 if (encoding().package() == Encoding::japanese)
2914 return lyxrc.default_platex_view_format;
2916 return lyxrc.default_otf_view_format;
2917 return lyxrc.default_view_format;
2920 Font const BufferParams::getFont() const
2922 FontInfo f = documentClass().defaultfont();
2923 if (fonts_default_family == "rmdefault")
2924 f.setFamily(ROMAN_FAMILY);
2925 else if (fonts_default_family == "sfdefault")
2926 f.setFamily(SANS_FAMILY);
2927 else if (fonts_default_family == "ttdefault")
2928 f.setFamily(TYPEWRITER_FAMILY);
2929 return Font(f, language);
2933 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2935 return quotesstyletranslator().find(qs);
2939 bool BufferParams::isLatex() const
2941 return documentClass().outputType() == LATEX;
2945 bool BufferParams::isLiterate() const
2947 return documentClass().outputType() == LITERATE;
2951 void BufferParams::readPreamble(Lexer & lex)
2953 if (lex.getString() != "\\begin_preamble")
2954 lyxerr << "Error (BufferParams::readPreamble):"
2955 "consistency check failed." << endl;
2957 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2961 void BufferParams::readDocumentMetadata(Lexer & lex)
2963 if (lex.getString() != "\\begin_metadata")
2964 lyxerr << "Error (BufferParams::readDocumentMetadata):"
2965 "consistency check failed." << endl;
2967 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
2971 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2973 string const expected = forced ? "\\begin_forced_local_layout" :
2974 "\\begin_local_layout";
2975 if (lex.getString() != expected)
2976 lyxerr << "Error (BufferParams::readLocalLayout):"
2977 "consistency check failed." << endl;
2980 forced_local_layout_ =
2981 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2983 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2987 bool BufferParams::setLanguage(string const & lang)
2989 Language const *new_language = languages.getLanguage(lang);
2990 if (!new_language) {
2991 // Language lang was not found
2994 language = new_language;
2999 void BufferParams::readLanguage(Lexer & lex)
3001 if (!lex.next()) return;
3003 string const tmptok = lex.getString();
3005 // check if tmptok is part of tex_babel in tex-defs.h
3006 if (!setLanguage(tmptok)) {
3007 // Language tmptok was not found
3008 language = default_language;
3009 lyxerr << "Warning: Setting language `"
3010 << tmptok << "' to `" << language->lang()
3016 void BufferParams::readGraphicsDriver(Lexer & lex)
3021 string const tmptok = lex.getString();
3022 // check if tmptok is part of tex_graphics in tex_defs.h
3025 string const test = tex_graphics[n++];
3027 if (test == tmptok) {
3028 graphics_driver = tmptok;
3033 "Warning: graphics driver `$$Token' not recognized!\n"
3034 " Setting graphics driver to `default'.\n");
3035 graphics_driver = "default";
3042 void BufferParams::readBullets(Lexer & lex)
3047 int const index = lex.getInteger();
3049 int temp_int = lex.getInteger();
3050 user_defined_bullet(index).setFont(temp_int);
3051 temp_bullet(index).setFont(temp_int);
3053 user_defined_bullet(index).setCharacter(temp_int);
3054 temp_bullet(index).setCharacter(temp_int);
3056 user_defined_bullet(index).setSize(temp_int);
3057 temp_bullet(index).setSize(temp_int);
3061 void BufferParams::readBulletsLaTeX(Lexer & lex)
3063 // The bullet class should be able to read this.
3066 int const index = lex.getInteger();
3068 docstring const temp_str = lex.getDocString();
3070 user_defined_bullet(index).setText(temp_str);
3071 temp_bullet(index).setText(temp_str);
3075 void BufferParams::readModules(Lexer & lex)
3077 if (!lex.eatLine()) {
3078 lyxerr << "Error (BufferParams::readModules):"
3079 "Unexpected end of input." << endl;
3083 string mod = lex.getString();
3084 if (mod == "\\end_modules")
3086 addLayoutModule(mod);
3092 void BufferParams::readRemovedModules(Lexer & lex)
3094 if (!lex.eatLine()) {
3095 lyxerr << "Error (BufferParams::readRemovedModules):"
3096 "Unexpected end of input." << endl;
3100 string mod = lex.getString();
3101 if (mod == "\\end_removed_modules")
3103 removed_modules_.push_back(mod);
3106 // now we want to remove any removed modules that were previously
3107 // added. normally, that will be because default modules were added in
3108 // setBaseClass(), which gets called when \textclass is read at the
3109 // start of the read.
3110 for (auto const & rm : removed_modules_) {
3111 LayoutModuleList::iterator const mit = layout_modules_.begin();
3112 LayoutModuleList::iterator const men = layout_modules_.end();
3113 LayoutModuleList::iterator found = find(mit, men, rm);
3116 layout_modules_.erase(found);
3121 void BufferParams::readIncludeonly(Lexer & lex)
3123 if (!lex.eatLine()) {
3124 lyxerr << "Error (BufferParams::readIncludeonly):"
3125 "Unexpected end of input." << endl;
3129 string child = lex.getString();
3130 if (child == "\\end_includeonly")
3132 included_children_.push_back(child);
3138 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3140 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3143 if (documentClass().pagesize() == "default")
3144 // could be anything, so don't guess
3146 return paperSizeName(purpose, documentClass().pagesize());
3147 case PAPER_CUSTOM: {
3148 if (purpose == XDVI && !paperwidth.empty() &&
3149 !paperheight.empty()) {
3150 // heightxwidth<unit>
3151 string first = paperwidth;
3152 string second = paperheight;
3153 if (orientation == ORIENTATION_LANDSCAPE)
3156 return first.erase(first.length() - 2)
3162 // dvips and dvipdfm do not know this
3163 if (purpose == DVIPS || purpose == DVIPDFM)
3167 if (purpose == DVIPS || purpose == DVIPDFM)
3171 if (purpose == DVIPS || purpose == DVIPDFM)
3181 if (purpose == DVIPS || purpose == DVIPDFM)
3185 if (purpose == DVIPS || purpose == DVIPDFM)
3189 if (purpose == DVIPS || purpose == DVIPDFM)
3193 if (purpose == DVIPS || purpose == DVIPDFM)
3197 if (purpose == DVIPS || purpose == DVIPDFM)
3201 // dvipdfm does not know this
3202 if (purpose == DVIPDFM)
3206 if (purpose == DVIPDFM)
3210 if (purpose == DVIPS || purpose == DVIPDFM)
3214 if (purpose == DVIPS || purpose == DVIPDFM)
3218 if (purpose == DVIPS || purpose == DVIPDFM)
3222 if (purpose == DVIPS || purpose == DVIPDFM)
3226 if (purpose == DVIPS || purpose == DVIPDFM)
3230 if (purpose == DVIPS || purpose == DVIPDFM)
3234 if (purpose == DVIPS || purpose == DVIPDFM)
3238 if (purpose == DVIPS || purpose == DVIPDFM)
3242 if (purpose == DVIPS || purpose == DVIPDFM)
3246 if (purpose == DVIPS || purpose == DVIPDFM)
3250 if (purpose == DVIPS || purpose == DVIPDFM)
3254 if (purpose == DVIPS || purpose == DVIPDFM)
3258 if (purpose == DVIPS || purpose == DVIPDFM)
3262 if (purpose == DVIPS || purpose == DVIPDFM)
3266 if (purpose == DVIPS || purpose == DVIPDFM)
3269 case PAPER_USEXECUTIVE:
3270 // dvipdfm does not know this
3271 if (purpose == DVIPDFM)
3276 case PAPER_USLETTER:
3278 if (purpose == XDVI)
3285 string const BufferParams::dvips_options() const
3289 // If the class loads the geometry package, we do not know which
3290 // paper size is used, since we do not set it (bug 7013).
3291 // Therefore we must not specify any argument here.
3292 // dvips gets the correct paper size via DVI specials in this case
3293 // (if the class uses the geometry package correctly).
3294 if (documentClass().provides("geometry"))
3298 && papersize == PAPER_CUSTOM
3299 && !lyxrc.print_paper_dimension_flag.empty()
3300 && !paperwidth.empty()
3301 && !paperheight.empty()) {
3302 // using a custom papersize
3303 result = lyxrc.print_paper_dimension_flag;
3304 result += ' ' + paperwidth;
3305 result += ',' + paperheight;
3307 string const paper_option = paperSizeName(DVIPS);
3308 if (!paper_option.empty() && (paper_option != "letter" ||
3309 orientation != ORIENTATION_LANDSCAPE)) {
3310 // dvips won't accept -t letter -t landscape.
3311 // In all other cases, include the paper size
3313 result = lyxrc.print_paper_flag;
3314 result += ' ' + paper_option;
3317 if (orientation == ORIENTATION_LANDSCAPE &&
3318 papersize != PAPER_CUSTOM)
3319 result += ' ' + lyxrc.print_landscape_flag;
3324 string const BufferParams::main_font_encoding() const
3326 vector<string> const fencs = font_encodings();
3327 if (fencs.empty()) {
3328 if (ascii_lowercase(language->fontenc(*this)) == "none")
3332 return fencs.back();
3336 vector<string> const BufferParams::font_encodings() const
3338 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3340 vector<string> fontencs;
3342 // "default" means "no explicit font encoding"
3343 if (doc_fontenc != "default") {
3344 if (!doc_fontenc.empty())
3345 // If we have a custom setting, we use only that!
3346 return getVectorFromString(doc_fontenc);
3347 string const lfe = language->fontenc(*this);
3349 && ascii_lowercase(language->fontenc(*this)) != "none") {
3350 vector<string> fencs = getVectorFromString(lfe);
3351 for (auto & fe : fencs) {
3352 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3353 fontencs.push_back(fe);
3362 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3364 // suppress the babel call if there is no BabelName defined
3365 // for the document language in the lib/languages file and if no
3366 // other languages are used (lang_opts is then empty)
3367 if (lang_opts.empty())
3369 // The prefs may require the languages to
3370 // be submitted to babel itself (not the class).
3372 return "\\usepackage[" + lang_opts + "]{babel}";
3373 return "\\usepackage{babel}";
3377 docstring BufferParams::getGraphicsDriver(string const & package) const
3381 if (package == "geometry") {
3382 if (graphics_driver == "dvips"
3383 || graphics_driver == "dvipdfm"
3384 || graphics_driver == "pdftex"
3385 || graphics_driver == "vtex")
3386 result = from_ascii(graphics_driver);
3387 else if (graphics_driver == "dvipdfmx")
3388 result = from_ascii("dvipdfm");
3395 void BufferParams::writeEncodingPreamble(otexstream & os,
3396 LaTeXFeatures & features) const
3398 // With no-TeX fonts we use utf8-plain without encoding package.
3402 if (inputenc == "auto-legacy") {
3403 string const doc_encoding =
3404 language->encoding()->latexName();
3405 Encoding::Package const package =
3406 language->encoding()->package();
3408 // Create list of inputenc options:
3409 set<string> encoding_set;
3410 // luainputenc fails with more than one encoding
3411 if (features.runparams().flavor != Flavor::LuaTeX
3412 && features.runparams().flavor != Flavor::DviLuaTeX)
3413 // list all input encodings used in the document
3414 encoding_set = features.getEncodingSet(doc_encoding);
3416 // The "japanese" babel-language requires the pLaTeX engine
3417 // which conflicts with "inputenc".
3418 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3419 if ((!encoding_set.empty() || package == Encoding::inputenc)
3420 && !features.isRequired("japanese")
3421 && !features.isProvided("inputenc")) {
3422 os << "\\usepackage[";
3423 set<string>::const_iterator it = encoding_set.begin();
3424 set<string>::const_iterator const end = encoding_set.end();
3426 os << from_ascii(*it);
3429 for (; it != end; ++it)
3430 os << ',' << from_ascii(*it);
3431 if (package == Encoding::inputenc) {
3432 if (!encoding_set.empty())
3434 os << from_ascii(doc_encoding);
3436 if (features.runparams().flavor == Flavor::LuaTeX
3437 || features.runparams().flavor == Flavor::DviLuaTeX)
3438 os << "]{luainputenc}\n";
3440 os << "]{inputenc}\n";
3442 } else if (inputenc != "auto-legacy-plain") {
3443 switch (encoding().package()) {
3444 case Encoding::none:
3446 case Encoding::japanese:
3447 if (encoding().iconvName() != "UTF-8"
3448 && !features.runparams().isFullUnicode())
3449 // don't default to [utf8]{inputenc} with TeXLive >= 18
3450 os << "\\ifdefined\\UseRawInputEncoding\n"
3451 << " \\UseRawInputEncoding\\fi\n";
3453 case Encoding::inputenc:
3454 // do not load inputenc if japanese is used
3455 // or if the class provides inputenc
3456 if (features.isRequired("japanese")
3457 || features.isProvided("inputenc"))
3459 os << "\\usepackage[" << from_ascii(encoding().latexName());
3460 if (features.runparams().flavor == Flavor::LuaTeX
3461 || features.runparams().flavor == Flavor::DviLuaTeX)
3462 os << "]{luainputenc}\n";
3464 os << "]{inputenc}\n";
3468 if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3469 // don't default to [utf8]{inputenc} with TeXLive >= 18
3470 os << "\\ifdefined\\UseRawInputEncoding\n";
3471 os << " \\UseRawInputEncoding\\fi\n";
3476 string const BufferParams::parseFontName(string const & name) const
3478 string mangled = name;
3479 size_t const idx = mangled.find('[');
3480 if (idx == string::npos || idx == 0)
3483 return mangled.substr(0, idx - 1);
3487 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3489 if (fontsRoman() == "default" && fontsSans() == "default"
3490 && fontsTypewriter() == "default"
3491 && (fontsMath() == "default" || fontsMath() == "auto"))
3497 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3498 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3499 * Mapping=tex-text option assures TeX ligatures (such as "--")
3500 * are resolved. Note that tt does not use these ligatures.
3502 * -- add more GUI options?
3503 * -- add more fonts (fonts for other scripts)
3504 * -- if there's a way to find out if a font really supports
3505 * OldStyle, enable/disable the widget accordingly.
3507 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3508 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3509 // However, until v.2 (2010/07/11) fontspec only knew
3510 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3511 // was introduced for both XeTeX and LuaTeX (LuaTeX
3512 // didn't understand "Mapping=tex-text", while XeTeX
3513 // understood both. With most recent versions, both
3514 // variants are understood by both engines. However,
3515 // we want to provide support for at least TeXLive 2009
3516 // (for XeTeX; LuaTeX is only supported as of v.2)
3517 // As of 2017/11/03, Babel has its own higher-level
3518 // interface on top of fontspec that is to be used.
3519 bool const babelfonts = features.useBabel()
3520 && features.isAvailable("babel-2017/11/03");
3521 string const texmapping =
3522 (features.runparams().flavor == Flavor::XeTeX) ?
3523 "Mapping=tex-text" : "Ligatures=TeX";
3524 if (fontsRoman() != "default") {
3526 os << "\\babelfont{rm}[";
3528 os << "\\setmainfont[";
3529 if (!font_roman_opts.empty())
3530 os << font_roman_opts << ',';
3532 if (fonts_roman_osf)
3533 os << ",Numbers=OldStyle";
3534 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3536 if (fontsSans() != "default") {
3537 string const sans = parseFontName(fontsSans());
3538 if (fontsSansScale() != 100) {
3540 os << "\\babelfont{sf}";
3542 os << "\\setsansfont";
3544 << float(fontsSansScale()) / 100 << ',';
3546 os << "Numbers=OldStyle,";
3547 if (!font_sans_opts.empty())
3548 os << font_sans_opts << ',';
3549 os << texmapping << "]{"
3553 os << "\\babelfont{sf}[";
3555 os << "\\setsansfont[";
3557 os << "Numbers=OldStyle,";
3558 if (!font_sans_opts.empty())
3559 os << font_sans_opts << ',';
3560 os << texmapping << "]{"
3564 if (fontsTypewriter() != "default") {
3565 string const mono = parseFontName(fontsTypewriter());
3566 if (fontsTypewriterScale() != 100) {
3568 os << "\\babelfont{tt}";
3570 os << "\\setmonofont";
3572 << float(fontsTypewriterScale()) / 100;
3573 if (fonts_typewriter_osf)
3574 os << ",Numbers=OldStyle";
3575 if (!font_typewriter_opts.empty())
3576 os << ',' << font_typewriter_opts;
3581 os << "\\babelfont{tt}";
3583 os << "\\setmonofont";
3584 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3586 if (fonts_typewriter_osf)
3587 os << "Numbers=OldStyle";
3588 if (!font_typewriter_opts.empty()) {
3589 if (fonts_typewriter_osf)
3591 os << font_typewriter_opts;
3595 os << '{' << mono << "}\n";
3602 bool const ot1 = (features.runparams().main_fontenc == "default"
3603 || features.runparams().main_fontenc == "OT1");
3604 bool const dryrun = features.runparams().dryrun;
3605 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3606 bool const nomath = (fontsMath() != "auto");
3609 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3610 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3611 nomath, font_roman_opts);
3614 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3615 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3616 nomath, font_sans_opts, fontsSansScale());
3618 // MONOSPACED/TYPEWRITER
3619 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3620 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3621 nomath, font_typewriter_opts, fontsTypewriterScale());
3624 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3625 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3632 Encoding const & BufferParams::encoding() const
3634 // Main encoding for LaTeX output.
3636 return *(encodings.fromLyXName("utf8-plain"));
3637 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3638 return *language->encoding();
3639 if (inputenc == "utf8" && language->lang() == "japanese")
3640 return *(encodings.fromLyXName("utf8-platex"));
3641 Encoding const * const enc = encodings.fromLyXName(inputenc);
3644 LYXERR0("Unknown inputenc value `" << inputenc
3645 << "'. Using `auto' instead.");
3646 return *language->encoding();
3650 string const & BufferParams::defaultBiblioStyle() const
3652 if (!biblio_style.empty())
3653 return biblio_style;
3655 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3656 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3657 if (cit != bs.end())
3660 return empty_string();
3664 bool BufferParams::fullAuthorList() const
3666 return documentClass().fullAuthorList();
3670 string BufferParams::getCiteAlias(string const & s) const
3672 vector<string> commands =
3673 documentClass().citeCommands(citeEngineType());
3674 // If it is a real command, don't treat it as an alias
3675 if (find(commands.begin(), commands.end(), s) != commands.end())
3677 map<string,string> aliases = documentClass().citeCommandAliases();
3678 if (aliases.find(s) != aliases.end())
3684 vector<string> BufferParams::citeCommands() const
3686 static CitationStyle const default_style;
3687 vector<string> commands =
3688 documentClass().citeCommands(citeEngineType());
3689 if (commands.empty())
3690 commands.push_back(default_style.name);
3695 vector<CitationStyle> BufferParams::citeStyles() const
3697 static CitationStyle const default_style;
3698 vector<CitationStyle> styles =
3699 documentClass().citeStyles(citeEngineType());
3701 styles.push_back(default_style);
3706 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3708 // split from options
3710 split(cmd, command_in, ' ');
3712 // Look if the requested command is available. If so, use that.
3713 for (auto const & alts : lyxrc.bibtex_alternatives) {
3714 string command_prov;
3715 split(alts, command_prov, ' ');
3716 if (command_in == command_prov)
3720 // If not, find the most suitable fallback for the current cite framework,
3721 // and warn. Note that we omit options in any such case.
3723 if (useBiblatex()) {
3724 // For Biblatex, we prefer biber (also for Japanese)
3725 // and try to fall back to bibtex8
3726 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3728 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3729 fallback = "bibtex8";
3731 // For classic BibTeX and as last resort for biblatex, try bibtex
3732 if (fallback.empty()) {
3733 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3734 fallback = "bibtex";
3740 if (fallback.empty()) {
3741 frontend::Alert::warning(
3742 _("No bibliography processor found!"),
3744 _("The bibliography processor requested by this document "
3745 "(%1$s) is not available and no appropriate "
3746 "alternative has been found. "
3747 "No bibliography and references will be generated.\n"
3748 "Please fix your installation!"),
3751 frontend::Alert::warning(
3752 _("Requested bibliography processor not found!"),
3754 _("The bibliography processor requested by this document "
3755 "(%1$s) is not available. "
3756 "As a fallback, '%2$s' will be used, options are omitted. "
3757 "This might result in errors or unwanted changes in "
3758 "the bibliography. Please check carefully!\n"
3759 "It is suggested to install the missing processor."),
3760 from_utf8(cmd), from_utf8(fallback)));
3766 string const BufferParams::bibtexCommand(bool const warn) const
3768 // Return document-specific setting if available
3769 if (bibtex_command != "default")
3770 return getBibtexCommand(bibtex_command, warn);
3772 // If we have "default" in document settings, consult the prefs
3773 // 1. Japanese (uses a specific processor)
3774 if (encoding().package() == Encoding::japanese) {
3775 if (lyxrc.jbibtex_command != "automatic")
3776 // Return the specified program, if "automatic" is not set
3777 return lyxrc.jbibtex_command;
3778 else if (!useBiblatex()) {
3779 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3780 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3782 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3787 // 2. All other languages
3788 else if (lyxrc.bibtex_command != "automatic")
3789 // Return the specified program, if "automatic" is not set
3790 return getBibtexCommand(lyxrc.bibtex_command, warn);
3792 // 3. Automatic: find the most suitable for the current cite framework
3793 if (useBiblatex()) {
3794 // For Biblatex, we prefer biber (also for Japanese)
3795 // and fall back to bibtex8 and, as last resort, bibtex
3796 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3798 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3805 bool BufferParams::useBiblatex() const
3807 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3811 void BufferParams::invalidateConverterCache() const
3813 pimpl_->isExportCacheValid = false;
3814 pimpl_->isViewCacheValid = false;
3818 // We shouldn't need to reset the params here, since anything
3819 // we need will be recopied.
3820 void BufferParams::copyForAdvFR(const BufferParams & bp)
3822 string const & lang = bp.language->lang();
3824 layout_modules_ = bp.layout_modules_;
3825 string const & doc_class = bp.documentClass().name();
3826 setBaseClass(doc_class);
3830 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3832 bib_encodings[file] = enc;
3836 string const BufferParams::bibFileEncoding(string const & file) const
3838 if (bib_encodings.find(file) == bib_encodings.end())
3840 return bib_encodings.find(file)->second;