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)));
373 // set comparison author
374 authorlist.record(Author(from_utf8("Document Comparison"),
375 docstring(), docstring()));
380 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
383 return new BufferParams::Impl(*ptr);
387 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
393 BufferParams::BufferParams()
396 setBaseClass(defaultBaseclass());
397 cite_engine_ = "basic";
398 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
400 paragraph_separation = ParagraphIndentSeparation;
401 is_math_indent = false;
402 math_numbering_side = DEFAULT;
403 quotes_style = QuoteStyle::English;
404 dynamic_quotes = false;
405 fontsize = "default";
408 papersize = PAPER_DEFAULT;
409 orientation = ORIENTATION_PORTRAIT;
410 use_geometry = false;
411 biblio_style = string();
412 use_bibtopic = false;
415 save_transient_properties = true;
416 track_changes = false;
417 output_changes = false;
419 postpone_fragile_content = true;
420 use_default_options = true;
421 maintain_unincluded_children = CM_None;
424 language = default_language;
426 fonts_roman[0] = "default";
427 fonts_roman[1] = "default";
428 fonts_sans[0] = "default";
429 fonts_sans[1] = "default";
430 fonts_typewriter[0] = "default";
431 fonts_typewriter[1] = "default";
432 fonts_math[0] = "auto";
433 fonts_math[1] = "auto";
434 fonts_default_family = "default";
435 useNonTeXFonts = false;
436 use_microtype = false;
437 use_dash_ligatures = true;
438 fonts_expert_sc = false;
439 fonts_roman_osf = false;
440 fonts_sans_osf = false;
441 fonts_typewriter_osf = false;
442 fonts_sans_scale[0] = 100;
443 fonts_sans_scale[1] = 100;
444 fonts_typewriter_scale[0] = 100;
445 fonts_typewriter_scale[1] = 100;
447 lang_package = "default";
448 graphics_driver = "default";
449 default_output_format = "default";
450 bibtex_command = "default";
451 index_command = "default";
454 listings_params = string();
455 pagestyle = "default";
456 tablestyle = "default";
457 float_alignment = "class";
458 float_placement = "class";
459 suppress_date = false;
460 justification = true;
461 // no color is the default (white)
462 backgroundcolor = lyx::rgbFromHexName("#ffffff");
463 isbackgroundcolor = false;
464 // no color is the default (black)
465 fontcolor = lyx::rgbFromHexName("#000000");
467 // light gray is the default font color for greyed-out notes
468 notefontcolor = lyx::rgbFromHexName("#cccccc");
469 isnotefontcolor = false;
470 boxbgcolor = lyx::rgbFromHexName("#ff0000");
471 isboxbgcolor = false;
472 compressed = lyxrc.save_compressed;
473 for (int iter = 0; iter < 4; ++iter) {
474 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
475 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
478 indiceslist().addDefault(B_("Index"));
479 html_be_strict = false;
480 html_math_output = MathML;
481 html_math_img_scale = 1.0;
482 html_css_as_file = false;
483 docbook_table_output = HTMLTable;
484 docbook_mathml_prefix = MPrefix;
485 display_pixel_ratio = 1.0;
487 shell_escape = false;
493 // map current author
494 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
498 docstring BufferParams::B_(string const & l10n) const
500 LASSERT(language, return from_utf8(l10n));
501 return getMessages(language->code()).get(l10n);
505 BufferParams::Package BufferParams::use_package(std::string const & p) const
507 PackageMap::const_iterator it = use_packages.find(p);
508 if (it == use_packages.end())
514 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
520 map<string, string> const & BufferParams::auto_packages()
522 static map<string, string> packages;
523 if (packages.empty()) {
524 // We could have a race condition here that two threads
525 // discover an empty map at the same time and want to fill
526 // it, but that is no problem, since the same contents is
527 // filled in twice then. Having the locker inside the
528 // packages.empty() condition has the advantage that we
529 // don't need the mutex overhead for simple reading.
531 Mutex::Locker locker(&mutex);
532 // adding a package here implies a file format change!
533 packages["amsmath"] =
534 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
535 packages["amssymb"] =
536 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
538 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
540 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
541 packages["mathdots"] =
542 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
543 packages["mathtools"] =
544 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
546 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
547 packages["stackrel"] =
548 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
549 packages["stmaryrd"] =
550 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");
551 packages["undertilde"] =
552 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
558 bool BufferParams::useBibtopic() const
562 return (use_bibtopic || (!multibib.empty() && multibib != "child"));
566 AuthorList & BufferParams::authors()
568 return pimpl_->authorlist;
572 AuthorList const & BufferParams::authors() const
574 return pimpl_->authorlist;
578 void BufferParams::addAuthor(Author const & a)
580 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
584 BranchList & BufferParams::branchlist()
586 return pimpl_->branchlist;
590 BranchList const & BufferParams::branchlist() const
592 return pimpl_->branchlist;
596 IndicesList & BufferParams::indiceslist()
598 return pimpl_->indiceslist;
602 IndicesList const & BufferParams::indiceslist() const
604 return pimpl_->indiceslist;
608 WordLangTable & BufferParams::spellignore()
610 return pimpl_->spellignore;
614 WordLangTable const & BufferParams::spellignore() const
616 return pimpl_->spellignore;
620 bool BufferParams::spellignored(WordLangTuple const & wl) const
622 bool has_item = false;
623 vector<WordLangTuple> il = spellignore();
624 vector<WordLangTuple>::const_iterator it = il.begin();
625 for (; it != il.end(); ++it) {
626 if (it->lang()->code() != wl.lang()->code())
628 if (it->word() == wl.word()) {
637 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
639 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
640 return pimpl_->temp_bullets[index];
644 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
646 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
647 return pimpl_->temp_bullets[index];
651 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
653 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
654 return pimpl_->user_defined_bullets[index];
658 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
660 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
661 return pimpl_->user_defined_bullets[index];
665 Spacing & BufferParams::spacing()
667 return pimpl_->spacing;
671 Spacing const & BufferParams::spacing() const
673 return pimpl_->spacing;
677 PDFOptions & BufferParams::pdfoptions()
679 return pimpl_->pdfoptions;
683 PDFOptions const & BufferParams::pdfoptions() const
685 return pimpl_->pdfoptions;
689 Length const & BufferParams::getMathIndent() const
691 return pimpl_->mathindent;
695 void BufferParams::setMathIndent(Length const & indent)
697 pimpl_->mathindent = indent;
701 Length const & BufferParams::getParIndent() const
703 return pimpl_->parindent;
707 void BufferParams::setParIndent(Length const & indent)
709 pimpl_->parindent = indent;
713 VSpace const & BufferParams::getDefSkip() const
715 return pimpl_->defskip;
719 void BufferParams::setDefSkip(VSpace const & vs)
721 // DEFSKIP will cause an infinite loop
722 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
723 pimpl_->defskip = vs;
727 BufferParams::MathNumber BufferParams::getMathNumber() const
729 if (math_numbering_side != DEFAULT)
730 return math_numbering_side;
731 // FIXME: do not hardcode language here
732 else if (language->lang() == "arabic_arabi"
733 || documentClass().provides("leqno"))
740 string BufferParams::readToken(Lexer & lex, string const & token,
741 FileName const & filename)
744 FileName const & filepath = filename.onlyPath();
746 if (token == "\\textclass") {
748 string const classname = lex.getString();
749 // if there exists a local layout file, ignore the system one
750 // NOTE: in this case, the textclass (.cls file) is assumed to
753 LayoutFileList & bcl = LayoutFileList::get();
754 if (!filepath.empty()) {
755 // If classname is an absolute path, the document is
756 // using a local layout file which could not be accessed
757 // by a relative path. In this case the path is correct
758 // even if the document was moved to a different
759 // location. However, we will have a problem if the
760 // document was generated on a different platform.
761 bool isabsolute = FileName::isAbsolute(classname);
762 string const classpath = onlyPath(classname);
763 string const path = isabsolute ? classpath
764 : FileName(addPath(filepath.absFileName(),
765 classpath)).realPath();
766 string const oldpath = isabsolute ? string()
767 : FileName(addPath(origin, classpath)).realPath();
768 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
770 // that returns non-empty if a "local" layout file is found.
772 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
773 from_utf8(filepath.absFileName())));
776 setBaseClass(onlyFileName(tcp));
778 setBaseClass(onlyFileName(classname));
779 // We assume that a tex class exists for local or unknown
780 // layouts so this warning, will only be given for system layouts.
781 if (!baseClass()->isTeXClassAvailable()) {
782 docstring const desc =
783 translateIfPossible(from_utf8(baseClass()->description()));
784 docstring const prereqs =
785 from_utf8(baseClass()->prerequisites());
786 docstring const msg =
787 bformat(_("The selected document class\n"
789 "requires external files that are not available.\n"
790 "The document class can still be used, but the\n"
791 "document cannot be compiled until the following\n"
792 "prerequisites are installed:\n"
794 "See section 3.1.2.2 (Class Availability) of the\n"
795 "User's Guide for more information."), desc, prereqs);
796 frontend::Alert::warning(_("Document class not available"),
799 } else if (token == "\\save_transient_properties") {
800 lex >> save_transient_properties;
801 } else if (token == "\\origin") {
803 origin = lex.getString();
804 string const sysdirprefix = "/systemlyxdir/";
805 if (prefixIs(origin, sysdirprefix)) {
807 if (inSystemDir(filepath, docsys))
808 origin.replace(0, sysdirprefix.length() - 1, docsys);
810 origin.replace(0, sysdirprefix.length() - 1,
811 package().system_support().absFileName());
813 } else if (token == "\\begin_metadata") {
814 readDocumentMetadata(lex);
815 } else if (token == "\\begin_preamble") {
817 } else if (token == "\\begin_local_layout") {
818 readLocalLayout(lex, false);
819 } else if (token == "\\begin_forced_local_layout") {
820 readLocalLayout(lex, true);
821 } else if (token == "\\begin_modules") {
823 } else if (token == "\\begin_removed_modules") {
824 readRemovedModules(lex);
825 } else if (token == "\\begin_includeonly") {
826 readIncludeonly(lex);
827 } else if (token == "\\maintain_unincluded_children") {
831 maintain_unincluded_children = CM_None;
832 else if (tmp == "mostly")
833 maintain_unincluded_children = CM_Mostly;
834 else if (tmp == "strict")
835 maintain_unincluded_children = CM_Strict;
836 } else if (token == "\\options") {
838 options = lex.getString();
839 } else if (token == "\\use_default_options") {
840 lex >> use_default_options;
841 } else if (token == "\\master") {
843 master = lex.getString();
844 if (!filepath.empty() && FileName::isAbsolute(origin)) {
845 bool const isabs = FileName::isAbsolute(master);
846 FileName const abspath(isabs ? master : origin + master);
847 bool const moved = filepath != FileName(origin);
848 if (moved && abspath.exists()) {
849 docstring const path = isabs
851 : from_utf8(abspath.realPath());
852 docstring const refpath =
853 from_utf8(filepath.absFileName());
854 master = to_utf8(makeRelPath(path, refpath));
857 } else if (token == "\\suppress_date") {
858 lex >> suppress_date;
859 } else if (token == "\\justification") {
860 lex >> justification;
861 } else if (token == "\\language") {
863 } else if (token == "\\language_package") {
865 lang_package = lex.getString();
866 } else if (token == "\\inputencoding") {
868 } else if (token == "\\graphics") {
869 readGraphicsDriver(lex);
870 } else if (token == "\\default_output_format") {
871 lex >> default_output_format;
872 } else if (token == "\\bibtex_command") {
874 bibtex_command = lex.getString();
875 } else if (token == "\\index_command") {
877 index_command = lex.getString();
878 } else if (token == "\\fontencoding") {
880 fontenc = lex.getString();
881 } else if (token == "\\font_roman") {
882 lex >> fonts_roman[0];
883 lex >> fonts_roman[1];
884 } else if (token == "\\font_sans") {
885 lex >> fonts_sans[0];
886 lex >> fonts_sans[1];
887 } else if (token == "\\font_typewriter") {
888 lex >> fonts_typewriter[0];
889 lex >> fonts_typewriter[1];
890 } else if (token == "\\font_math") {
891 lex >> fonts_math[0];
892 lex >> fonts_math[1];
893 } else if (token == "\\font_default_family") {
894 lex >> fonts_default_family;
895 } else if (token == "\\use_non_tex_fonts") {
896 lex >> useNonTeXFonts;
897 } else if (token == "\\font_sc") {
898 lex >> fonts_expert_sc;
899 } else if (token == "\\font_roman_osf") {
900 lex >> fonts_roman_osf;
901 } else if (token == "\\font_sans_osf") {
902 lex >> fonts_sans_osf;
903 } else if (token == "\\font_typewriter_osf") {
904 lex >> fonts_typewriter_osf;
905 } else if (token == "\\font_roman_opts") {
906 lex >> font_roman_opts;
907 } else if (token == "\\font_sf_scale") {
908 lex >> fonts_sans_scale[0];
909 lex >> fonts_sans_scale[1];
910 } else if (token == "\\font_sans_opts") {
911 lex >> font_sans_opts;
912 } else if (token == "\\font_tt_scale") {
913 lex >> fonts_typewriter_scale[0];
914 lex >> fonts_typewriter_scale[1];
915 } else if (token == "\\font_typewriter_opts") {
916 lex >> font_typewriter_opts;
917 } else if (token == "\\font_cjk") {
919 } else if (token == "\\use_microtype") {
920 lex >> use_microtype;
921 } else if (token == "\\use_dash_ligatures") {
922 lex >> use_dash_ligatures;
923 } else if (token == "\\paragraph_separation") {
926 paragraph_separation = parseptranslator().find(parsep);
927 } else if (token == "\\paragraph_indentation") {
929 string parindent = lex.getString();
930 if (parindent == "default")
931 pimpl_->parindent = Length();
933 pimpl_->parindent = Length(parindent);
934 } else if (token == "\\defskip") {
936 string const defskip = lex.getString();
937 pimpl_->defskip = VSpace(defskip);
938 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
940 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
941 } else if (token == "\\is_math_indent") {
942 lex >> is_math_indent;
943 } else if (token == "\\math_indentation") {
945 string mathindent = lex.getString();
946 if (mathindent == "default")
947 pimpl_->mathindent = Length();
949 pimpl_->mathindent = Length(mathindent);
950 } else if (token == "\\math_numbering_side") {
954 math_numbering_side = LEFT;
955 else if (tmp == "right")
956 math_numbering_side = RIGHT;
958 math_numbering_side = DEFAULT;
959 } else if (token == "\\quotes_style") {
962 quotes_style = quotesstyletranslator().find(qstyle);
963 } else if (token == "\\dynamic_quotes") {
964 lex >> dynamic_quotes;
965 } else if (token == "\\papersize") {
968 papersize = papersizetranslator().find(ppsize);
969 } else if (token == "\\use_geometry") {
971 } else if (token == "\\use_package") {
976 use_package(package, packagetranslator().find(use));
977 } else if (token == "\\cite_engine") {
979 cite_engine_ = lex.getString();
980 } else if (token == "\\cite_engine_type") {
983 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
984 } else if (token == "\\biblio_style") {
986 biblio_style = lex.getString();
987 } else if (token == "\\biblio_options") {
989 biblio_opts = trim(lex.getString());
990 } else if (token == "\\biblatex_bibstyle") {
992 biblatex_bibstyle = trim(lex.getString());
993 } else if (token == "\\biblatex_citestyle") {
995 biblatex_citestyle = trim(lex.getString());
996 } else if (token == "\\use_bibtopic") {
998 } else if (token == "\\multibib") {
1000 } else if (token == "\\use_indices") {
1002 } else if (token == "\\tracking_changes") {
1003 lex >> track_changes;
1004 } else if (token == "\\output_changes") {
1005 lex >> output_changes;
1006 } else if (token == "\\change_bars") {
1008 } else if (token == "\\postpone_fragile_content") {
1009 lex >> postpone_fragile_content;
1010 } else if (token == "\\branch") {
1012 docstring branch = lex.getDocString();
1013 branchlist().add(branch);
1016 string const tok = lex.getString();
1017 if (tok == "\\end_branch")
1019 Branch * branch_ptr = branchlist().find(branch);
1020 if (tok == "\\selected") {
1023 branch_ptr->setSelected(lex.getInteger());
1025 if (tok == "\\filename_suffix") {
1028 branch_ptr->setFileNameSuffix(lex.getInteger());
1030 if (tok == "\\color") {
1032 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1033 string const lmcolor = colors.front();
1035 if (colors.size() > 1)
1036 dmcolor = colors.back();
1038 branch_ptr->setColors(lmcolor, dmcolor);
1041 } else if (token == "\\index") {
1043 docstring index = lex.getDocString();
1045 indiceslist().add(index);
1048 string const tok = lex.getString();
1049 if (tok == "\\end_index")
1051 Index * index_ptr = indiceslist().find(index);
1052 if (tok == "\\shortcut") {
1054 shortcut = lex.getDocString();
1056 index_ptr->setShortcut(shortcut);
1058 if (tok == "\\color") {
1060 string color = lex.getString();
1062 index_ptr->setColor(color);
1063 // Update also the Color table:
1064 if (color == "none")
1065 color = lcolor.getX11HexName(Color_background);
1067 if (!shortcut.empty())
1068 lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1071 } else if (token == "\\spellchecker_ignore") {
1073 docstring wl = lex.getDocString();
1075 docstring word = split(wl, language, ' ');
1076 Language const * lang = languages.getLanguage(to_ascii(language));
1078 spellignore().push_back(WordLangTuple(word, lang));
1079 } else if (token == "\\author") {
1081 istringstream ss(lex.getString());
1085 } else if (token == "\\paperorientation") {
1088 orientation = paperorientationtranslator().find(orient);
1089 } else if (token == "\\backgroundcolor") {
1091 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1092 isbackgroundcolor = true;
1093 } else if (token == "\\fontcolor") {
1095 fontcolor = lyx::rgbFromHexName(lex.getString());
1097 } else if (token == "\\notefontcolor") {
1099 string color = lex.getString();
1100 notefontcolor = lyx::rgbFromHexName(color);
1101 lcolor.setColor("notefontcolor", color);
1102 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1103 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1104 // set a local name for the painter
1105 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1106 isnotefontcolor = true;
1107 } else if (token == "\\boxbgcolor") {
1109 string color = lex.getString();
1110 boxbgcolor = lyx::rgbFromHexName(color);
1111 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1112 isboxbgcolor = true;
1113 } else if (token == "\\paperwidth") {
1115 } else if (token == "\\paperheight") {
1117 } else if (token == "\\leftmargin") {
1119 } else if (token == "\\topmargin") {
1121 } else if (token == "\\rightmargin") {
1123 } else if (token == "\\bottommargin") {
1124 lex >> bottommargin;
1125 } else if (token == "\\headheight") {
1127 } else if (token == "\\headsep") {
1129 } else if (token == "\\footskip") {
1131 } else if (token == "\\columnsep") {
1133 } else if (token == "\\paperfontsize") {
1135 } else if (token == "\\papercolumns") {
1137 } else if (token == "\\listings_params") {
1140 listings_params = InsetListingsParams(par).params();
1141 } else if (token == "\\papersides") {
1144 sides = sidestranslator().find(psides);
1145 } else if (token == "\\paperpagestyle") {
1147 } else if (token == "\\tablestyle") {
1149 } else if (token == "\\bullet") {
1151 } else if (token == "\\bulletLaTeX") {
1152 readBulletsLaTeX(lex);
1153 } else if (token == "\\secnumdepth") {
1155 } else if (token == "\\tocdepth") {
1157 } else if (token == "\\spacing") {
1161 if (nspacing == "other") {
1164 spacing().set(spacetranslator().find(nspacing), tmp_val);
1165 } else if (token == "\\float_placement") {
1166 lex >> float_placement;
1167 } else if (token == "\\float_alignment") {
1168 lex >> float_alignment;
1170 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1171 string toktmp = pdfoptions().readToken(lex, token);
1172 if (!toktmp.empty()) {
1173 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1177 } else if (token == "\\html_math_output") {
1180 html_math_output = static_cast<MathOutput>(temp);
1181 } else if (token == "\\html_be_strict") {
1182 lex >> html_be_strict;
1183 } else if (token == "\\html_css_as_file") {
1184 lex >> html_css_as_file;
1185 } else if (token == "\\html_math_img_scale") {
1186 lex >> html_math_img_scale;
1187 } else if (token == "\\html_latex_start") {
1189 html_latex_start = lex.getString();
1190 } else if (token == "\\html_latex_end") {
1192 html_latex_end = lex.getString();
1193 } else if (token == "\\docbook_table_output") {
1196 docbook_table_output = static_cast<TableOutput>(temp);
1197 } else if (token == "\\docbook_mathml_prefix") {
1200 docbook_mathml_prefix = static_cast<MathMLNameSpacePrefix>(temp);
1201 } else if (token == "\\output_sync") {
1203 } else if (token == "\\output_sync_macro") {
1204 lex >> output_sync_macro;
1205 } else if (token == "\\use_refstyle") {
1206 lex >> use_refstyle;
1207 } else if (token == "\\use_minted") {
1209 } else if (token == "\\use_lineno") {
1211 } else if (token == "\\lineno_options") {
1213 lineno_opts = trim(lex.getString());
1215 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1225 // Quote argument if it contains spaces
1226 string quoteIfNeeded(string const & str) {
1227 if (contains(str, ' '))
1228 return "\"" + str + "\"";
1234 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1236 // The top of the file is written by the buffer.
1237 // Prints out the buffer info into the .lyx file given by file
1239 os << "\\save_transient_properties "
1240 << convert<string>(save_transient_properties) << '\n';
1242 // the document directory (must end with a path separator)
1243 // realPath() is used to resolve symlinks, while addPath(..., "")
1244 // ensures a trailing path separator.
1246 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1247 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1248 : addPath(package().system_support().realPath(), "");
1249 string const relpath =
1250 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1251 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1252 filepath = addPath("/systemlyxdir", relpath);
1253 else if (!save_transient_properties || !lyxrc.save_origin)
1254 filepath = "unavailable";
1255 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1258 os << "\\textclass "
1259 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1260 baseClass()->name()), "layout"))
1263 // then document metadata
1264 if (!document_metadata.empty()) {
1265 // remove '\n' from the end of document_metadata
1266 docstring const tmpmd = rtrim(document_metadata, "\n");
1267 os << "\\begin_metadata\n"
1269 << "\n\\end_metadata\n";
1272 // then the preamble
1273 if (!preamble.empty()) {
1274 // remove '\n' from the end of preamble
1275 docstring const tmppreamble = rtrim(preamble, "\n");
1276 os << "\\begin_preamble\n"
1277 << to_utf8(tmppreamble)
1278 << "\n\\end_preamble\n";
1282 if (!options.empty()) {
1283 os << "\\options " << options << '\n';
1286 // use the class options defined in the layout?
1287 os << "\\use_default_options "
1288 << convert<string>(use_default_options) << "\n";
1290 // the master document
1291 if (!master.empty()) {
1292 os << "\\master " << master << '\n';
1296 if (!removed_modules_.empty()) {
1297 os << "\\begin_removed_modules" << '\n';
1298 for (auto const & mod : removed_modules_)
1300 os << "\\end_removed_modules" << '\n';
1304 if (!layout_modules_.empty()) {
1305 os << "\\begin_modules" << '\n';
1306 for (auto const & mod : layout_modules_)
1308 os << "\\end_modules" << '\n';
1312 if (!included_children_.empty()) {
1313 os << "\\begin_includeonly" << '\n';
1314 for (auto const & c : included_children_)
1316 os << "\\end_includeonly" << '\n';
1319 switch (maintain_unincluded_children) {
1330 os << "\\maintain_unincluded_children " << muc << '\n';
1332 // local layout information
1333 docstring const local_layout = getLocalLayout(false);
1334 if (!local_layout.empty()) {
1335 // remove '\n' from the end
1336 docstring const tmplocal = rtrim(local_layout, "\n");
1337 os << "\\begin_local_layout\n"
1338 << to_utf8(tmplocal)
1339 << "\n\\end_local_layout\n";
1341 docstring const forced_local_layout = getLocalLayout(true);
1342 if (!forced_local_layout.empty()) {
1343 // remove '\n' from the end
1344 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1345 os << "\\begin_forced_local_layout\n"
1346 << to_utf8(tmplocal)
1347 << "\n\\end_forced_local_layout\n";
1350 // then the text parameters
1351 if (language != ignore_language)
1352 os << "\\language " << language->lang() << '\n';
1353 os << "\\language_package " << lang_package
1354 << "\n\\inputencoding " << inputenc
1355 << "\n\\fontencoding " << fontenc
1356 << "\n\\font_roman \"" << fonts_roman[0]
1357 << "\" \"" << fonts_roman[1] << '"'
1358 << "\n\\font_sans \"" << fonts_sans[0]
1359 << "\" \"" << fonts_sans[1] << '"'
1360 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1361 << "\" \"" << fonts_typewriter[1] << '"'
1362 << "\n\\font_math \"" << fonts_math[0]
1363 << "\" \"" << fonts_math[1] << '"'
1364 << "\n\\font_default_family " << fonts_default_family
1365 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1366 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1367 << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1368 << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1369 << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1370 if (!font_roman_opts.empty())
1371 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1372 os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1373 << ' ' << fonts_sans_scale[1];
1374 if (!font_sans_opts.empty())
1375 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1376 os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1377 << ' ' << fonts_typewriter_scale[1];
1378 if (!font_typewriter_opts.empty())
1379 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1381 if (!fonts_cjk.empty())
1382 os << "\\font_cjk " << fonts_cjk << '\n';
1383 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1384 os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1385 os << "\\graphics " << graphics_driver << '\n';
1386 os << "\\default_output_format " << default_output_format << '\n';
1387 os << "\\output_sync " << output_sync << '\n';
1388 if (!output_sync_macro.empty())
1389 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1390 os << "\\bibtex_command " << bibtex_command << '\n';
1391 os << "\\index_command " << index_command << '\n';
1393 if (!float_placement.empty())
1394 os << "\\float_placement " << float_placement << '\n';
1395 if (!float_alignment.empty())
1396 os << "\\float_alignment " << float_alignment << '\n';
1397 os << "\\paperfontsize " << fontsize << '\n';
1399 spacing().writeFile(os);
1400 pdfoptions().writeFile(os);
1402 os << "\\papersize " << string_papersize[papersize]
1403 << "\n\\use_geometry " << convert<string>(use_geometry);
1404 map<string, string> const & packages = auto_packages();
1405 for (auto const & pack : packages)
1406 os << "\n\\use_package " << pack.first << ' '
1407 << use_package(pack.first);
1409 os << "\n\\cite_engine ";
1411 if (!cite_engine_.empty())
1416 os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1418 if (!biblio_style.empty())
1419 os << "\n\\biblio_style " << biblio_style;
1420 if (!biblio_opts.empty())
1421 os << "\n\\biblio_options " << biblio_opts;
1422 if (!biblatex_bibstyle.empty())
1423 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1424 if (!biblatex_citestyle.empty())
1425 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1426 if (!multibib.empty())
1427 os << "\n\\multibib " << multibib;
1429 os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1430 << "\n\\use_indices " << convert<string>(use_indices)
1431 << "\n\\paperorientation " << string_orientation[orientation]
1432 << "\n\\suppress_date " << convert<string>(suppress_date)
1433 << "\n\\justification " << convert<string>(justification)
1434 << "\n\\use_refstyle " << use_refstyle
1435 << "\n\\use_minted " << use_minted
1436 << "\n\\use_lineno " << use_lineno
1439 if (!lineno_opts.empty())
1440 os << "\\lineno_options " << lineno_opts << '\n';
1442 if (isbackgroundcolor)
1443 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1445 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1446 if (isnotefontcolor)
1447 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1449 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1451 for (auto const & br : branchlist()) {
1452 os << "\\branch " << to_utf8(br.branch())
1453 << "\n\\selected " << br.isSelected()
1454 << "\n\\filename_suffix " << br.hasFileNameSuffix()
1455 << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1460 for (auto const & id : indiceslist()) {
1461 os << "\\index " << to_utf8(id.index())
1462 << "\n\\shortcut " << to_utf8(id.shortcut())
1463 << "\n\\color " << lyx::X11hexname(id.color())
1468 for (auto const & si : spellignore()) {
1469 os << "\\spellchecker_ignore " << si.lang()->lang()
1470 << " " << to_utf8(si.word())
1474 if (!paperwidth.empty())
1475 os << "\\paperwidth "
1476 << VSpace(paperwidth).asLyXCommand() << '\n';
1477 if (!paperheight.empty())
1478 os << "\\paperheight "
1479 << VSpace(paperheight).asLyXCommand() << '\n';
1480 if (!leftmargin.empty())
1481 os << "\\leftmargin "
1482 << VSpace(leftmargin).asLyXCommand() << '\n';
1483 if (!topmargin.empty())
1484 os << "\\topmargin "
1485 << VSpace(topmargin).asLyXCommand() << '\n';
1486 if (!rightmargin.empty())
1487 os << "\\rightmargin "
1488 << VSpace(rightmargin).asLyXCommand() << '\n';
1489 if (!bottommargin.empty())
1490 os << "\\bottommargin "
1491 << VSpace(bottommargin).asLyXCommand() << '\n';
1492 if (!headheight.empty())
1493 os << "\\headheight "
1494 << VSpace(headheight).asLyXCommand() << '\n';
1495 if (!headsep.empty())
1497 << VSpace(headsep).asLyXCommand() << '\n';
1498 if (!footskip.empty())
1500 << VSpace(footskip).asLyXCommand() << '\n';
1501 if (!columnsep.empty())
1502 os << "\\columnsep "
1503 << VSpace(columnsep).asLyXCommand() << '\n';
1504 os << "\\secnumdepth " << secnumdepth
1505 << "\n\\tocdepth " << tocdepth
1506 << "\n\\paragraph_separation "
1507 << string_paragraph_separation[paragraph_separation];
1508 if (!paragraph_separation)
1509 os << "\n\\paragraph_indentation "
1510 << (getParIndent().empty() ? "default" : getParIndent().asString());
1512 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1513 os << "\n\\is_math_indent " << is_math_indent;
1515 os << "\n\\math_indentation "
1516 << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1517 os << "\n\\math_numbering_side ";
1518 switch(math_numbering_side) {
1528 os << "\n\\quotes_style "
1529 << string_quotes_style[static_cast<int>(quotes_style)]
1530 << "\n\\dynamic_quotes " << dynamic_quotes
1531 << "\n\\papercolumns " << columns
1532 << "\n\\papersides " << sides
1533 << "\n\\paperpagestyle " << pagestyle
1534 << "\n\\tablestyle " << tablestyle << '\n';
1535 if (!listings_params.empty())
1536 os << "\\listings_params \"" <<
1537 InsetListingsParams(listings_params).encodedString() << "\"\n";
1538 for (int i = 0; i < 4; ++i) {
1539 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1540 if (user_defined_bullet(i).getFont() != -1) {
1541 os << "\\bullet " << i << " "
1542 << user_defined_bullet(i).getFont() << " "
1543 << user_defined_bullet(i).getCharacter() << " "
1544 << user_defined_bullet(i).getSize() << "\n";
1548 os << "\\bulletLaTeX " << i << " \""
1549 << lyx::to_ascii(user_defined_bullet(i).getText())
1555 os << "\\tracking_changes "
1556 << (save_transient_properties ? convert<string>(track_changes) : "false")
1559 os << "\\output_changes "
1560 << (save_transient_properties ? convert<string>(output_changes) : "false")
1563 os << "\\change_bars "
1564 << (save_transient_properties ? convert<string>(change_bars) : "false")
1567 os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1569 os << "\\html_math_output " << html_math_output << '\n'
1570 << "\\html_css_as_file " << html_css_as_file << '\n'
1571 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1573 os << "\\docbook_table_output " << docbook_table_output << '\n';
1574 os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n';
1576 if (html_math_img_scale != 1.0)
1577 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1578 if (!html_latex_start.empty())
1579 os << "\\html_latex_start " << html_latex_start << '\n';
1580 if (!html_latex_end.empty())
1581 os << "\\html_latex_end " << html_latex_end << '\n';
1583 os << pimpl_->authorlist;
1587 void BufferParams::validate(LaTeXFeatures & features) const
1589 features.require(documentClass().required());
1591 if (columns > 1 && language->rightToLeft())
1592 features.require("rtloutputdblcol");
1594 if (output_changes) {
1595 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1596 LaTeXFeatures::isAvailable("xcolor");
1598 switch (features.runparams().flavor) {
1600 case Flavor::DviLuaTeX:
1602 features.require("ct-xcolor-ulem");
1603 features.require("ulem");
1604 features.require("xcolor");
1606 features.require("ct-none");
1609 case Flavor::LuaTeX:
1610 case Flavor::PdfLaTeX:
1613 features.require("ct-xcolor-ulem");
1614 features.require("ulem");
1615 features.require("xcolor");
1616 // improves color handling in PDF output
1617 features.require("pdfcolmk");
1619 features.require("ct-none");
1626 features.require("changebar");
1629 // Floats with 'Here definitely' as default setting.
1630 if (float_placement.find('H') != string::npos)
1631 features.require("float");
1633 for (auto const & pm : use_packages) {
1634 if (pm.first == "amsmath") {
1635 // AMS Style is at document level
1636 if (pm.second == package_on ||
1637 features.isProvided("amsmath"))
1638 features.require(pm.first);
1639 } else if (pm.second == package_on)
1640 features.require(pm.first);
1643 // Document-level line spacing
1644 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1645 features.require("setspace");
1647 // the bullet shapes are buffer level not paragraph level
1648 // so they are tested here
1649 for (int i = 0; i < 4; ++i) {
1650 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1652 int const font = user_defined_bullet(i).getFont();
1654 int const c = user_defined_bullet(i).getCharacter();
1660 features.require("latexsym");
1662 } else if (font == 1) {
1663 features.require("amssymb");
1664 } else if (font >= 2 && font <= 5) {
1665 features.require("pifont");
1669 if (pdfoptions().use_hyperref) {
1670 features.require("hyperref");
1671 // due to interferences with babel and hyperref, the color package has to
1672 // be loaded after hyperref when hyperref is used with the colorlinks
1673 // option, see http://www.lyx.org/trac/ticket/5291
1674 if (pdfoptions().colorlinks)
1675 features.require("color");
1677 if (!listings_params.empty()) {
1678 // do not test validity because listings_params is
1679 // supposed to be valid
1681 InsetListingsParams(listings_params).separatedParams(true);
1682 // we can't support all packages, but we should load the color package
1683 if (par.find("\\color", 0) != string::npos)
1684 features.require("color");
1687 // some languages are only available via polyglossia
1688 if (features.hasPolyglossiaExclusiveLanguages())
1689 features.require("polyglossia");
1691 if (useNonTeXFonts && fontsMath() != "auto")
1692 features.require("unicode-math");
1695 features.require("microtype");
1697 if (!language->required().empty())
1698 features.require(language->required());
1702 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1703 FileName const & filepath) const
1705 // DocumentMetadata must come before anything else
1706 if (features.isAvailableAtLeastFrom("LaTeX", 2022, 6)
1707 && !containsOnly(document_metadata, " \n\t")) {
1708 // Check if the user preamble contains uncodable glyphs
1709 odocstringstream doc_metadata;
1710 docstring uncodable_glyphs;
1711 Encoding const * const enc = features.runparams().encoding;
1713 for (char_type c : document_metadata) {
1714 if (!enc->encodable(c)) {
1715 docstring const glyph(1, c);
1716 LYXERR0("Uncodable character '"
1718 << "' in document metadata!");
1719 uncodable_glyphs += glyph;
1720 if (features.runparams().dryrun) {
1721 doc_metadata << "<" << _("LyX Warning: ")
1722 << _("uncodable character") << " '";
1723 doc_metadata.put(c);
1724 doc_metadata << "'>";
1727 doc_metadata.put(c);
1730 doc_metadata << document_metadata;
1732 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1733 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1734 frontend::Alert::warning(
1735 _("Uncodable character in document metadata"),
1737 _("The metadata of your document contains glyphs "
1738 "that are unknown in the current document encoding "
1739 "(namely %1$s).\nThese glyphs are omitted "
1740 " from the output, which may result in "
1741 "incomplete output."
1742 "\n\nPlease select an appropriate "
1743 "document encoding\n"
1744 "(such as utf8) or change the "
1745 "preamble code accordingly."),
1748 if (!doc_metadata.str().empty()) {
1749 os << "\\DocumentMetadata{\n"
1750 << doc_metadata.str()
1755 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1756 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1757 // \RequirePackage to do so, rather than the normal \usepackage
1758 // Do not try to load any other package before the document class, unless you
1759 // have a thorough understanding of the LATEX internals and know exactly what you
1761 if (features.mustProvide("fix-cm"))
1762 os << "\\RequirePackage{fix-cm}\n";
1763 // Likewise for fixltx2e. If other packages conflict with this policy,
1764 // treat it as a package bug (and report it!)
1765 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1766 if (features.mustProvide("fixltx2e"))
1767 os << "\\RequirePackage{fixltx2e}\n";
1769 os << "\\documentclass";
1771 DocumentClass const & tclass = documentClass();
1773 ostringstream clsoptions; // the document class options.
1775 if (tokenPos(tclass.opt_fontsize(),
1776 '|', fontsize) >= 0) {
1777 // only write if existing in list (and not default)
1778 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1781 // paper sizes not supported by the class itself need the
1783 vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1784 bool class_supported_papersize = papersize == PAPER_DEFAULT
1785 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1787 if ((!use_geometry || features.isProvided("geometry-light"))
1788 && class_supported_papersize && papersize != PAPER_DEFAULT)
1789 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1792 if (sides != tclass.sides()) {
1795 clsoptions << "oneside,";
1798 clsoptions << "twoside,";
1804 if (columns != tclass.columns()) {
1806 clsoptions << "twocolumn,";
1808 clsoptions << "onecolumn,";
1812 && orientation == ORIENTATION_LANDSCAPE)
1813 clsoptions << "landscape,";
1816 clsoptions << "fleqn,";
1818 switch(math_numbering_side) {
1820 clsoptions << "leqno,";
1823 clsoptions << "reqno,";
1824 features.require("amsmath");
1830 // language should be a parameter to \documentclass
1831 if (language->babel() == "hebrew"
1832 && default_language->babel() != "hebrew")
1833 // This seems necessary
1834 features.useLanguage(default_language);
1836 ostringstream language_options;
1837 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1838 bool const use_polyglossia = features.usePolyglossia();
1839 bool const global = lyxrc.language_global_options;
1840 if (features.useBabel() || (use_polyglossia && global)) {
1841 language_options << features.getBabelLanguages();
1842 if (!language->babel().empty()) {
1843 if (!language_options.str().empty())
1844 language_options << ',';
1845 language_options << language->babel();
1847 if (global && !language_options.str().empty())
1848 clsoptions << language_options.str() << ',';
1851 // the predefined options from the layout
1852 if (use_default_options && !tclass.options().empty())
1853 clsoptions << tclass.options() << ',';
1855 // the user-defined options
1856 if (!options.empty()) {
1857 clsoptions << options << ',';
1860 docstring const strOptions = from_utf8(clsoptions.str());
1861 if (!strOptions.empty()) {
1862 // Check if class options contain uncodable glyphs
1863 docstring uncodable_glyphs;
1864 docstring options_encodable;
1865 Encoding const * const enc = features.runparams().encoding;
1867 for (char_type c : strOptions) {
1868 if (!enc->encodable(c)) {
1869 docstring const glyph(1, c);
1870 LYXERR0("Uncodable character '"
1872 << "' in class options!");
1873 uncodable_glyphs += glyph;
1874 if (features.runparams().dryrun) {
1875 options_encodable += "<" + _("LyX Warning: ")
1876 + _("uncodable character") + " '";
1877 options_encodable += c;
1878 options_encodable += "'>";
1881 options_encodable += c;
1884 options_encodable = strOptions;
1886 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1887 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1888 frontend::Alert::warning(
1889 _("Uncodable character in class options"),
1891 _("The class options of your document contain glyphs "
1892 "that are unknown in the current document encoding "
1893 "(namely %1$s).\nThese glyphs are omitted "
1894 " from the output, which may result in "
1895 "incomplete output."
1896 "\n\nPlease select an appropriate "
1897 "document encoding\n"
1898 "(such as utf8) or change the "
1899 "class options accordingly."),
1902 options_encodable = rtrim(options_encodable, ",");
1903 os << '[' << options_encodable << ']';
1906 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1907 // end of \documentclass defs
1909 // The package options (via \PassOptionsToPackage)
1910 os << from_ascii(features.getPackageOptions());
1912 // if we use fontspec or newtxmath, we have to load the AMS packages here
1913 string const ams = features.loadAMSPackages();
1914 string const main_font_enc = features.runparams().main_fontenc;
1915 bool const ot1 = (main_font_enc == "default" || main_font_enc == "OT1");
1916 bool const use_newtxmath =
1917 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1918 ot1, false, false) == "newtxmath";
1919 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1920 os << from_ascii(ams);
1922 if (useNonTeXFonts) {
1923 // Babel (as of 2017/11/03) loads fontspec itself
1924 if (!features.isProvided("fontspec")
1925 && !(features.useBabel() && features.isAvailableAtLeastFrom("babel", 2017, 11, 3)))
1926 os << "\\usepackage{fontspec}\n";
1927 if (features.mustProvide("unicode-math")
1928 && features.isAvailable("unicode-math"))
1929 os << "\\usepackage{unicode-math}\n";
1932 // load CJK support package before font selection
1933 // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1934 if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1935 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1936 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1937 os << "\\usepackage{CJKutf8}\n";
1939 os << "\\usepackage[encapsulated]{CJK}\n";
1942 // font selection must be done before loading fontenc.sty
1943 // but after babel with non-TeX fonts
1944 string const fonts = loadFonts(features);
1945 if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1946 os << from_utf8(fonts);
1948 if (fonts_default_family != "default")
1949 os << "\\renewcommand{\\familydefault}{\\"
1950 << from_ascii(fonts_default_family) << "}\n";
1952 // set font encoding
1953 // non-TeX fonts use font encoding TU (set by fontspec)
1954 if (!useNonTeXFonts && !features.isProvided("fontenc")
1955 && main_font_enc != "default") {
1956 // get main font encodings
1957 vector<string> fontencs = font_encodings();
1958 // get font encodings of secondary languages
1959 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1960 // option (for text in other languages).
1961 features.getFontEncodings(fontencs);
1962 if (!fontencs.empty()) {
1963 os << "\\usepackage["
1964 << from_ascii(getStringFromVector(fontencs))
1969 // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1970 if (features.mustProvide("textcomp"))
1971 os << "\\usepackage{textcomp}\n";
1972 if (features.mustProvide("pmboxdraw"))
1973 os << "\\usepackage{pmboxdraw}\n";
1975 // handle inputenc etc.
1976 // (In documents containing text in Thai language,
1977 // we must load inputenc after babel, see lib/languages).
1978 if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1979 writeEncodingPreamble(os, features);
1982 if (!features.runparams().includeall && !included_children_.empty()) {
1983 os << "\\includeonly{";
1985 // we do not use "auto const &" here, because incfile is modified later
1986 // coverity[auto_causes_copy]
1987 for (auto incfile : included_children_) {
1988 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1989 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1991 if (!features.runparams().nice)
1993 // \includeonly doesn't want an extension
1994 incfile = changeExtension(incfile, string());
1995 incfile = support::latex_path(incfile);
1996 if (!incfile.empty()) {
1999 os << from_utf8(incfile);
2006 if (!features.isProvided("geometry")
2007 && (use_geometry || !class_supported_papersize)) {
2008 odocstringstream ods;
2009 if (!getGraphicsDriver("geometry").empty())
2010 ods << getGraphicsDriver("geometry");
2011 if (orientation == ORIENTATION_LANDSCAPE)
2012 ods << ",landscape";
2013 switch (papersize) {
2015 if (!paperwidth.empty())
2016 ods << ",paperwidth="
2017 << from_ascii(paperwidth);
2018 if (!paperheight.empty())
2019 ods << ",paperheight="
2020 << from_ascii(paperheight);
2022 case PAPER_USLETTER:
2024 case PAPER_USEXECUTIVE:
2053 ods << "," << from_ascii(string_papersize_geometry[papersize]);
2058 docstring g_options = trim(ods.str(), ",");
2059 os << "\\usepackage";
2060 // geometry-light means that the class works with geometry, but overwrites
2061 // the package options and paper sizes (memoir does this).
2062 // In this case, all options need to go to \geometry
2063 // and the standard paper sizes need to go to the class options.
2064 if (!g_options.empty() && !features.isProvided("geometry-light")) {
2065 os << '[' << g_options << ']';
2068 os << "{geometry}\n";
2069 if (use_geometry || features.isProvided("geometry-light")) {
2070 os << "\\geometry{verbose";
2071 if (!g_options.empty())
2072 // Output general options here with "geometry light".
2073 os << "," << g_options;
2074 // output this only if use_geometry is true
2076 if (!topmargin.empty())
2077 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2078 if (!bottommargin.empty())
2079 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2080 if (!leftmargin.empty())
2081 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2082 if (!rightmargin.empty())
2083 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2084 if (!headheight.empty())
2085 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2086 if (!headsep.empty())
2087 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2088 if (!footskip.empty())
2089 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2090 if (!columnsep.empty())
2091 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2095 } else if (orientation == ORIENTATION_LANDSCAPE
2096 || papersize != PAPER_DEFAULT) {
2097 features.require("papersize");
2100 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2101 if (pagestyle == "fancy")
2102 os << "\\usepackage{fancyhdr}\n";
2103 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2106 // only output when the background color is not default
2107 if (isbackgroundcolor) {
2108 // only require color here, the background color will be defined
2109 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2111 features.require("color");
2112 features.require("pagecolor");
2115 // only output when the font color is not default
2117 // only require color here, the font color will be defined
2118 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2120 features.require("color");
2121 features.require("fontcolor");
2124 // Only if class has a ToC hierarchy
2125 if (tclass.hasTocLevels()) {
2126 if (secnumdepth != tclass.secnumdepth()) {
2127 os << "\\setcounter{secnumdepth}{"
2131 if (tocdepth != tclass.tocdepth()) {
2132 os << "\\setcounter{tocdepth}{"
2138 if (paragraph_separation) {
2139 // when skip separation
2141 switch (getDefSkip().kind()) {
2142 case VSpace::SMALLSKIP:
2143 psopt = "\\smallskipamount";
2145 case VSpace::MEDSKIP:
2146 psopt = "\\medskipamount";
2148 case VSpace::BIGSKIP:
2149 psopt = "\\bigskipamount";
2151 case VSpace::HALFLINE:
2152 // default (no option)
2154 case VSpace::FULLLINE:
2155 psopt = "\\baselineskip";
2157 case VSpace::LENGTH:
2158 psopt = getDefSkip().length().asLatexString();
2163 if (!features.isProvided("parskip")) {
2165 psopt = "[skip=" + psopt + "]";
2166 os << "\\usepackage" + psopt + "{parskip}\n";
2168 os << "\\setlength{\\parskip}{" + psopt + "}\n";
2171 // when separation by indentation
2172 // only output something when a width is given
2173 if (!getParIndent().empty()) {
2174 os << "\\setlength{\\parindent}{"
2175 << from_utf8(getParIndent().asLatexString())
2180 if (is_math_indent) {
2181 // when formula indentation
2182 // only output something when it is not the default
2183 if (!getMathIndent().empty()) {
2184 os << "\\setlength{\\mathindent}{"
2185 << from_utf8(getMathIndent().asString())
2190 // Now insert the LyX specific LaTeX commands...
2191 features.resolveAlternatives();
2192 features.expandMultiples();
2195 if (!output_sync_macro.empty())
2196 os << from_utf8(output_sync_macro) +"\n";
2197 else if (features.runparams().flavor == Flavor::LaTeX)
2198 os << "\\usepackage[active]{srcltx}\n";
2200 os << "\\synctex=-1\n";
2203 // due to interferences with babel and hyperref, the color package has to
2204 // be loaded (when it is not already loaded) before babel when hyperref
2205 // is used with the colorlinks option, see
2206 // http://www.lyx.org/trac/ticket/5291
2207 // we decided therefore to load color always before babel, see
2208 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2209 os << from_ascii(features.getColorOptions());
2211 // If we use hyperref, jurabib, japanese or varioref,
2212 // we have to call babel before
2214 && (features.isRequired("jurabib")
2215 || features.isRequired("hyperref")
2216 || features.isRequired("varioref")
2217 || features.isRequired("japanese"))) {
2218 os << features.getBabelPresettings();
2220 os << from_utf8(babelCall(language_options.str(),
2221 !lyxrc.language_global_options)) + '\n';
2222 os << features.getBabelPostsettings();
2225 // The optional packages;
2226 os << from_ascii(features.getPackages());
2228 // Additional Indices
2229 if (features.isRequired("splitidx")) {
2230 for (auto const & idx : indiceslist()) {
2231 os << "\\newindex{";
2232 os << escape(idx.shortcut());
2238 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2241 // * Hyperref manual: "Make sure it comes last of your loaded
2242 // packages, to give it a fighting chance of not being over-written,
2243 // since its job is to redefine many LaTeX commands."
2244 // * Email from Heiko Oberdiek: "It is usually better to load babel
2245 // before hyperref. Then hyperref has a chance to detect babel.
2246 // * Has to be loaded before the "LyX specific LaTeX commands" to
2247 // avoid errors with algorithm floats.
2248 // use hyperref explicitly if it is required
2249 if (features.isRequired("hyperref")) {
2250 OutputParams tmp_params = features.runparams();
2251 pdfoptions().writeLaTeX(tmp_params, os,
2252 features.isProvided("hyperref"));
2253 // correctly break URLs with hyperref and dvi/ps output
2254 if (features.runparams().hyperref_driver == "dvips"
2255 && features.isAvailable("breakurl"))
2256 os << "\\usepackage{breakurl}\n";
2257 } else if (features.isRequired("nameref"))
2258 // hyperref loads this automatically
2259 os << "\\usepackage{nameref}\n";
2262 os << "\\usepackage";
2263 if (!lineno_opts.empty())
2264 os << "[" << lineno_opts << "]";
2266 os << "\\linenumbers\n";
2269 // bibtopic needs to be loaded after hyperref.
2270 // the dot provides the aux file naming which LyX can detect.
2271 if (features.mustProvide("bibtopic"))
2272 os << "\\usepackage[dot]{bibtopic}\n";
2274 // Will be surrounded by \makeatletter and \makeatother when not empty
2275 otexstringstream atlyxpreamble;
2277 // Some macros LyX will need
2279 TexString tmppreamble = features.getMacros();
2280 if (!tmppreamble.str.empty())
2281 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2282 "LyX specific LaTeX commands.\n"
2283 << std::move(tmppreamble)
2286 // the text class specific preamble
2288 docstring tmppreamble = features.getTClassPreamble();
2289 if (!tmppreamble.empty())
2290 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2291 "Textclass specific LaTeX commands.\n"
2295 // suppress date if selected
2296 // use \@ifundefined because we cannot be sure that every document class
2297 // has a \date command
2299 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2301 /* the user-defined preamble */
2302 if (!containsOnly(preamble, " \n\t")) {
2304 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2305 "User specified LaTeX commands.\n";
2307 // Check if the user preamble contains uncodable glyphs
2308 odocstringstream user_preamble;
2309 docstring uncodable_glyphs;
2310 Encoding const * const enc = features.runparams().encoding;
2312 for (char_type c : preamble) {
2313 if (!enc->encodable(c)) {
2314 docstring const glyph(1, c);
2315 LYXERR0("Uncodable character '"
2317 << "' in user preamble!");
2318 uncodable_glyphs += glyph;
2319 if (features.runparams().dryrun) {
2320 user_preamble << "<" << _("LyX Warning: ")
2321 << _("uncodable character") << " '";
2322 user_preamble.put(c);
2323 user_preamble << "'>";
2326 user_preamble.put(c);
2329 user_preamble << preamble;
2331 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2332 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2333 frontend::Alert::warning(
2334 _("Uncodable character in user preamble"),
2336 _("The user preamble of your document contains glyphs "
2337 "that are unknown in the current document encoding "
2338 "(namely %1$s).\nThese glyphs are omitted "
2339 " from the output, which may result in "
2340 "incomplete output."
2341 "\n\nPlease select an appropriate "
2342 "document encoding\n"
2343 "(such as utf8) or change the "
2344 "preamble code accordingly."),
2347 atlyxpreamble << user_preamble.str() << '\n';
2350 // footmisc must be loaded after setspace
2351 // Load it here to avoid clashes with footmisc loaded in the user
2352 // preamble. For that reason we also pass the options via
2353 // \PassOptionsToPackage in getPreamble() and not here.
2354 if (features.mustProvide("footmisc"))
2355 atlyxpreamble << "\\usepackage{footmisc}\n";
2357 // subfig loads internally the LaTeX package "caption". As
2358 // caption is a very popular package, users will load it in
2359 // the preamble. Therefore we must load subfig behind the
2360 // user-defined preamble and check if the caption package was
2361 // loaded or not. For the case that caption is loaded before
2362 // subfig, there is the subfig option "caption=false". This
2363 // option also works when a koma-script class is used and
2364 // koma's own caption commands are used instead of caption. We
2365 // use \PassOptionsToPackage here because the user could have
2366 // already loaded subfig in the preamble.
2367 if (features.mustProvide("subfig"))
2368 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2369 " % Caption package is used. Advise subfig not to load it again.\n"
2370 " \\PassOptionsToPackage{caption=false}{subfig}\n"
2372 "\\usepackage{subfig}\n";
2374 // Itemize bullet settings need to be last in case the user
2375 // defines their own bullets that use a package included
2376 // in the user-defined preamble -- ARRae
2377 // Actually it has to be done much later than that
2378 // since some packages like frenchb make modifications
2379 // at \begin{document} time -- JMarc
2380 docstring bullets_def;
2381 for (int i = 0; i < 4; ++i) {
2382 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2383 if (bullets_def.empty())
2384 bullets_def += "\\AtBeginDocument{\n";
2385 bullets_def += " \\def\\labelitemi";
2387 // `i' is one less than the item to modify
2394 bullets_def += "ii";
2400 bullets_def += '{' +
2401 user_defined_bullet(i).getText()
2406 if (!bullets_def.empty())
2407 atlyxpreamble << bullets_def << "}\n\n";
2409 if (!atlyxpreamble.empty())
2410 os << "\n\\makeatletter\n"
2411 << atlyxpreamble.release()
2412 << "\\makeatother\n\n";
2414 // We try to load babel late, in case it interferes with other packages.
2415 // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2416 // have to be called after babel, though.
2417 if (use_babel && !features.isRequired("jurabib")
2418 && !features.isRequired("hyperref")
2419 && !features.isRequired("varioref")
2420 && !features.isRequired("japanese")) {
2421 os << features.getBabelPresettings();
2423 os << from_utf8(babelCall(language_options.str(),
2424 !lyxrc.language_global_options)) + '\n';
2425 os << features.getBabelPostsettings();
2427 // In documents containing text in Thai language,
2428 // we must load inputenc after babel (see lib/languages).
2429 if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2430 writeEncodingPreamble(os, features);
2432 // font selection must be done after babel with non-TeX fonts
2433 if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2434 os << from_utf8(fonts);
2436 if (features.isRequired("bicaption"))
2437 os << "\\usepackage{bicaption}\n";
2438 if (!listings_params.empty()
2439 || features.mustProvide("listings")
2440 || features.mustProvide("minted")) {
2442 os << "\\usepackage{minted}\n";
2444 os << "\\usepackage{listings}\n";
2446 string lst_params = listings_params;
2447 // If minted, do not output the language option (bug 11203)
2448 if (use_minted && contains(lst_params, "language=")) {
2449 vector<string> opts =
2450 getVectorFromString(lst_params, ",", false);
2451 for (size_t i = 0; i < opts.size(); ++i) {
2452 if (prefixIs(opts[i], "language="))
2453 opts.erase(opts.begin() + i--);
2455 lst_params = getStringFromVector(opts, ",");
2457 if (!lst_params.empty()) {
2459 os << "\\setminted{";
2462 // do not test validity because listings_params is
2463 // supposed to be valid
2465 InsetListingsParams(lst_params).separatedParams(true);
2466 os << from_utf8(par);
2470 // xunicode only needs to be loaded if tipa is used
2471 // (the rest is obsoleted by the new TU encoding).
2472 // It needs to be loaded at least after amsmath, amssymb,
2473 // esint and the other packages that provide special glyphs
2474 if (features.mustProvide("tipa") && useNonTeXFonts
2475 && !features.isProvided("xunicode")) {
2476 // The `xunicode` package officially only supports XeTeX,
2477 // but also works with LuaTeX. We work around its XeTeX test.
2478 if (features.runparams().flavor != Flavor::XeTeX) {
2479 os << "% Pretend to xunicode that we are XeTeX\n"
2480 << "\\def\\XeTeXpicfile{}\n";
2482 os << "\\usepackage{xunicode}\n";
2485 // covington must be loaded after beamerarticle
2486 if (features.isRequired("covington"))
2487 os << "\\usepackage{covington}\n";
2489 // Polyglossia must be loaded last ...
2490 if (use_polyglossia) {
2492 os << "\\usepackage{polyglossia}\n";
2493 // set the main language
2494 os << "\\setdefaultlanguage";
2495 if (!language->polyglossiaOpts().empty())
2496 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2497 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2498 // now setup the other languages
2499 set<string> const polylangs =
2500 features.getPolyglossiaLanguages();
2501 for (auto const & pl : polylangs) {
2502 // We do not output the options here; they are output in
2503 // the language switch commands. This is safer if multiple
2504 // varieties are used.
2505 if (pl == language->polyglossia())
2507 os << "\\setotherlanguage";
2508 os << "{" << from_ascii(pl) << "}\n";
2512 // ... but before biblatex (see #7065)
2513 if ((features.mustProvide("biblatex")
2514 || features.isRequired("biblatex-chicago"))
2515 && !features.isProvided("biblatex-chicago")
2516 && !features.isProvided("biblatex-natbib")
2517 && !features.isProvided("natbib-internal")
2518 && !features.isProvided("natbib")
2519 && !features.isProvided("jurabib")) {
2520 // The biblatex-chicago package has a differing interface
2521 // it uses a wrapper package and loads styles via fixed options
2522 bool const chicago = features.isRequired("biblatex-chicago");
2525 os << "\\usepackage";
2526 if (!biblatex_bibstyle.empty()
2527 && (biblatex_bibstyle == biblatex_citestyle)
2529 opts = "style=" + biblatex_bibstyle;
2531 } else if (!chicago) {
2532 if (!biblatex_bibstyle.empty()) {
2533 opts = "bibstyle=" + biblatex_bibstyle;
2536 if (!biblatex_citestyle.empty()) {
2537 opts += delim + "citestyle=" + biblatex_citestyle;
2541 if (!multibib.empty() && multibib != "child") {
2542 opts += delim + "refsection=" + multibib;
2545 if (bibtexCommand() == "bibtex8"
2546 || prefixIs(bibtexCommand(), "bibtex8 ")) {
2547 opts += delim + "backend=bibtex8";
2549 } else if (bibtexCommand() == "bibtex"
2550 || prefixIs(bibtexCommand(), "bibtex ")) {
2551 opts += delim + "backend=bibtex";
2554 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2555 opts += delim + "bibencoding="
2556 + encodings.fromLyXName(bib_encoding)->latexName();
2559 if (!biblio_opts.empty())
2560 opts += delim + biblio_opts;
2562 os << "[" << opts << "]";
2564 os << "{biblatex-chicago}\n";
2566 os << "{biblatex}\n";
2570 // Load custom language package here
2571 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2572 if (lang_package == "default")
2573 os << from_utf8(lyxrc.language_custom_package);
2575 os << from_utf8(lang_package);
2579 // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2580 // it is recommended to load menukeys as the last package (even after hyperref)
2581 if (features.isRequired("menukeys"))
2582 os << "\\usepackage{menukeys}\n";
2584 docstring const i18npreamble =
2585 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2587 if (!i18npreamble.empty())
2588 os << i18npreamble + '\n';
2594 void BufferParams::useClassDefaults()
2596 DocumentClass const & tclass = documentClass();
2598 sides = tclass.sides();
2599 columns = tclass.columns();
2600 pagestyle = tclass.pagestyle();
2601 tablestyle = tclass.tablestyle();
2602 use_default_options = true;
2603 // Only if class has a ToC hierarchy
2604 if (tclass.hasTocLevels()) {
2605 secnumdepth = tclass.secnumdepth();
2606 tocdepth = tclass.tocdepth();
2611 bool BufferParams::hasClassDefaults() const
2613 DocumentClass const & tclass = documentClass();
2615 return sides == tclass.sides()
2616 && columns == tclass.columns()
2617 && pagestyle == tclass.pagestyle()
2618 && tablestyle == tclass.tablestyle()
2619 && use_default_options
2620 && secnumdepth == tclass.secnumdepth()
2621 && tocdepth == tclass.tocdepth();
2625 DocumentClass const & BufferParams::documentClass() const
2631 DocumentClassConstPtr BufferParams::documentClassPtr() const
2637 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2639 // evil, but this function is evil
2640 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2641 invalidateConverterCache();
2645 bool BufferParams::setBaseClass(string const & classname, string const & path)
2647 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2648 LayoutFileList & bcl = LayoutFileList::get();
2649 if (!bcl.haveClass(classname)) {
2651 bformat(_("The layout file:\n"
2653 "could not be found. A default textclass with default\n"
2654 "layouts will be used. LyX will not be able to produce\n"
2656 from_utf8(classname));
2657 frontend::Alert::error(_("Document class not found"), s);
2658 bcl.addEmptyClass(classname);
2661 bool const success = bcl[classname].load(path);
2664 bformat(_("Due to some error in it, the layout file:\n"
2666 "could not be loaded. A default textclass with default\n"
2667 "layouts will be used. LyX will not be able to produce\n"
2669 from_utf8(classname));
2670 frontend::Alert::error(_("Could not load class"), s);
2671 bcl.addEmptyClass(classname);
2674 pimpl_->baseClass_ = classname;
2675 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2680 LayoutFile const * BufferParams::baseClass() const
2682 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2683 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2689 LayoutFileIndex const & BufferParams::baseClassID() const
2691 return pimpl_->baseClass_;
2695 void BufferParams::makeDocumentClass(bool clone, bool internal)
2700 invalidateConverterCache();
2701 LayoutModuleList mods;
2702 for (auto const & mod : layout_modules_)
2703 mods.push_back(mod);
2705 doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2707 TextClass::ReturnValues success = TextClass::OK;
2708 if (!forced_local_layout_.empty())
2709 success = doc_class_->read(to_utf8(forced_local_layout_),
2711 if (!local_layout_.empty() &&
2712 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2713 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2714 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2715 docstring const msg = _("Error reading internal layout information");
2716 frontend::Alert::warning(_("Read Error"), msg);
2721 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2723 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2727 docstring BufferParams::getLocalLayout(bool forced) const
2730 return from_utf8(doc_class_->forcedLayouts());
2732 return local_layout_;
2736 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2739 forced_local_layout_ = layout;
2741 local_layout_ = layout;
2745 bool BufferParams::addLayoutModule(string const & modName)
2747 for (auto const & mod : layout_modules_)
2750 layout_modules_.push_back(modName);
2755 string BufferParams::bufferFormat() const
2757 return documentClass().outputFormat();
2761 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2763 FormatList const & formats = exportableFormats(need_viewable);
2764 for (auto const & fmt : formats) {
2765 if (fmt->name() == format)
2772 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2774 FormatList & cached = only_viewable ?
2775 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2776 bool & valid = only_viewable ?
2777 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2781 vector<string> const backs = backends();
2782 set<string> excludes;
2783 if (useNonTeXFonts) {
2784 excludes.insert("latex");
2785 excludes.insert("pdflatex");
2786 } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2787 // XeTeX with TeX fonts requires input encoding ascii (#10600).
2788 excludes.insert("xetex");
2792 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2793 vector<string>::const_iterator it = backs.begin() + 1;
2794 for (; it != backs.end(); ++it) {
2795 FormatList r = theConverters().getReachable(*it, only_viewable,
2797 result.insert(result.end(), r.begin(), r.end());
2799 sort(result.begin(), result.end(), Format::formatSorter);
2806 vector<string> BufferParams::backends() const
2809 string const buffmt = bufferFormat();
2811 // FIXME: Don't hardcode format names here, but use a flag
2812 if (buffmt == "latex") {
2813 if (encoding().package() == Encoding::japanese)
2814 v.push_back("platex");
2816 if (!useNonTeXFonts) {
2817 v.push_back("pdflatex");
2818 v.push_back("latex");
2821 || inputenc == "ascii" || inputenc == "utf8-plain")
2822 v.push_back("xetex");
2823 v.push_back("luatex");
2824 v.push_back("dviluatex");
2827 string rbuffmt = buffmt;
2828 // If we use an OutputFormat in Japanese docs,
2829 // we need special format in order to get the path
2830 // via pLaTeX (#8823)
2831 if (documentClass().hasOutputFormat()
2832 && encoding().package() == Encoding::japanese)
2834 v.push_back(rbuffmt);
2837 v.push_back("xhtml");
2838 v.push_back("docbook5");
2839 v.push_back("text");
2845 Flavor BufferParams::getOutputFlavor(string const & format) const
2847 string const dformat = (format.empty() || format == "default") ?
2848 getDefaultOutputFormat() : format;
2849 DefaultFlavorCache::const_iterator it =
2850 default_flavors_.find(dformat);
2852 if (it != default_flavors_.end())
2855 Flavor result = Flavor::LaTeX;
2857 // FIXME It'd be better not to hardcode this, but to do
2858 // something with formats.
2859 if (dformat == "xhtml")
2860 result = Flavor::Html;
2861 else if (dformat == "docbook5")
2862 result = Flavor::DocBook5;
2863 else if (dformat == "text")
2864 result = Flavor::Text;
2865 else if (dformat == "lyx")
2866 result = Flavor::LyX;
2867 else if (dformat == "pdflatex")
2868 result = Flavor::PdfLaTeX;
2869 else if (dformat == "xetex")
2870 result = Flavor::XeTeX;
2871 else if (dformat == "luatex")
2872 result = Flavor::LuaTeX;
2873 else if (dformat == "dviluatex")
2874 result = Flavor::DviLuaTeX;
2876 // Try to determine flavor of default output format
2877 vector<string> backs = backends();
2878 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2879 // Get shortest path to format
2880 Graph::EdgePath path;
2881 for (auto const & bvar : backs) {
2882 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2883 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2888 result = theConverters().getFlavor(path);
2891 // cache this flavor
2892 default_flavors_[dformat] = result;
2897 string BufferParams::getDefaultOutputFormat() const
2899 if (!default_output_format.empty()
2900 && default_output_format != "default")
2901 return default_output_format;
2902 if (encoding().package() == Encoding::japanese)
2903 return lyxrc.default_platex_view_format;
2905 return lyxrc.default_otf_view_format;
2906 return lyxrc.default_view_format;
2909 Font const BufferParams::getFont() const
2911 FontInfo f = documentClass().defaultfont();
2912 if (fonts_default_family == "rmdefault")
2913 f.setFamily(ROMAN_FAMILY);
2914 else if (fonts_default_family == "sfdefault")
2915 f.setFamily(SANS_FAMILY);
2916 else if (fonts_default_family == "ttdefault")
2917 f.setFamily(TYPEWRITER_FAMILY);
2918 return Font(f, language);
2922 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2924 return quotesstyletranslator().find(qs);
2928 bool BufferParams::isLatex() const
2930 return documentClass().outputType() == LATEX;
2934 bool BufferParams::isLiterate() const
2936 return documentClass().outputType() == LITERATE;
2940 void BufferParams::readPreamble(Lexer & lex)
2942 if (lex.getString() != "\\begin_preamble")
2943 lyxerr << "Error (BufferParams::readPreamble):"
2944 "consistency check failed." << endl;
2946 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2950 void BufferParams::readDocumentMetadata(Lexer & lex)
2952 if (lex.getString() != "\\begin_metadata")
2953 lyxerr << "Error (BufferParams::readDocumentMetadata):"
2954 "consistency check failed." << endl;
2956 document_metadata = lex.getLongString(from_ascii("\\end_metadata"));
2960 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2962 string const expected = forced ? "\\begin_forced_local_layout" :
2963 "\\begin_local_layout";
2964 if (lex.getString() != expected)
2965 lyxerr << "Error (BufferParams::readLocalLayout):"
2966 "consistency check failed." << endl;
2969 forced_local_layout_ =
2970 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2972 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2976 bool BufferParams::setLanguage(string const & lang)
2978 Language const *new_language = languages.getLanguage(lang);
2979 if (!new_language) {
2980 // Language lang was not found
2983 language = new_language;
2988 void BufferParams::readLanguage(Lexer & lex)
2990 if (!lex.next()) return;
2992 string const tmptok = lex.getString();
2994 // check if tmptok is part of tex_babel in tex-defs.h
2995 if (!setLanguage(tmptok)) {
2996 // Language tmptok was not found
2997 language = default_language;
2998 lyxerr << "Warning: Setting language `"
2999 << tmptok << "' to `" << language->lang()
3005 void BufferParams::readGraphicsDriver(Lexer & lex)
3010 string const tmptok = lex.getString();
3011 // check if tmptok is part of tex_graphics in tex_defs.h
3014 string const test = tex_graphics[n++];
3016 if (test == tmptok) {
3017 graphics_driver = tmptok;
3022 "Warning: graphics driver `$$Token' not recognized!\n"
3023 " Setting graphics driver to `default'.\n");
3024 graphics_driver = "default";
3031 void BufferParams::readBullets(Lexer & lex)
3036 int const index = lex.getInteger();
3038 int temp_int = lex.getInteger();
3039 user_defined_bullet(index).setFont(temp_int);
3040 temp_bullet(index).setFont(temp_int);
3042 user_defined_bullet(index).setCharacter(temp_int);
3043 temp_bullet(index).setCharacter(temp_int);
3045 user_defined_bullet(index).setSize(temp_int);
3046 temp_bullet(index).setSize(temp_int);
3050 void BufferParams::readBulletsLaTeX(Lexer & lex)
3052 // The bullet class should be able to read this.
3055 int const index = lex.getInteger();
3057 docstring const temp_str = lex.getDocString();
3059 user_defined_bullet(index).setText(temp_str);
3060 temp_bullet(index).setText(temp_str);
3064 void BufferParams::readModules(Lexer & lex)
3066 if (!lex.eatLine()) {
3067 lyxerr << "Error (BufferParams::readModules):"
3068 "Unexpected end of input." << endl;
3072 string mod = lex.getString();
3073 if (mod == "\\end_modules")
3075 addLayoutModule(mod);
3081 void BufferParams::readRemovedModules(Lexer & lex)
3083 if (!lex.eatLine()) {
3084 lyxerr << "Error (BufferParams::readRemovedModules):"
3085 "Unexpected end of input." << endl;
3089 string mod = lex.getString();
3090 if (mod == "\\end_removed_modules")
3092 removed_modules_.push_back(mod);
3095 // now we want to remove any removed modules that were previously
3096 // added. normally, that will be because default modules were added in
3097 // setBaseClass(), which gets called when \textclass is read at the
3098 // start of the read.
3099 for (auto const & rm : removed_modules_) {
3100 LayoutModuleList::iterator const mit = layout_modules_.begin();
3101 LayoutModuleList::iterator const men = layout_modules_.end();
3102 LayoutModuleList::iterator found = find(mit, men, rm);
3105 layout_modules_.erase(found);
3110 void BufferParams::readIncludeonly(Lexer & lex)
3112 if (!lex.eatLine()) {
3113 lyxerr << "Error (BufferParams::readIncludeonly):"
3114 "Unexpected end of input." << endl;
3118 string child = lex.getString();
3119 if (child == "\\end_includeonly")
3121 included_children_.push_back(child);
3127 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3129 PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3132 if (documentClass().pagesize() == "default")
3133 // could be anything, so don't guess
3135 return paperSizeName(purpose, documentClass().pagesize());
3136 case PAPER_CUSTOM: {
3137 if (purpose == XDVI && !paperwidth.empty() &&
3138 !paperheight.empty()) {
3139 // heightxwidth<unit>
3140 string first = paperwidth;
3141 string second = paperheight;
3142 if (orientation == ORIENTATION_LANDSCAPE)
3145 return first.erase(first.length() - 2)
3151 // dvips and dvipdfm do not know this
3152 if (purpose == DVIPS || purpose == DVIPDFM)
3156 if (purpose == DVIPS || purpose == DVIPDFM)
3160 if (purpose == DVIPS || purpose == DVIPDFM)
3170 if (purpose == DVIPS || purpose == DVIPDFM)
3174 if (purpose == DVIPS || purpose == DVIPDFM)
3178 if (purpose == DVIPS || purpose == DVIPDFM)
3182 if (purpose == DVIPS || purpose == DVIPDFM)
3186 if (purpose == DVIPS || purpose == DVIPDFM)
3190 // dvipdfm does not know this
3191 if (purpose == DVIPDFM)
3195 if (purpose == DVIPDFM)
3199 if (purpose == DVIPS || purpose == DVIPDFM)
3203 if (purpose == DVIPS || purpose == DVIPDFM)
3207 if (purpose == DVIPS || purpose == DVIPDFM)
3211 if (purpose == DVIPS || purpose == DVIPDFM)
3215 if (purpose == DVIPS || purpose == DVIPDFM)
3219 if (purpose == DVIPS || purpose == DVIPDFM)
3223 if (purpose == DVIPS || purpose == DVIPDFM)
3227 if (purpose == DVIPS || purpose == DVIPDFM)
3231 if (purpose == DVIPS || purpose == DVIPDFM)
3235 if (purpose == DVIPS || purpose == DVIPDFM)
3239 if (purpose == DVIPS || purpose == DVIPDFM)
3243 if (purpose == DVIPS || purpose == DVIPDFM)
3247 if (purpose == DVIPS || purpose == DVIPDFM)
3251 if (purpose == DVIPS || purpose == DVIPDFM)
3255 if (purpose == DVIPS || purpose == DVIPDFM)
3258 case PAPER_USEXECUTIVE:
3259 // dvipdfm does not know this
3260 if (purpose == DVIPDFM)
3265 case PAPER_USLETTER:
3267 if (purpose == XDVI)
3274 string const BufferParams::dvips_options() const
3278 // If the class loads the geometry package, we do not know which
3279 // paper size is used, since we do not set it (bug 7013).
3280 // Therefore we must not specify any argument here.
3281 // dvips gets the correct paper size via DVI specials in this case
3282 // (if the class uses the geometry package correctly).
3283 if (documentClass().provides("geometry"))
3287 && papersize == PAPER_CUSTOM
3288 && !lyxrc.print_paper_dimension_flag.empty()
3289 && !paperwidth.empty()
3290 && !paperheight.empty()) {
3291 // using a custom papersize
3292 result = lyxrc.print_paper_dimension_flag;
3293 result += ' ' + paperwidth;
3294 result += ',' + paperheight;
3296 string const paper_option = paperSizeName(DVIPS);
3297 if (!paper_option.empty() && (paper_option != "letter" ||
3298 orientation != ORIENTATION_LANDSCAPE)) {
3299 // dvips won't accept -t letter -t landscape.
3300 // In all other cases, include the paper size
3302 result = lyxrc.print_paper_flag;
3303 result += ' ' + paper_option;
3306 if (orientation == ORIENTATION_LANDSCAPE &&
3307 papersize != PAPER_CUSTOM)
3308 result += ' ' + lyxrc.print_landscape_flag;
3313 string const BufferParams::main_font_encoding() const
3315 vector<string> const fencs = font_encodings();
3316 if (fencs.empty()) {
3317 if (ascii_lowercase(language->fontenc(*this)) == "none")
3321 return fencs.back();
3325 vector<string> const BufferParams::font_encodings() const
3327 string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3329 vector<string> fontencs;
3331 // "default" means "no explicit font encoding"
3332 if (doc_fontenc != "default") {
3333 if (!doc_fontenc.empty())
3334 // If we have a custom setting, we use only that!
3335 return getVectorFromString(doc_fontenc);
3336 string const lfe = language->fontenc(*this);
3338 && ascii_lowercase(language->fontenc(*this)) != "none") {
3339 vector<string> fencs = getVectorFromString(lfe);
3340 for (auto & fe : fencs) {
3341 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3342 fontencs.push_back(fe);
3351 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3353 // suppress the babel call if there is no BabelName defined
3354 // for the document language in the lib/languages file and if no
3355 // other languages are used (lang_opts is then empty)
3356 if (lang_opts.empty())
3358 // The prefs may require the languages to
3359 // be submitted to babel itself (not the class).
3361 return "\\usepackage[" + lang_opts + "]{babel}";
3362 return "\\usepackage{babel}";
3366 docstring BufferParams::getGraphicsDriver(string const & package) const
3370 if (package == "geometry") {
3371 if (graphics_driver == "dvips"
3372 || graphics_driver == "dvipdfm"
3373 || graphics_driver == "pdftex"
3374 || graphics_driver == "vtex")
3375 result = from_ascii(graphics_driver);
3376 else if (graphics_driver == "dvipdfmx")
3377 result = from_ascii("dvipdfm");
3384 void BufferParams::writeEncodingPreamble(otexstream & os,
3385 LaTeXFeatures & features) const
3387 // With no-TeX fonts we use utf8-plain without encoding package.
3391 string const doc_encoding = encoding().latexName();
3392 Encoding::Package const package = encoding().package();
3393 // (dvi)lualatex uses luainputenc rather than inputenc
3394 string const inputenc_package =
3395 (features.runparams().flavor == Flavor::LuaTeX
3396 || features.runparams().flavor == Flavor::DviLuaTeX)
3397 ? "luainputenc" : "inputenc";
3399 if (inputenc == "auto-legacy") {
3400 // The "japanese" babel language requires the pLaTeX engine
3401 // which conflicts with "inputenc".
3402 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3403 if (!features.isRequired("japanese")
3404 && !features.isProvided("inputenc")) {
3405 if (package == Encoding::inputenc) {
3406 // Main language requires (lua)inputenc
3407 os << "\\usepackage[" << doc_encoding << "]{"
3408 << inputenc_package << "}\n";
3410 // We might have an additional language that requires inputenc
3411 set<string> encoding_set = features.getEncodingSet(doc_encoding);
3412 bool inputenc = false;
3413 for (auto const & enc : encoding_set) {
3414 if (encodings.fromLaTeXName(enc)
3415 && encodings.fromLaTeXName(enc)->package() == Encoding::inputenc) {
3421 // load (lua)inputenc without options
3422 // (the encoding is loaded later)
3423 os << "\\usepackage{" << inputenc_package << "}\n";
3426 } else if (inputenc != "auto-legacy-plain") {
3428 case Encoding::none:
3430 case Encoding::japanese:
3431 if (encoding().iconvName() != "UTF-8"
3432 && !features.runparams().isFullUnicode()
3433 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3434 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3435 os << "\\UseRawInputEncoding\n";
3437 case Encoding::inputenc:
3438 // do not load inputenc if japanese is used
3439 // or if the class provides inputenc
3440 if (features.isRequired("japanese")
3441 || features.isProvided("inputenc"))
3443 // The 2022 release of ucs.sty uses the default utf8
3444 // inputenc encoding with 'utf8x' inputenc if the ucs
3445 // package is not loaded before inputenc.
3446 // This breaks existing documents that use utf8x
3447 // and also makes utf8x redundant.
3448 // Thus we load ucs.sty in order to keep functionality
3449 // that would otherwise be silently dropped.
3450 if (doc_encoding == "utf8x"
3451 && features.isAvailableAtLeastFrom("ucs", 2022, 8, 7)
3452 && !features.isProvided("ucs"))
3453 os << "\\usepackage{ucs}\n";
3454 os << "\\usepackage[" << doc_encoding << "]{"
3455 << inputenc_package << "}\n";
3459 if ((inputenc == "auto-legacy-plain" || features.isRequired("japanese"))
3460 && features.isAvailableAtLeastFrom("LaTeX", 2018, 4))
3461 // don't default to [utf8]{inputenc} with LaTeX >= 2018/04
3462 os << "\\UseRawInputEncoding\n";
3466 string const BufferParams::parseFontName(string const & name) const
3468 string mangled = name;
3469 size_t const idx = mangled.find('[');
3470 if (idx == string::npos || idx == 0)
3473 return mangled.substr(0, idx - 1);
3477 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3479 if (fontsRoman() == "default" && fontsSans() == "default"
3480 && fontsTypewriter() == "default"
3481 && (fontsMath() == "default" || fontsMath() == "auto"))
3487 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3488 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3489 * Mapping=tex-text option assures TeX ligatures (such as "--")
3490 * are resolved. Note that tt does not use these ligatures.
3492 * -- add more GUI options?
3493 * -- add more fonts (fonts for other scripts)
3494 * -- if there's a way to find out if a font really supports
3495 * OldStyle, enable/disable the widget accordingly.
3497 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3498 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3499 // However, until v.2 (2010/07/11) fontspec only knew
3500 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3501 // was introduced for both XeTeX and LuaTeX (LuaTeX
3502 // didn't understand "Mapping=tex-text", while XeTeX
3503 // understood both. With most recent versions, both
3504 // variants are understood by both engines. However,
3505 // we want to provide support for at least TeXLive 2009
3506 // (for XeTeX; LuaTeX is only supported as of v.2)
3507 // As of 2017/11/03, Babel has its own higher-level
3508 // interface on top of fontspec that is to be used.
3509 bool const babelfonts = features.useBabel()
3510 && features.isAvailableAtLeastFrom("babel", 2017, 11, 3);
3511 string const texmapping =
3512 (features.runparams().flavor == Flavor::XeTeX) ?
3513 "Mapping=tex-text" : "Ligatures=TeX";
3514 if (fontsRoman() != "default") {
3516 os << "\\babelfont{rm}[";
3518 os << "\\setmainfont[";
3519 if (!font_roman_opts.empty())
3520 os << font_roman_opts << ',';
3522 if (fonts_roman_osf)
3523 os << ",Numbers=OldStyle";
3524 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3526 if (fontsSans() != "default") {
3527 string const sans = parseFontName(fontsSans());
3528 if (fontsSansScale() != 100) {
3530 os << "\\babelfont{sf}";
3532 os << "\\setsansfont";
3534 << float(fontsSansScale()) / 100 << ',';
3536 os << "Numbers=OldStyle,";
3537 if (!font_sans_opts.empty())
3538 os << font_sans_opts << ',';
3539 os << texmapping << "]{"
3543 os << "\\babelfont{sf}[";
3545 os << "\\setsansfont[";
3547 os << "Numbers=OldStyle,";
3548 if (!font_sans_opts.empty())
3549 os << font_sans_opts << ',';
3550 os << texmapping << "]{"
3554 if (fontsTypewriter() != "default") {
3555 string const mono = parseFontName(fontsTypewriter());
3556 if (fontsTypewriterScale() != 100) {
3558 os << "\\babelfont{tt}";
3560 os << "\\setmonofont";
3562 << float(fontsTypewriterScale()) / 100;
3563 if (fonts_typewriter_osf)
3564 os << ",Numbers=OldStyle";
3565 if (!font_typewriter_opts.empty())
3566 os << ',' << font_typewriter_opts;
3571 os << "\\babelfont{tt}";
3573 os << "\\setmonofont";
3574 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3576 if (fonts_typewriter_osf)
3577 os << "Numbers=OldStyle";
3578 if (!font_typewriter_opts.empty()) {
3579 if (fonts_typewriter_osf)
3581 os << font_typewriter_opts;
3585 os << '{' << mono << "}\n";
3592 bool const ot1 = (features.runparams().main_fontenc == "default"
3593 || features.runparams().main_fontenc == "OT1");
3594 bool const dryrun = features.runparams().dryrun;
3595 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3596 bool const nomath = (fontsMath() != "auto");
3599 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3600 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3601 nomath, font_roman_opts);
3604 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3605 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3606 nomath, font_sans_opts, fontsSansScale());
3608 // MONOSPACED/TYPEWRITER
3609 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3610 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3611 nomath, font_typewriter_opts, fontsTypewriterScale());
3614 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3615 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3622 Encoding const & BufferParams::encoding() const
3624 // Main encoding for LaTeX output.
3626 return *(encodings.fromLyXName("utf8-plain"));
3627 if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3628 return *language->encoding();
3629 if (inputenc == "utf8" && language->lang() == "japanese")
3630 return *(encodings.fromLyXName("utf8-platex"));
3631 Encoding const * const enc = encodings.fromLyXName(inputenc);
3634 LYXERR0("Unknown inputenc value `" << inputenc
3635 << "'. Using `auto' instead.");
3636 return *language->encoding();
3640 string const & BufferParams::defaultBiblioStyle() const
3642 if (!biblio_style.empty())
3643 return biblio_style;
3645 map<string, string> const & bs = documentClass().defaultBiblioStyle();
3646 auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3647 if (cit != bs.end())
3650 return empty_string();
3654 bool BufferParams::fullAuthorList() const
3656 return documentClass().fullAuthorList();
3660 string BufferParams::getCiteAlias(string const & s) const
3662 vector<string> commands =
3663 documentClass().citeCommands(citeEngineType());
3664 // If it is a real command, don't treat it as an alias
3665 if (find(commands.begin(), commands.end(), s) != commands.end())
3667 map<string,string> aliases = documentClass().citeCommandAliases();
3668 if (aliases.find(s) != aliases.end())
3674 vector<string> BufferParams::citeCommands() const
3676 static CitationStyle const default_style;
3677 vector<string> commands =
3678 documentClass().citeCommands(citeEngineType());
3679 if (commands.empty())
3680 commands.push_back(default_style.name);
3685 vector<CitationStyle> BufferParams::citeStyles() const
3687 static CitationStyle const default_style;
3688 vector<CitationStyle> styles =
3689 documentClass().citeStyles(citeEngineType());
3691 styles.push_back(default_style);
3696 string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
3698 // split from options
3700 split(cmd, command_in, ' ');
3702 // Look if the requested command is available. If so, use that.
3703 for (auto const & alts : lyxrc.bibtex_alternatives) {
3704 string command_prov;
3705 split(alts, command_prov, ' ');
3706 if (command_in == command_prov)
3710 // If not, find the most suitable fallback for the current cite framework,
3711 // and warn. Note that we omit options in any such case.
3713 if (useBiblatex()) {
3714 // For Biblatex, we prefer biber (also for Japanese)
3715 // and try to fall back to bibtex8
3716 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3718 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3719 fallback = "bibtex8";
3721 // For classic BibTeX and as last resort for biblatex, try bibtex
3722 if (fallback.empty()) {
3723 if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
3724 fallback = "bibtex";
3730 if (fallback.empty()) {
3731 frontend::Alert::warning(
3732 _("No bibliography processor found!"),
3734 _("The bibliography processor requested by this document "
3735 "(%1$s) is not available and no appropriate "
3736 "alternative has been found. "
3737 "No bibliography and references will be generated.\n"
3738 "Please fix your installation!"),
3741 frontend::Alert::warning(
3742 _("Requested bibliography processor not found!"),
3744 _("The bibliography processor requested by this document "
3745 "(%1$s) is not available. "
3746 "As a fallback, '%2$s' will be used, options are omitted. "
3747 "This might result in errors or unwanted changes in "
3748 "the bibliography. Please check carefully!\n"
3749 "It is suggested to install the missing processor."),
3750 from_utf8(cmd), from_utf8(fallback)));
3756 string const BufferParams::bibtexCommand(bool const warn) const
3758 // Return document-specific setting if available
3759 if (bibtex_command != "default")
3760 return getBibtexCommand(bibtex_command, warn);
3762 // If we have "default" in document settings, consult the prefs
3763 // 1. Japanese (uses a specific processor)
3764 if (encoding().package() == Encoding::japanese) {
3765 if (lyxrc.jbibtex_command != "automatic")
3766 // Return the specified program, if "automatic" is not set
3767 return lyxrc.jbibtex_command;
3768 else if (!useBiblatex()) {
3769 // With classic BibTeX, return pbibtex, jbibtex, bibtex
3770 if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3772 if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3777 // 2. All other languages
3778 else if (lyxrc.bibtex_command != "automatic")
3779 // Return the specified program, if "automatic" is not set
3780 return getBibtexCommand(lyxrc.bibtex_command, warn);
3782 // 3. Automatic: find the most suitable for the current cite framework
3783 if (useBiblatex()) {
3784 // For Biblatex, we prefer biber (also for Japanese)
3785 // and fall back to bibtex8 and, as last resort, bibtex
3786 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3788 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3795 bool BufferParams::useBiblatex() const
3797 return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3801 void BufferParams::invalidateConverterCache() const
3803 pimpl_->isExportCacheValid = false;
3804 pimpl_->isViewCacheValid = false;
3808 // We shouldn't need to reset the params here, since anything
3809 // we need will be recopied.
3810 void BufferParams::copyForAdvFR(const BufferParams & bp)
3812 string const & lang = bp.language->lang();
3814 quotes_style = bp.quotes_style;
3815 layout_modules_ = bp.layout_modules_;
3816 string const & doc_class = bp.documentClass().name();
3817 setBaseClass(doc_class);
3821 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3823 bib_encodings[file] = enc;
3827 string const BufferParams::bibFileEncoding(string const & file) const
3829 if (bib_encodings.find(file) == bib_encodings.end())
3831 return bib_encodings.find(file)->second;
3835 BufferParams const & defaultBufferParams()
3837 static BufferParams default_params;
3838 return default_params;